feat(issues): wire session resume through CLI and frontend handlers
Add --resume-sessions CLI arg to investigate subparser. Frontend reads persisted session IDs from investigation_state.json and passes them to the subprocess when resuming an interrupted investigation. Co-Authored-By: Claude Opus 4.6 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
a89bd75904
commit
4d3db8f407
@@ -1519,6 +1519,7 @@ class GitHubOrchestrator:
|
||||
self,
|
||||
issue_number: int,
|
||||
project_root: Path | None = None,
|
||||
resume_sessions: dict[str, str] | None = None,
|
||||
) -> dict:
|
||||
"""
|
||||
Run an AI investigation on a GitHub issue.
|
||||
@@ -1531,6 +1532,8 @@ class GitHubOrchestrator:
|
||||
issue_number: The GitHub issue number to investigate
|
||||
project_root: Working directory for agents (e.g., worktree path).
|
||||
Defaults to self.project_dir.
|
||||
resume_sessions: Optional dict mapping specialist name to SDK
|
||||
session ID for resuming interrupted investigations.
|
||||
|
||||
Returns:
|
||||
Dict with investigation results (InvestigationReport as dict)
|
||||
@@ -1616,6 +1619,7 @@ class GitHubOrchestrator:
|
||||
issue_labels=issue_labels,
|
||||
issue_comments=issue_comments,
|
||||
project_root=working_dir,
|
||||
resume_sessions=resume_sessions,
|
||||
)
|
||||
|
||||
# Update state to findings_ready
|
||||
|
||||
@@ -348,13 +348,25 @@ async def cmd_investigate(args) -> int:
|
||||
sys.stderr.reconfigure(line_buffering=True)
|
||||
|
||||
config = get_config(args)
|
||||
|
||||
# Parse resume sessions if provided
|
||||
resume_sessions = None
|
||||
if getattr(args, "resume_sessions", None):
|
||||
try:
|
||||
resume_sessions = json.loads(args.resume_sessions)
|
||||
except json.JSONDecodeError:
|
||||
safe_print("Warning: Invalid --resume-sessions JSON, starting fresh")
|
||||
|
||||
orchestrator = GitHubOrchestrator(
|
||||
project_dir=args.project,
|
||||
config=config,
|
||||
progress_callback=print_progress,
|
||||
)
|
||||
|
||||
result = await orchestrator.investigate_issue(args.issue_number)
|
||||
result = await orchestrator.investigate_issue(
|
||||
args.issue_number,
|
||||
resume_sessions=resume_sessions,
|
||||
)
|
||||
|
||||
# Output JSON for the Electron frontend to parse
|
||||
safe_print("\nJSON Output")
|
||||
@@ -830,6 +842,12 @@ def main():
|
||||
investigate_parser.add_argument(
|
||||
"issue_number", type=int, help="Issue number to investigate"
|
||||
)
|
||||
investigate_parser.add_argument(
|
||||
"--resume-sessions",
|
||||
type=str,
|
||||
default=None,
|
||||
help="JSON dict of specialist_name:session_id for resuming interrupted investigations",
|
||||
)
|
||||
|
||||
# post-investigation command
|
||||
post_investigation_parser = subparsers.add_parser(
|
||||
|
||||
@@ -152,6 +152,7 @@ class IssueInvestigationOrchestrator(ParallelAgentOrchestrator):
|
||||
issue_labels: list[str] | None = None,
|
||||
issue_comments: list[str] | None = None,
|
||||
project_root: Path | None = None,
|
||||
resume_sessions: dict[str, str] | None = None,
|
||||
) -> InvestigationReport:
|
||||
"""
|
||||
Run a full investigation on a GitHub issue.
|
||||
@@ -217,6 +218,7 @@ class IssueInvestigationOrchestrator(ParallelAgentOrchestrator):
|
||||
model=model,
|
||||
thinking_budget=thinking_budget,
|
||||
issue_number=issue_number,
|
||||
resume_sessions=resume_sessions,
|
||||
)
|
||||
|
||||
self._report_progress(
|
||||
@@ -331,6 +333,7 @@ Use Read, Grep, and Glob tools to explore the codebase.
|
||||
model: str,
|
||||
thinking_budget: int | None,
|
||||
issue_number: int | None = None,
|
||||
resume_sessions: dict[str, str] | None = None,
|
||||
) -> dict[str, dict[str, Any]]:
|
||||
"""Run all investigation specialists in parallel.
|
||||
|
||||
@@ -340,6 +343,8 @@ Use Read, Grep, and Glob tools to explore the codebase.
|
||||
model: Model to use
|
||||
thinking_budget: Max thinking tokens
|
||||
issue_number: GitHub issue number (for session persistence)
|
||||
resume_sessions: Optional dict mapping specialist name to SDK
|
||||
session ID for resuming interrupted sessions.
|
||||
|
||||
Returns:
|
||||
Dict mapping specialist name → stream result dict
|
||||
@@ -363,6 +368,10 @@ Use Read, Grep, and Glob tools to explore the codebase.
|
||||
if thinking_budget
|
||||
else None
|
||||
)
|
||||
# Look up resume session ID for this specialist
|
||||
_resume_id = (
|
||||
resume_sessions.get(cfg.name) if resume_sessions else None
|
||||
)
|
||||
return self._run_specialist_session(
|
||||
config=cfg,
|
||||
prompt=_prompt,
|
||||
@@ -373,6 +382,7 @@ Use Read, Grep, and Glob tools to explore the codebase.
|
||||
agent_type="investigation_specialist",
|
||||
context_name=f"Investigation:{cfg.name}",
|
||||
max_messages=cfg.max_turns,
|
||||
resume_session_id=_resume_id,
|
||||
on_thinking=lambda text, _name=cfg.name: emit_json_event(
|
||||
"thinking",
|
||||
_name,
|
||||
|
||||
@@ -977,13 +977,35 @@ async function runInvestigation(
|
||||
});
|
||||
}
|
||||
|
||||
const args = buildRunnerArgs(
|
||||
getRunnerPath(backendPath),
|
||||
project.path,
|
||||
'investigate',
|
||||
[String(issueNumber)],
|
||||
{ model, thinkingLevel },
|
||||
);
|
||||
// Read session IDs for interrupted investigation resume
|
||||
let resumeSessionsArg: string[] = [];
|
||||
try {
|
||||
const stateFile = path.join(
|
||||
project.path, '.auto-claude', 'issues', `${issueNumber}`, 'investigation_state.json'
|
||||
);
|
||||
if (fs.existsSync(stateFile)) {
|
||||
const stateData = JSON.parse(fs.readFileSync(stateFile, 'utf-8'));
|
||||
if (stateData.sessions && Object.keys(stateData.sessions).length > 0) {
|
||||
// Only pass sessions if this is a resume (status was 'investigating')
|
||||
if (stateData.status === 'investigating') {
|
||||
resumeSessionsArg = ['--resume-sessions', JSON.stringify(stateData.sessions)];
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// Non-fatal: will start fresh
|
||||
}
|
||||
|
||||
const args = [
|
||||
...buildRunnerArgs(
|
||||
getRunnerPath(backendPath),
|
||||
project.path,
|
||||
'investigate',
|
||||
[String(issueNumber)],
|
||||
{ model, thinkingLevel },
|
||||
),
|
||||
...resumeSessionsArg,
|
||||
];
|
||||
|
||||
const startedAt = new Date().toISOString();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user