fix(opencode): SessionPrompt.shell() now triggers loop if messages are queued (#10987)

This commit is contained in:
Goni Zahavy
2026-02-07 00:13:11 +02:00
committed by GitHub
parent 71930621fd
commit def907ae4b
2 changed files with 30 additions and 5 deletions

View File

@@ -539,7 +539,7 @@ export const SessionRoutes = lazy(() =>
}, },
auto: body.auto, auto: body.auto,
}) })
await SessionPrompt.loop(sessionID) await SessionPrompt.loop({ sessionID })
return c.json(true) return c.json(true)
}, },
) )

View File

@@ -174,7 +174,7 @@ export namespace SessionPrompt {
return message return message
} }
return loop(input.sessionID) return loop({sessionID: input.sessionID})
}) })
export async function resolvePromptParts(template: string): Promise<PromptInput["parts"]> { export async function resolvePromptParts(template: string): Promise<PromptInput["parts"]> {
@@ -239,6 +239,13 @@ export namespace SessionPrompt {
return controller.signal return controller.signal
} }
function resume(sessionID: string) {
const s = state()
if (!s[sessionID]) return
return s[sessionID].abort.signal
}
export function cancel(sessionID: string) { export function cancel(sessionID: string) {
log.info("cancel", { sessionID }) log.info("cancel", { sessionID })
const s = state() const s = state()
@@ -253,8 +260,14 @@ export namespace SessionPrompt {
return return
} }
export const loop = fn(Identifier.schema("session"), async (sessionID) => { export const LoopInput = z.object({
const abort = start(sessionID) sessionID: Identifier.schema("session"),
resume_existing: z.boolean().optional(),
})
export const loop = fn(LoopInput, async (input) => {
const { sessionID, resume_existing } = input
const abort = resume_existing ? resume(sessionID) : start(sessionID)
if (!abort) { if (!abort) {
return new Promise<MessageV2.WithParts>((resolve, reject) => { return new Promise<MessageV2.WithParts>((resolve, reject) => {
const callbacks = state()[sessionID].callbacks const callbacks = state()[sessionID].callbacks
@@ -1366,7 +1379,19 @@ NOTE: At any point in time through this workflow you should feel free to ask the
if (!abort) { if (!abort) {
throw new Session.BusyError(input.sessionID) throw new Session.BusyError(input.sessionID)
} }
using _ = defer(() => cancel(input.sessionID))
using _ = defer(() => {
// If no queued callbacks, cancel (the default)
const callbacks = state()[input.sessionID]?.callbacks ?? []
if (callbacks.length === 0) {
cancel(input.sessionID)
} else {
// Otherwise, trigger the session loop to process queued items
loop({sessionID: input.sessionID, resume_existing: true}).catch((error) => {
log.error("session loop failed to resume after shell command", { sessionID: input.sessionID, error })
})
}
})
const session = await Session.get(input.sessionID) const session = await Session.get(input.sessionID)
if (session.revert) { if (session.revert) {