Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions src/forge/workflow/bug/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,19 @@

_MAX_REFLECTION_COUNT = 3

# LangGraph filters state channels based on each node function's type annotation.
# implement_task and local_review_changes are typed as FeatureState, which lacks
# bug-specific fields like qualitative_retry_count. These wrappers are typed as
# BugState so LangGraph passes and records the full bug state for these nodes.


async def _implement_task_bug(state: BugState) -> BugState:
return await implement_task(state) # type: ignore[return-value]


async def _local_review_bug(state: BugState) -> BugState:
return await local_review_changes(state) # type: ignore[return-value]


def route_entry(state: BugState) -> str:
"""Route workflow based on current progress for resume/retry.
Expand Down Expand Up @@ -371,8 +384,8 @@ def build_bug_graph() -> StateGraph:
# Use the container-based implement_task (same as feature workflow) so the
# fix runs inside an isolated Podman container with full tool access.
# implement_bug_fix (ForgeAgent-based) is kept only for route_entry backward compat.
graph.add_node("implement_bug_fix", implement_task)
graph.add_node("local_review", local_review_changes)
graph.add_node("implement_bug_fix", _implement_task_bug)
graph.add_node("local_review", _local_review_bug)
graph.add_node("update_documentation", update_documentation)
graph.add_node("create_pr", create_pull_request)
graph.add_node("teardown_workspace", teardown_and_route)
Expand Down
8 changes: 4 additions & 4 deletions src/forge/workflow/nodes/implementation.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ async def implement_task(state: WorkflowState) -> WorkflowState:
return {
**state,
"last_error": "Workspace not set up",
"current_node": "implement_task",
"current_node": "implement_bug_fix",
}

# Get next task to implement if not set
Expand Down Expand Up @@ -159,9 +159,9 @@ async def implement_task(state: WorkflowState) -> WorkflowState:
**state,
"current_task_key": None,
"implemented_tasks": implemented,
"current_node": "implement_task", # Loop back for next task
"current_node": "implement_bug_fix",
"last_error": None,
"retry_count": 0, # Reset retry count on success
"retry_count": 0,
}
)
else:
Expand All @@ -180,7 +180,7 @@ async def implement_task(state: WorkflowState) -> WorkflowState:
return {
**state,
"last_error": str(e),
"current_node": "implement_task",
"current_node": "implement_bug_fix",
"retry_count": state.get("retry_count", 0) + 1,
}
finally:
Expand Down
Loading