diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx index 644ac262241..b24a49dd048 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx @@ -215,9 +215,11 @@ export function Prompt(props: PromptProps) { }, 5000) if (store.interrupt >= 2) { - sdk.client.session.abort({ - sessionID: props.sessionID, - }) + sdk.client.session + .abort({ + sessionID: props.sessionID, + }) + .catch(() => {}) setStore("interrupt", 0) } dialog.clear() diff --git a/packages/opencode/src/server/server.ts b/packages/opencode/src/server/server.ts index 32d7a179555..01f0be0768a 100644 --- a/packages/opencode/src/server/server.ts +++ b/packages/opencode/src/server/server.ts @@ -1424,14 +1424,10 @@ export namespace Server { ), validator("json", SessionPrompt.PromptInput.omit({ sessionID: true })), async (c) => { - c.status(200) - c.header("Content-Type", "application/json") - return stream(c, async (stream) => { - const sessionID = c.req.valid("param").sessionID - const body = c.req.valid("json") - const msg = await SessionPrompt.prompt({ ...body, sessionID }) - stream.write(JSON.stringify(msg)) - }) + const sessionID = c.req.valid("param").sessionID + const body = c.req.valid("json") + const msg = await SessionPrompt.prompt({ ...body, sessionID }) + return c.json(msg) }, ) .post( @@ -1456,13 +1452,12 @@ export namespace Server { ), validator("json", SessionPrompt.PromptInput.omit({ sessionID: true })), async (c) => { - c.status(204) - c.header("Content-Type", "application/json") - return stream(c, async () => { - const sessionID = c.req.valid("param").sessionID - const body = c.req.valid("json") - SessionPrompt.prompt({ ...body, sessionID }) + const sessionID = c.req.valid("param").sessionID + const body = c.req.valid("json") + void SessionPrompt.prompt({ ...body, sessionID }).catch((error) => { + log.error("prompt_async failed", { error, sessionID }) }) + return c.body(null, 204) }, ) .post( diff --git a/packages/opencode/src/util/rpc.ts b/packages/opencode/src/util/rpc.ts index ebd8be40e45..f9749979d39 100644 --- a/packages/opencode/src/util/rpc.ts +++ b/packages/opencode/src/util/rpc.ts @@ -7,8 +7,18 @@ export namespace Rpc { onmessage = async (evt) => { const parsed = JSON.parse(evt.data) if (parsed.type === "rpc.request") { - const result = await rpc[parsed.method](parsed.input) - postMessage(JSON.stringify({ type: "rpc.result", result, id: parsed.id })) + try { + const result = await rpc[parsed.method](parsed.input) + postMessage(JSON.stringify({ type: "rpc.result", result, id: parsed.id })) + } catch (error) { + postMessage( + JSON.stringify({ + type: "rpc.error", + error: error instanceof Error ? error.message : String(error), + id: parsed.id, + }), + ) + } } } } @@ -21,15 +31,22 @@ export namespace Rpc { postMessage: (data: string) => void | null onmessage: ((this: Worker, ev: MessageEvent) => any) | null }) { - const pending = new Map void>() + const pending = new Map void; reject: (error: Error) => void }>() const listeners = new Map void>>() let id = 0 target.onmessage = async (evt) => { const parsed = JSON.parse(evt.data) if (parsed.type === "rpc.result") { - const resolve = pending.get(parsed.id) - if (resolve) { - resolve(parsed.result) + const callbacks = pending.get(parsed.id) + if (callbacks) { + callbacks.resolve(parsed.result) + pending.delete(parsed.id) + } + } + if (parsed.type === "rpc.error") { + const callbacks = pending.get(parsed.id) + if (callbacks) { + callbacks.reject(new Error(parsed.error)) pending.delete(parsed.id) } } @@ -45,8 +62,8 @@ export namespace Rpc { return { call(method: Method, input: Parameters[0]): Promise> { const requestId = id++ - return new Promise((resolve) => { - pending.set(requestId, resolve) + return new Promise((resolve, reject) => { + pending.set(requestId, { resolve, reject }) target.postMessage(JSON.stringify({ type: "rpc.request", method, input, id: requestId })) }) },