Просмотр исходного кода

fix(desktop): busy state and reactivity

Adam 3 месяцев назад
Родитель
Сommit
333b8e907b

+ 1 - 1
packages/desktop/src/components/prompt-input.tsx

@@ -266,7 +266,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
     if (!existing) {
       const created = await sdk.client.session.create()
       existing = created.data ?? undefined
-      if (existing) navigate(`${local.slug()}/session/${existing.id}`)
+      if (existing) navigate(existing.id)
     }
     if (!existing) return
 

+ 9 - 0
packages/desktop/src/context/global-sync.tsx

@@ -11,6 +11,7 @@ import type {
   Project,
   FileDiff,
   Todo,
+  SessionStatus,
 } from "@opencode-ai/sdk"
 import { createStore, produce, reconcile } from "solid-js/store"
 import { Binary } from "@/utils/binary"
@@ -25,6 +26,9 @@ type State = {
   config: Config
   path: Path
   session: Session[]
+  session_status: {
+    [sessionID: string]: SessionStatus
+  }
   session_diff: {
     [sessionID: string]: FileDiff[]
   }
@@ -68,6 +72,7 @@ export const { use: useGlobalSync, provider: GlobalSyncProvider } = createSimple
           agent: [],
           provider: [],
           session: [],
+          session_status: {},
           session_diff: {},
           todo: {},
           limit: 10,
@@ -108,6 +113,10 @@ export const { use: useGlobalSync, provider: GlobalSyncProvider } = createSimple
         case "todo.updated":
           setStore("todo", event.properties.sessionID, event.properties.todos)
           break
+        case "session.status": {
+          setStore("session_status", event.properties.sessionID, event.properties.status)
+          break
+        }
         case "message.updated": {
           const messages = store.message[event.properties.info.sessionID]
           if (!messages) {

+ 11 - 11
packages/desktop/src/context/session.tsx

@@ -58,16 +58,13 @@ export const { use: useSession, provider: SessionProvider } = createSimpleContex
       if (!store.messageId) return lastUserMessage()
       return userMessages()?.find((m) => m.id === store.messageId)
     })
-    const working = createMemo(() => {
-      if (!params.id) return false
-      const last = lastUserMessage()
-      if (!last) return false
-      const assistantMessages = sync.data.message[params.id]?.filter(
-        (m) => m.role === "assistant" && m.parentID == last?.id,
-      ) as AssistantMessage[]
-      const error = assistantMessages?.find((m) => m?.error)?.error
-      return !last?.summary?.body && !error
-    })
+    const status = createMemo(
+      () =>
+        sync.data.session_status[params.id] ?? {
+          type: "idle",
+        },
+    )
+    const working = createMemo(() => status()?.type !== "idle")
 
     const cost = createMemo(() => {
       const total = pipe(
@@ -102,8 +99,11 @@ export const { use: useSession, provider: SessionProvider } = createSimpleContex
     })
 
     return {
-      id: params.id,
+      get id() {
+        return params.id
+      },
       info,
+      status,
       working,
       diffs,
       prompt: {

+ 1 - 0
packages/desktop/src/context/sync.tsx

@@ -26,6 +26,7 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({
             .slice(0, store.limit)
           setStore("session", sessions)
         }),
+      status: () => sdk.client.session.status().then((x) => setStore("session_status", x.data!)),
       config: () => sdk.client.config.get().then((x) => setStore("config", x.data!)),
       changes: () => sdk.client.file.status().then((x) => setStore("changes", x.data!)),
       node: () => sdk.client.file.list({ query: { path: "/" } }).then((x) => setStore("node", x.data!)),

+ 5 - 7
packages/desktop/src/pages/directory-layout.tsx

@@ -14,12 +14,10 @@ export default function Layout(props: ParentProps) {
     return sync.data.projects.find((x) => x.worktree === decoded)?.worktree ?? "/"
   })
   return (
-    <Show when={params.id || true} keyed>
-      <SDKProvider directory={directory()}>
-        <SyncProvider>
-          <LocalProvider>{props.children}</LocalProvider>
-        </SyncProvider>
-      </SDKProvider>
-    </Show>
+    <SDKProvider directory={directory()}>
+      <SyncProvider>
+        <LocalProvider>{props.children}</LocalProvider>
+      </SyncProvider>
+    </SDKProvider>
   )
 }

+ 6 - 10
packages/desktop/src/pages/session.tsx

@@ -378,15 +378,9 @@ export default function Page() {
                             >
                               <For each={session.messages.user()}>
                                 {(message) => {
-                                  const assistantMessages = createMemo(() => {
-                                    if (!session.id) return []
-                                    return sync.data.message[session.id]?.filter(
-                                      (m) => m.role === "assistant" && m.parentID == message.id,
-                                    ) as AssistantMessageType[]
-                                  })
-                                  const error = createMemo(() => assistantMessages().find((m) => m?.error)?.error)
-                                  const working = createMemo(() => !message.summary?.body && !error())
-
+                                  const working = createMemo(
+                                    () => message.id === session.messages.last()?.id && session.working(),
+                                  )
                                   const handleClick = () => session.messages.setActive(message.id)
 
                                   return (
@@ -473,7 +467,9 @@ export default function Page() {
                                 ?.flatMap((m) => sync.data.part[m.id])
                                 .some((p) => p?.type === "tool"),
                             )
-                            const working = createMemo(() => !message.summary?.body && !error())
+                            const working = createMemo(
+                              () => message.id === session.messages.last()?.id && session.working(),
+                            )
 
                             // allowing time for the animations to finish
                             createEffect(() => {