Skip to content

Commit ccbe2f4

Browse files
committed
Skip session resume when JSONL hydration finds no conversation
1 parent ba99774 commit ccbe2f4

2 files changed

Lines changed: 23 additions & 7 deletions

File tree

apps/code/src/main/services/agent/service.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -709,14 +709,17 @@ When creating pull requests, add the following footer at the end of the PR descr
709709
let configOptions: SessionConfigOption[] | undefined;
710710
let agentSessionId: string;
711711

712+
// Claude-specific: hydrate session JSONL from PostHog before resuming.
713+
// If hydration finds no conversation to restore, skip the resume and
714+
// fall through to creating a new session. This avoids a doomed
715+
// unstable_resumeSession that would fail with "Resource not found"
712716
if (isReconnect && config.sessionId) {
713717
const existingSessionId = config.sessionId;
714718

715-
// Claude-specific: hydrate session JSONL from PostHog before resuming
716719
if (adapter !== "codex") {
717720
const posthogAPI = agent.getPosthogAPI();
718721
if (posthogAPI) {
719-
await hydrateSessionJsonl({
722+
const hasSession = await hydrateSessionJsonl({
720723
sessionId: existingSessionId,
721724
cwd: repoPath,
722725
taskId,
@@ -725,8 +728,19 @@ When creating pull requests, add the following footer at the end of the PR descr
725728
posthogAPI,
726729
log,
727730
});
731+
if (!hasSession) {
732+
log.info(
733+
"No session JSONL to resume, creating new session instead",
734+
{ taskId, taskRunId },
735+
);
736+
config.sessionId = undefined;
737+
}
728738
}
729739
}
740+
}
741+
742+
if (isReconnect && config.sessionId) {
743+
const existingSessionId = config.sessionId;
730744

731745
// Both adapters implement unstable_resumeSession:
732746
// - Claude: delegates to SDK's resumeSession with JSONL hydration

packages/agent/src/adapters/claude/session/jsonl-hydration.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,7 @@ export async function hydrateSessionJsonl(params: {
496496
permissionMode?: string;
497497
posthogAPI: PostHogAPIClient;
498498
log: HydrationLog;
499-
}): Promise<void> {
499+
}): Promise<boolean> {
500500
const { posthogAPI, log } = params;
501501

502502
try {
@@ -506,21 +506,21 @@ export async function hydrateSessionJsonl(params: {
506506
log.info("Local JSONL exists, skipping S3 hydration", {
507507
sessionId: params.sessionId,
508508
});
509-
return;
509+
return true;
510510
} catch {
511511
// File doesn't exist, proceed with hydration
512512
}
513513

514514
const taskRun = await posthogAPI.getTaskRun(params.taskId, params.runId);
515515
if (!taskRun.log_url) {
516516
log.info("No log URL, skipping JSONL hydration");
517-
return;
517+
return false;
518518
}
519519

520520
const entries = await posthogAPI.fetchTaskRunLogs(taskRun);
521521
if (entries.length === 0) {
522522
log.info("No S3 log entries, skipping JSONL hydration");
523-
return;
523+
return false;
524524
}
525525

526526
const entryCounts: Record<string, number> = {};
@@ -545,7 +545,7 @@ export async function hydrateSessionJsonl(params: {
545545
const allTurns = rebuildConversation(entries);
546546
if (allTurns.length === 0) {
547547
log.info("No conversation in S3 logs, skipping JSONL hydration");
548-
return;
548+
return false;
549549
}
550550

551551
const maxTokens = supports1MContext(params.model ?? "")
@@ -577,10 +577,12 @@ export async function hydrateSessionJsonl(params: {
577577
turns: conversation.length,
578578
lines: jsonlLines.length,
579579
});
580+
return true;
580581
} catch (err) {
581582
log.warn("Failed to hydrate session JSONL, continuing", {
582583
sessionId: params.sessionId,
583584
error: err instanceof Error ? err.message : String(err),
584585
});
586+
return false;
585587
}
586588
}

0 commit comments

Comments
 (0)