fix(session-recovery): gate resume prompts
This commit is contained in:
@@ -3,11 +3,13 @@ import type { MessageData, ResumeConfig } from "./types"
|
|||||||
import { readParts } from "./storage"
|
import { readParts } from "./storage"
|
||||||
import { isSqliteBackend } from "../../shared/opencode-storage-detection"
|
import { isSqliteBackend } from "../../shared/opencode-storage-detection"
|
||||||
import { normalizeSDKResponse } from "../../shared"
|
import { normalizeSDKResponse } from "../../shared"
|
||||||
|
import { promptAsyncAfterSessionIdle } from "../shared/prompt-async-gate"
|
||||||
|
|
||||||
type Client = ReturnType<typeof createOpencodeClient>
|
type Client = ReturnType<typeof createOpencodeClient>
|
||||||
type ClientWithPromptAsync = {
|
type ClientWithPromptAsync = {
|
||||||
session: {
|
session: {
|
||||||
promptAsync: (opts: { path: { id: string }; body: Record<string, unknown> }) => Promise<unknown>
|
promptAsync: (opts: { path: { id: string }; body: Record<string, unknown> }) => Promise<unknown>
|
||||||
|
status?: () => Promise<unknown>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,9 +121,14 @@ export async function recoverToolResultMissing(
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
await client.session.promptAsync(promptInput)
|
const promptResult = await promptAsyncAfterSessionIdle({
|
||||||
|
client,
|
||||||
|
sessionID,
|
||||||
|
source: "session-recovery-tool-result-missing",
|
||||||
|
input: promptInput,
|
||||||
|
})
|
||||||
|
|
||||||
return true
|
return promptResult.status === "dispatched"
|
||||||
} catch {
|
} catch {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { readParts } from "./storage"
|
|||||||
import type { MessageData } from "./types"
|
import type { MessageData } from "./types"
|
||||||
import { normalizeSDKResponse } from "../../shared"
|
import { normalizeSDKResponse } from "../../shared"
|
||||||
import { isSqliteBackend } from "../../shared/opencode-storage-detection"
|
import { isSqliteBackend } from "../../shared/opencode-storage-detection"
|
||||||
|
import { promptAsyncAfterSessionIdle } from "../shared/prompt-async-gate"
|
||||||
|
|
||||||
type Client = ReturnType<typeof createOpencodeClient>
|
type Client = ReturnType<typeof createOpencodeClient>
|
||||||
|
|
||||||
@@ -100,8 +101,21 @@ export async function recoverUnavailableTool(
|
|||||||
body: { parts: toolResultParts },
|
body: { parts: toolResultParts },
|
||||||
}
|
}
|
||||||
const promptAsync = client.session.promptAsync as (...args: never[]) => unknown
|
const promptAsync = client.session.promptAsync as (...args: never[]) => unknown
|
||||||
await Reflect.apply(promptAsync, client.session, [promptInput])
|
const promptClient = {
|
||||||
return true
|
session: {
|
||||||
|
status: client.session.status,
|
||||||
|
promptAsync: (input: PromptWithToolResultInput) => (
|
||||||
|
Reflect.apply(promptAsync, client.session, [input]) as Promise<unknown>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const promptResult = await promptAsyncAfterSessionIdle<PromptWithToolResultInput>({
|
||||||
|
client: promptClient,
|
||||||
|
sessionID,
|
||||||
|
source: "session-recovery-unavailable-tool",
|
||||||
|
input: promptInput,
|
||||||
|
})
|
||||||
|
return promptResult.status === "dispatched"
|
||||||
} catch {
|
} catch {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import type { createOpencodeClient } from "@opencode-ai/sdk"
|
import type { createOpencodeClient } from "@opencode-ai/sdk"
|
||||||
import type { MessageData, ResumeConfig } from "./types"
|
import type { MessageData, ResumeConfig } from "./types"
|
||||||
import { createInternalAgentContinuationTextPart, resolveInheritedPromptTools } from "../../shared"
|
import { createInternalAgentContinuationTextPart, resolveInheritedPromptTools } from "../../shared"
|
||||||
|
import { promptAsyncAfterSessionIdle } from "../shared/prompt-async-gate"
|
||||||
|
|
||||||
const RECOVERY_RESUME_TEXT = "[session recovered - continuing previous task]"
|
const RECOVERY_RESUME_TEXT = "[session recovered - continuing previous task]"
|
||||||
|
|
||||||
@@ -32,17 +33,22 @@ export async function resumeSession(client: Client, config: ResumeConfig): Promi
|
|||||||
: undefined
|
: undefined
|
||||||
const launchVariant = config.model?.variant
|
const launchVariant = config.model?.variant
|
||||||
|
|
||||||
await client.session.promptAsync({
|
const promptResult = await promptAsyncAfterSessionIdle({
|
||||||
path: { id: config.sessionID },
|
client,
|
||||||
body: {
|
sessionID: config.sessionID,
|
||||||
parts: [createInternalAgentContinuationTextPart(RECOVERY_RESUME_TEXT)],
|
source: "session-recovery",
|
||||||
agent: config.agent,
|
input: {
|
||||||
...(launchModel ? { model: launchModel } : {}),
|
path: { id: config.sessionID },
|
||||||
...(launchVariant ? { variant: launchVariant } : {}),
|
body: {
|
||||||
...(inheritedTools ? { tools: inheritedTools } : {}),
|
parts: [createInternalAgentContinuationTextPart(RECOVERY_RESUME_TEXT)],
|
||||||
|
agent: config.agent,
|
||||||
|
...(launchModel ? { model: launchModel } : {}),
|
||||||
|
...(launchVariant ? { variant: launchVariant } : {}),
|
||||||
|
...(inheritedTools ? { tools: inheritedTools } : {}),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
return true
|
return promptResult.status === "dispatched"
|
||||||
} catch {
|
} catch {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user