summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGoni Zahavy <[email protected]>2026-02-07 00:13:11 +0200
committerGitHub <[email protected]>2026-02-06 16:13:11 -0600
commitdef907ae4bf228b43e0b4606f65b9cf2e03c65fc (patch)
tree23f2486c24d55de9c596b120d0f38b25a5ff1952
parent71930621fdfeb8f3d2b3baf956cd690cd699101a (diff)
downloadopencode-def907ae4bf228b43e0b4606f65b9cf2e03c65fc.tar.gz
opencode-def907ae4bf228b43e0b4606f65b9cf2e03c65fc.zip
fix(opencode): SessionPrompt.shell() now triggers loop if messages are queued (#10987)
-rw-r--r--packages/opencode/src/server/routes/session.ts2
-rw-r--r--packages/opencode/src/session/prompt.ts33
2 files changed, 30 insertions, 5 deletions
diff --git a/packages/opencode/src/server/routes/session.ts b/packages/opencode/src/server/routes/session.ts
index 3850376bd..82e6f3121 100644
--- a/packages/opencode/src/server/routes/session.ts
+++ b/packages/opencode/src/server/routes/session.ts
@@ -539,7 +539,7 @@ export const SessionRoutes = lazy(() =>
},
auto: body.auto,
})
- await SessionPrompt.loop(sessionID)
+ await SessionPrompt.loop({ sessionID })
return c.json(true)
},
)
diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts
index bcfccfb3e..6643466b2 100644
--- a/packages/opencode/src/session/prompt.ts
+++ b/packages/opencode/src/session/prompt.ts
@@ -174,7 +174,7 @@ export namespace SessionPrompt {
return message
}
- return loop(input.sessionID)
+ return loop({sessionID: input.sessionID})
})
export async function resolvePromptParts(template: string): Promise<PromptInput["parts"]> {
@@ -239,6 +239,13 @@ export namespace SessionPrompt {
return controller.signal
}
+ function resume(sessionID: string) {
+ const s = state()
+ if (!s[sessionID]) return
+
+ return s[sessionID].abort.signal
+ }
+
export function cancel(sessionID: string) {
log.info("cancel", { sessionID })
const s = state()
@@ -253,8 +260,14 @@ export namespace SessionPrompt {
return
}
- export const loop = fn(Identifier.schema("session"), async (sessionID) => {
- const abort = start(sessionID)
+ export const LoopInput = z.object({
+ 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) {
return new Promise<MessageV2.WithParts>((resolve, reject) => {
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) {
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)
if (session.revert) {