From e6d549497c8024da76165b6306e1ea754ae1e34d Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Mon, 17 Nov 2025 10:55:30 -0500 Subject: [PATCH] sync --- .opencode/{opencode.json => opencode.jsonc} | 8 ++- .../src/cli/cmd/tui/routes/session/index.tsx | 53 +++++++--------- packages/opencode/src/server/server.ts | 5 +- packages/opencode/src/session/processor.ts | 9 ++- packages/opencode/src/session/prompt.ts | 58 ++--------------- packages/opencode/src/session/status.ts | 63 +++++++++++++++++++ 6 files changed, 105 insertions(+), 91 deletions(-) rename .opencode/{opencode.json => opencode.jsonc} (60%) create mode 100644 packages/opencode/src/session/status.ts diff --git a/.opencode/opencode.json b/.opencode/opencode.jsonc similarity index 60% rename from .opencode/opencode.json rename to .opencode/opencode.jsonc index 2ec720efb..02278ce3a 100644 --- a/.opencode/opencode.json +++ b/.opencode/opencode.jsonc @@ -3,7 +3,9 @@ "plugin": ["opencode-openai-codex-auth"], "provider": { "opencode": { - "options": {} - } - } + "options": { + // "baseURL": "http://localhost:8080" + }, + }, + }, } diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx index fb8f9860a..192123e00 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -20,21 +20,12 @@ import { useTheme } from "@tui/context/theme" import { BoxRenderable, ScrollBoxRenderable, - TextAttributes, addDefaultParsers, MacOSScrollAccel, type ScrollAcceleration, } from "@opentui/core" import { Prompt, type PromptRef } from "@tui/component/prompt" -import type { - AssistantMessage, - Part, - ToolPart, - UserMessage, - TextPart, - ReasoningPart, - CompactionPart, -} from "@opencode-ai/sdk" +import type { AssistantMessage, Part, ToolPart, UserMessage, TextPart, ReasoningPart } from "@opencode-ai/sdk" import { useLocal } from "@tui/context/local" import { Locale } from "@/util/locale" import type { Tool } from "@/tool/tool" @@ -674,13 +665,6 @@ export function Session() { // snap to bottom when session changes createEffect(on(() => route.sessionID, toBottom)) - const status = createMemo( - () => - sync.data.session_status[route.sessionID] ?? { - type: "idle", - }, - ) - return ( @@ -829,17 +813,6 @@ export function Session() { )} - - - {Locale.titlecase(lastUserMessage().agent)} - - - - {(status() as any).message} [retry #{(status() as any).attempt}] - - - - (prompt = r)} @@ -957,6 +930,13 @@ function UserMessage(props: { function AssistantMessage(props: { message: AssistantMessage; parts: Part[]; last: boolean }) { const local = useLocal() const { theme } = useTheme() + const sync = useSync() + const status = createMemo( + () => + sync.data.session_status[props.message.sessionID] ?? { + type: "idle", + }, + ) return ( <> @@ -974,9 +954,7 @@ function AssistantMessage(props: { message: AssistantMessage; parts: Part[]; las ) }} - + {props.message.error?.data.message} + + + {Locale.titlecase(props.message.mode)} + + + + {(status() as any).message} [attempt #{(status() as any).attempt}] + + + + { - const result = SessionPrompt.status() + const result = SessionStatus.list() return c.json(result) }, ) diff --git a/packages/opencode/src/session/processor.ts b/packages/opencode/src/session/processor.ts index 7b3ad90b5..de96c5eea 100644 --- a/packages/opencode/src/session/processor.ts +++ b/packages/opencode/src/session/processor.ts @@ -10,6 +10,7 @@ import { Snapshot } from "@/snapshot" import { SessionSummary } from "./summary" import { Bus } from "@/bus" import { SessionRetry } from "./retry" +import { SessionStatus } from "./status" export namespace SessionProcessor { const DOOM_LOOP_THRESHOLD = 3 @@ -49,6 +50,7 @@ export namespace SessionProcessor { input.abort.throwIfAborted() switch (value.type) { case "start": + SessionStatus.set(input.sessionID, { type: "busy" }) break case "reasoning-start": @@ -325,7 +327,12 @@ export namespace SessionProcessor { attempt++ const delay = SessionRetry.getRetryDelayInMs(error, attempt) if (delay) { - await SessionRetry.sleep(delay, input.abort) + SessionStatus.set(input.sessionID, { + type: "retry", + attempt, + message: error.data.message, + }) + await SessionRetry.sleep(delay, input.abort).catch(() => {}) continue } } diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index 5bd6a2496..b8f3d112d 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -28,9 +28,8 @@ import { Plugin } from "../plugin" import PROMPT_PLAN from "../session/prompt/plan.txt" import BUILD_SWITCH from "../session/prompt/build-switch.txt" -import { ModelsDev } from "../provider/models" import { defer } from "../util/defer" -import { mapValues, mergeDeep, pipe } from "remeda" +import { mergeDeep, pipe } from "remeda" import { ToolRegistry } from "../tool/registry" import { Wildcard } from "../util/wildcard" import { MCP } from "../mcp" @@ -48,39 +47,13 @@ import { NamedError } from "@/util/error" import { fn } from "@/util/fn" import { SessionProcessor } from "./processor" import { TaskTool } from "@/tool/task" -import type { Message } from "vscode-jsonrpc" +import { SessionStatus } from "./status" export namespace SessionPrompt { const log = Log.create({ service: "session.prompt" }) export const OUTPUT_TOKEN_MAX = 32_000 - export const Status = z - .union([ - z.object({ - type: z.literal("idle"), - }), - z.object({ - type: z.literal("retry"), - attempt: z.number(), - message: z.string(), - }), - z.object({ - type: z.literal("busy"), - }), - ]) - .meta({ - ref: "SessionStatus", - }) - export type Status = z.infer - export const Event = { - Status: Bus.event( - "session.status", - z.object({ - sessionID: z.string(), - status: Status, - }), - ), Idle: Bus.event( "session.idle", z.object({ @@ -95,7 +68,6 @@ export namespace SessionPrompt { string, { abort: AbortController - status: Status callbacks: { resolve(input: MessageV2.WithParts): void reject(): void @@ -111,21 +83,9 @@ export namespace SessionPrompt { }, ) - export function status() { - return mapValues(state(), (item) => item.status) - } - - export function getStatus(sessionID: string) { - return ( - state()[sessionID]?.status ?? { - type: "idle", - } - ) - } - export function assertNotBusy(sessionID: string) { - const status = getStatus(sessionID) - if (status?.type !== "idle") throw new Session.BusyError(sessionID) + const match = state()[sessionID] + if (match) throw new Session.BusyError(sessionID) } export const PromptInput = z.object({ @@ -252,13 +212,8 @@ export namespace SessionPrompt { const controller = new AbortController() s[sessionID] = { abort: controller, - status: { type: "busy" }, callbacks: [], } - Bus.publish(Event.Status, { - sessionID, - status: s[sessionID].status, - }) return controller.signal } @@ -272,10 +227,7 @@ export namespace SessionPrompt { item.reject() } delete s[sessionID] - Bus.publish(Event.Status, { - sessionID, - status: { type: "idle" }, - }) + SessionStatus.set(sessionID, { type: "idle" }) return } diff --git a/packages/opencode/src/session/status.ts b/packages/opencode/src/session/status.ts new file mode 100644 index 000000000..ecac222f8 --- /dev/null +++ b/packages/opencode/src/session/status.ts @@ -0,0 +1,63 @@ +import { Bus } from "@/bus" +import { Instance } from "@/project/instance" +import z from "zod" + +export namespace SessionStatus { + export const Info = z + .union([ + z.object({ + type: z.literal("idle"), + }), + z.object({ + type: z.literal("retry"), + attempt: z.number(), + message: z.string(), + }), + z.object({ + type: z.literal("busy"), + }), + ]) + .meta({ + ref: "SessionStatus", + }) + export type Info = z.infer + + export const Event = { + Status: Bus.event( + "session.status", + z.object({ + sessionID: z.string(), + status: Info, + }), + ), + } + + const state = Instance.state(() => { + const data: Record = {} + return data + }) + + export function get(sessionID: string) { + return ( + state()[sessionID] ?? { + type: "idle", + } + ) + } + + export function list() { + return Object.values(state()) + } + + export function set(sessionID: string, status: Info) { + Bus.publish(Event.Status, { + sessionID, + status, + }) + if (status.type === "idle") { + delete state()[sessionID] + return + } + state()[sessionID] = status + } +}