diff options
| author | Daniel Polito <[email protected]> | 2026-01-13 15:28:08 -0300 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-01-13 12:28:08 -0600 |
| commit | 3600bd27f481c461734e517a40e01cd4e899e10f (patch) | |
| tree | e8d1a426a81ff04a4dfc2fb88ab925e4977bd936 /packages/app | |
| parent | 92089bb295ffc62e681baf5c93336e97a052b26e (diff) | |
| download | opencode-3600bd27f481c461734e517a40e01cd4e899e10f.tar.gz opencode-3600bd27f481c461734e517a40e01cd4e899e10f.zip | |
feat(desktop): Ask Question Tool Support (#8232)
Diffstat (limited to 'packages/app')
| -rw-r--r-- | packages/app/src/context/global-sync.tsx | 75 | ||||
| -rw-r--r-- | packages/app/src/pages/directory-layout.tsx | 8 |
2 files changed, 83 insertions, 0 deletions
diff --git a/packages/app/src/context/global-sync.tsx b/packages/app/src/context/global-sync.tsx index ddac1f228..c11edd292 100644 --- a/packages/app/src/context/global-sync.tsx +++ b/packages/app/src/context/global-sync.tsx @@ -16,6 +16,7 @@ import { type LspStatus, type VcsInfo, type PermissionRequest, + type QuestionRequest, createOpencodeClient, } from "@opencode-ai/sdk/v2/client" import { createStore, produce, reconcile } from "solid-js/store" @@ -49,6 +50,9 @@ type State = { permission: { [sessionID: string]: PermissionRequest[] } + question: { + [sessionID: string]: QuestionRequest[] + } mcp: { [name: string]: McpStatus } @@ -98,6 +102,7 @@ function createGlobalSync() { session_diff: {}, todo: {}, permission: {}, + question: {}, mcp: {}, lsp: [], vcs: undefined, @@ -208,6 +213,38 @@ function createGlobalSync() { } }) }), + sdk.question.list().then((x) => { + const grouped: Record<string, QuestionRequest[]> = {} + for (const question of x.data ?? []) { + if (!question?.id || !question.sessionID) continue + const existing = grouped[question.sessionID] + if (existing) { + existing.push(question) + continue + } + grouped[question.sessionID] = [question] + } + + batch(() => { + for (const sessionID of Object.keys(store.question)) { + if (grouped[sessionID]) continue + setStore("question", sessionID, []) + } + for (const [sessionID, questions] of Object.entries(grouped)) { + setStore( + "question", + sessionID, + reconcile( + questions + .filter((q) => !!q?.id) + .slice() + .sort((a, b) => a.id.localeCompare(b.id)), + { key: "id" }, + ), + ) + } + }) + }), ]).then(() => { setStore("status", "complete") }) @@ -396,6 +433,44 @@ function createGlobalSync() { ) break } + case "question.asked": { + const sessionID = event.properties.sessionID + const questions = store.question[sessionID] + if (!questions) { + setStore("question", sessionID, [event.properties]) + break + } + + const result = Binary.search(questions, event.properties.id, (q) => q.id) + if (result.found) { + setStore("question", sessionID, result.index, reconcile(event.properties)) + break + } + + setStore( + "question", + sessionID, + produce((draft) => { + draft.splice(result.index, 0, event.properties) + }), + ) + break + } + case "question.replied": + case "question.rejected": { + const questions = store.question[event.properties.sessionID] + if (!questions) break + const result = Binary.search(questions, event.properties.requestID, (q) => q.id) + if (!result.found) break + setStore( + "question", + event.properties.sessionID, + produce((draft) => { + draft.splice(result.index, 1) + }), + ) + break + } case "lsp.updated": { const sdk = createOpencodeClient({ baseUrl: globalSDK.url, diff --git a/packages/app/src/pages/directory-layout.tsx b/packages/app/src/pages/directory-layout.tsx index 39124637c..dca02489a 100644 --- a/packages/app/src/pages/directory-layout.tsx +++ b/packages/app/src/pages/directory-layout.tsx @@ -7,6 +7,7 @@ import { LocalProvider } from "@/context/local" import { base64Decode } from "@opencode-ai/util/encode" import { DataProvider } from "@opencode-ai/ui/context" import { iife } from "@opencode-ai/util/iife" +import type { QuestionAnswer } from "@opencode-ai/sdk/v2" export default function Layout(props: ParentProps) { const params = useParams() @@ -27,6 +28,11 @@ export default function Layout(props: ParentProps) { response: "once" | "always" | "reject" }) => sdk.client.permission.respond(input) + const replyToQuestion = (input: { requestID: string; answers: QuestionAnswer[] }) => + sdk.client.question.reply(input) + + const rejectQuestion = (input: { requestID: string }) => sdk.client.question.reject(input) + const navigateToSession = (sessionID: string) => { navigate(`/${params.dir}/session/${sessionID}`) } @@ -36,6 +42,8 @@ export default function Layout(props: ParentProps) { data={sync.data} directory={directory()} onPermissionRespond={respond} + onQuestionReply={replyToQuestion} + onQuestionReject={rejectQuestion} onNavigateToSession={navigateToSession} > <LocalProvider>{props.children}</LocalProvider> |
