| ... | @@ -88,6 +88,7 @@ interface ClaudeSessionContext { | ... | @@ -88,6 +88,7 @@ interface ClaudeSessionContext { |
| 88 | readonly promptQueue: Queue.Queue<PromptQueueItem>; | 88 | readonly promptQueue: Queue.Queue<PromptQueueItem>; |
| 89 | readonly query: ClaudeQueryRuntime; | 89 | readonly query: ClaudeQueryRuntime; |
| 90 | readonly startedAt: string; | 90 | readonly startedAt: string; |
| | 91 | resumeSessionId: string | undefined; |
| 91 | readonly pendingApprovals: Map<ApprovalRequestId, PendingApproval>; | 92 | readonly pendingApprovals: Map<ApprovalRequestId, PendingApproval>; |
| 92 | readonly turns: Array<{ | 93 | readonly turns: Array<{ |
| 93 | id: ReturnType<typeof ProviderTurnId.makeUnsafe>; | 94 | id: ReturnType<typeof ProviderTurnId.makeUnsafe>; |
| ... | @@ -115,6 +116,12 @@ export interface ClaudeCodeAdapterLiveOptions { | ... | @@ -115,6 +116,12 @@ export interface ClaudeCodeAdapterLiveOptions { |
| 115 | }) => ClaudeQueryRuntime; | 116 | }) => ClaudeQueryRuntime; |
| 116 | } | 117 | } |
| 117 | | 118 | |
| | 119 | function isUuid(value: string): boolean { |
| | 120 | return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test( |
| | 121 | value, |
| | 122 | ); |
| | 123 | } |
| | 124 | |
| 118 | function toMessage(cause: unknown, fallback: string): string { | 125 | function toMessage(cause: unknown, fallback: string): string { |
| 119 | if (cause instanceof Error && cause.message.length > 0) { | 126 | if (cause instanceof Error && cause.message.length > 0) { |
| 120 | return cause.message; | 127 | return cause.message; |
| ... | @@ -148,12 +155,13 @@ function readClaudeResumeState(resumeCursor: unknown): ClaudeResumeState | undef | ... | @@ -148,12 +155,13 @@ function readClaudeResumeState(resumeCursor: unknown): ClaudeResumeState | undef |
| 148 | }; | 155 | }; |
| 149 | | 156 | |
| 150 | const threadId = typeof cursor.threadId === "string" ? cursor.threadId : undefined; | 157 | const threadId = typeof cursor.threadId === "string" ? cursor.threadId : undefined; |
| 151 | const resume = | 158 | const resumeCandidate = |
| 152 | typeof cursor.resume === "string" | 159 | typeof cursor.resume === "string" |
| 153 | ? cursor.resume | 160 | ? cursor.resume |
| 154 | : typeof cursor.sessionId === "string" | 161 | : typeof cursor.sessionId === "string" |
| 155 | ? cursor.sessionId | 162 | ? cursor.sessionId |
| 156 | : undefined; | 163 | : undefined; |
| | 164 | const resume = resumeCandidate && isUuid(resumeCandidate) ? resumeCandidate : undefined; |
| 157 | const resumeSessionAt = | 165 | const resumeSessionAt = |
| 158 | typeof cursor.resumeSessionAt === "string" ? cursor.resumeSessionAt : undefined; | 166 | typeof cursor.resumeSessionAt === "string" ? cursor.resumeSessionAt : undefined; |
| 159 | const turnCountValue = typeof cursor.turnCount === "number" ? cursor.turnCount : undefined; | 167 | const turnCountValue = typeof cursor.turnCount === "number" ? cursor.turnCount : undefined; |
| ... | @@ -351,7 +359,7 @@ function makeClaudeCodeAdapter(options?: ClaudeCodeAdapterLiveOptions) { | ... | @@ -351,7 +359,7 @@ function makeClaudeCodeAdapter(options?: ClaudeCodeAdapterLiveOptions) { |
| 351 | | 359 | |
| 352 | const resumeCursor = { | 360 | const resumeCursor = { |
| 353 | threadId, | 361 | threadId, |
| 354 | resume: threadId, | 362 | ...(context.resumeSessionId ? { resume: context.resumeSessionId } : {}), |
| 355 | ...(context.lastAssistantUuid ? { resumeSessionAt: context.lastAssistantUuid } : {}), | 363 | ...(context.lastAssistantUuid ? { resumeSessionAt: context.lastAssistantUuid } : {}), |
| 356 | turnCount: context.turns.length, | 364 | turnCount: context.turns.length, |
| 357 | }; | 365 | }; |
| ... | @@ -369,6 +377,7 @@ function makeClaudeCodeAdapter(options?: ClaudeCodeAdapterLiveOptions) { | ... | @@ -369,6 +377,7 @@ function makeClaudeCodeAdapter(options?: ClaudeCodeAdapterLiveOptions) { |
| 369 | ): Effect.Effect<void> => | 377 | ): Effect.Effect<void> => |
| 370 | Effect.gen(function* () { | 378 | Effect.gen(function* () { |
| 371 | const nextThreadId = ProviderThreadId.makeUnsafe(message.session_id); | 379 | const nextThreadId = ProviderThreadId.makeUnsafe(message.session_id); |
| | 380 | context.resumeSessionId = message.session_id; |
| 372 | const changed = context.session.threadId !== nextThreadId; | 381 | const changed = context.session.threadId !== nextThreadId; |
| 373 | | 382 | |
| 374 | if (changed) { | 383 | if (changed) { |
| ... | @@ -935,7 +944,7 @@ function makeClaudeCodeAdapter(options?: ClaudeCodeAdapterLiveOptions) { | ... | @@ -935,7 +944,7 @@ function makeClaudeCodeAdapter(options?: ClaudeCodeAdapterLiveOptions) { |
| 935 | threadId, | 944 | threadId, |
| 936 | resumeCursor: { | 945 | resumeCursor: { |
| 937 | threadId, | 946 | threadId, |
| 938 | resume: resumeState?.resume ?? threadId, | 947 | ...(resumeState?.resume ? { resume: resumeState.resume } : {}), |
| 939 | ...(resumeState?.resumeSessionAt | 948 | ...(resumeState?.resumeSessionAt |
| 940 | ? { resumeSessionAt: resumeState.resumeSessionAt } | 949 | ? { resumeSessionAt: resumeState.resumeSessionAt } |
| 941 | : {}), | 950 | : {}), |
| ... | @@ -950,6 +959,7 @@ function makeClaudeCodeAdapter(options?: ClaudeCodeAdapterLiveOptions) { | ... | @@ -950,6 +959,7 @@ function makeClaudeCodeAdapter(options?: ClaudeCodeAdapterLiveOptions) { |
| 950 | promptQueue, | 959 | promptQueue, |
| 951 | query: queryRuntime, | 960 | query: queryRuntime, |
| 952 | startedAt, | 961 | startedAt, |
| | 962 | resumeSessionId: resumeState?.resume, |
| 953 | pendingApprovals, | 963 | pendingApprovals, |
| 954 | turns: [], | 964 | turns: [], |
| 955 | inFlightTools, | 965 | inFlightTools, |