Browse Source

fix(app): don't use findLast

adamelmore 4 tuần trước cách đây
mục cha
commit
1080f37f9c

+ 2 - 1
packages/app/src/components/session-context-usage.tsx

@@ -4,6 +4,7 @@ import { ProgressCircle } from "@opencode-ai/ui/progress-circle"
 import { Button } from "@opencode-ai/ui/button"
 import { Button } from "@opencode-ai/ui/button"
 import { useParams } from "@solidjs/router"
 import { useParams } from "@solidjs/router"
 import { AssistantMessage } from "@opencode-ai/sdk/v2/client"
 import { AssistantMessage } from "@opencode-ai/sdk/v2/client"
+import { findLast } from "@opencode-ai/util/array"
 
 
 import { useLayout } from "@/context/layout"
 import { useLayout } from "@/context/layout"
 import { useSync } from "@/context/sync"
 import { useSync } from "@/context/sync"
@@ -36,7 +37,7 @@ export function SessionContextUsage(props: SessionContextUsageProps) {
 
 
   const context = createMemo(() => {
   const context = createMemo(() => {
     const locale = language.locale()
     const locale = language.locale()
-    const last = messages().findLast((x) => {
+    const last = findLast(messages(), (x) => {
       if (x.role !== "assistant") return false
       if (x.role !== "assistant") return false
       const total = x.tokens.input + x.tokens.output + x.tokens.reasoning + x.tokens.cache.read + x.tokens.cache.write
       const total = x.tokens.input + x.tokens.output + x.tokens.reasoning + x.tokens.cache.read + x.tokens.cache.write
       return total > 0
       return total > 0

+ 3 - 2
packages/app/src/components/session/session-context-tab.tsx

@@ -5,6 +5,7 @@ import { DateTime } from "luxon"
 import { useSync } from "@/context/sync"
 import { useSync } from "@/context/sync"
 import { useLayout } from "@/context/layout"
 import { useLayout } from "@/context/layout"
 import { checksum } from "@opencode-ai/util/encode"
 import { checksum } from "@opencode-ai/util/encode"
+import { findLast } from "@opencode-ai/util/array"
 import { Icon } from "@opencode-ai/ui/icon"
 import { Icon } from "@opencode-ai/ui/icon"
 import { Accordion } from "@opencode-ai/ui/accordion"
 import { Accordion } from "@opencode-ai/ui/accordion"
 import { StickyAccordionHeader } from "@opencode-ai/ui/sticky-accordion-header"
 import { StickyAccordionHeader } from "@opencode-ai/ui/sticky-accordion-header"
@@ -26,7 +27,7 @@ export function SessionContextTab(props: SessionContextTabProps) {
   const language = useLanguage()
   const language = useLanguage()
 
 
   const ctx = createMemo(() => {
   const ctx = createMemo(() => {
-    const last = props.messages().findLast((x) => {
+    const last = findLast(props.messages(), (x) => {
       if (x.role !== "assistant") return false
       if (x.role !== "assistant") return false
       const total = x.tokens.input + x.tokens.output + x.tokens.reasoning + x.tokens.cache.read + x.tokens.cache.write
       const total = x.tokens.input + x.tokens.output + x.tokens.reasoning + x.tokens.cache.read + x.tokens.cache.write
       return total > 0
       return total > 0
@@ -81,7 +82,7 @@ export function SessionContextTab(props: SessionContextTabProps) {
   })
   })
 
 
   const systemPrompt = createMemo(() => {
   const systemPrompt = createMemo(() => {
-    const msg = props.visibleUserMessages().findLast((m) => !!m.system)
+    const msg = findLast(props.visibleUserMessages(), (m) => !!m.system)
     const system = msg?.system
     const system = msg?.system
     if (!system) return
     if (!system) return
     const trimmed = system.trim()
     const trimmed = system.trim()

+ 5 - 4
packages/app/src/pages/session.tsx

@@ -40,6 +40,7 @@ import { useTerminal, type LocalPTY } from "@/context/terminal"
 import { useLayout } from "@/context/layout"
 import { useLayout } from "@/context/layout"
 import { Terminal } from "@/components/terminal"
 import { Terminal } from "@/components/terminal"
 import { checksum, base64Encode, base64Decode } from "@opencode-ai/util/encode"
 import { checksum, base64Encode, base64Decode } from "@opencode-ai/util/encode"
+import { findLast } from "@opencode-ai/util/array"
 import { getFilename } from "@opencode-ai/util/path"
 import { getFilename } from "@opencode-ai/util/path"
 import { useDialog } from "@opencode-ai/ui/context/dialog"
 import { useDialog } from "@opencode-ai/ui/context/dialog"
 import { DialogSelectFile } from "@/components/dialog-select-file"
 import { DialogSelectFile } from "@/components/dialog-select-file"
@@ -748,7 +749,7 @@ export default function Page() {
         }
         }
         const revert = info()?.revert?.messageID
         const revert = info()?.revert?.messageID
         // Find the last user message that's not already reverted
         // Find the last user message that's not already reverted
-        const message = userMessages().findLast((x) => !revert || x.id < revert)
+        const message = findLast(userMessages(), (x) => !revert || x.id < revert)
         if (!message) return
         if (!message) return
         await sdk.client.session.revert({ sessionID, messageID: message.id })
         await sdk.client.session.revert({ sessionID, messageID: message.id })
         // Restore the prompt from the reverted message
         // Restore the prompt from the reverted message
@@ -758,7 +759,7 @@ export default function Page() {
           prompt.set(restored)
           prompt.set(restored)
         }
         }
         // Navigate to the message before the reverted one (which will be the new last visible message)
         // Navigate to the message before the reverted one (which will be the new last visible message)
-        const priorMessage = userMessages().findLast((x) => x.id < message.id)
+        const priorMessage = findLast(userMessages(), (x) => x.id < message.id)
         setActiveMessage(priorMessage)
         setActiveMessage(priorMessage)
       },
       },
     },
     },
@@ -780,14 +781,14 @@ export default function Page() {
           await sdk.client.session.unrevert({ sessionID })
           await sdk.client.session.unrevert({ sessionID })
           prompt.reset()
           prompt.reset()
           // Navigate to the last message (the one that was at the revert point)
           // Navigate to the last message (the one that was at the revert point)
-          const lastMsg = userMessages().findLast((x) => x.id >= revertMessageID)
+          const lastMsg = findLast(userMessages(), (x) => x.id >= revertMessageID)
           setActiveMessage(lastMsg)
           setActiveMessage(lastMsg)
           return
           return
         }
         }
         // Partial redo - move forward to next message
         // Partial redo - move forward to next message
         await sdk.client.session.revert({ sessionID, messageID: nextMessage.id })
         await sdk.client.session.revert({ sessionID, messageID: nextMessage.id })
         // Navigate to the message before the new revert point
         // Navigate to the message before the new revert point
-        const priorMsg = userMessages().findLast((x) => x.id < nextMessage.id)
+        const priorMsg = findLast(userMessages(), (x) => x.id < nextMessage.id)
         setActiveMessage(priorMsg)
         setActiveMessage(priorMsg)
       },
       },
     },
     },

+ 2 - 1
packages/ui/src/components/message-part.tsx

@@ -42,6 +42,7 @@ import { Checkbox } from "./checkbox"
 import { DiffChanges } from "./diff-changes"
 import { DiffChanges } from "./diff-changes"
 import { Markdown } from "./markdown"
 import { Markdown } from "./markdown"
 import { ImagePreview } from "./image-preview"
 import { ImagePreview } from "./image-preview"
+import { findLast } from "@opencode-ai/util/array"
 import { getDirectory as _getDirectory, getFilename } from "@opencode-ai/util/path"
 import { getDirectory as _getDirectory, getFilename } from "@opencode-ai/util/path"
 import { checksum } from "@opencode-ai/util/encode"
 import { checksum } from "@opencode-ai/util/encode"
 import { Tooltip } from "./tooltip"
 import { Tooltip } from "./tooltip"
@@ -891,7 +892,7 @@ ToolRegistry.register({
       if (!sessionId) return undefined
       if (!sessionId) return undefined
       // Find the tool part that matches the permission's callID
       // Find the tool part that matches the permission's callID
       const messages = data.store.message[sessionId] ?? []
       const messages = data.store.message[sessionId] ?? []
-      const message = messages.findLast((m) => m.id === perm.tool!.messageID)
+      const message = findLast(messages, (m) => m.id === perm.tool!.messageID)
       if (!message) return undefined
       if (!message) return undefined
       const parts = data.store.part[message.id] ?? []
       const parts = data.store.part[message.id] ?? []
       for (const part of parts) {
       for (const part of parts) {

+ 2 - 1
packages/ui/src/components/session-turn.tsx

@@ -11,6 +11,7 @@ import { type FileDiff } from "@opencode-ai/sdk/v2"
 import { useData } from "../context"
 import { useData } from "../context"
 import { useDiffComponent } from "../context/diff"
 import { useDiffComponent } from "../context/diff"
 import { type UiI18nKey, type UiI18nParams, useI18n } from "../context/i18n"
 import { type UiI18nKey, type UiI18nParams, useI18n } from "../context/i18n"
+import { findLast } from "@opencode-ai/util/array"
 import { getDirectory, getFilename } from "@opencode-ai/util/path"
 import { getDirectory, getFilename } from "@opencode-ai/util/path"
 
 
 import { Binary } from "@opencode-ai/util/binary"
 import { Binary } from "@opencode-ai/util/binary"
@@ -266,7 +267,7 @@ export function SessionTurn(
     const next = nextPermission()
     const next = nextPermission()
     if (!next || !next.tool) return emptyPermissionParts
     if (!next || !next.tool) return emptyPermissionParts
 
 
-    const message = assistantMessages().findLast((m) => m.id === next.tool!.messageID)
+    const message = findLast(assistantMessages(), (m) => m.id === next.tool!.messageID)
     if (!message) return emptyPermissionParts
     if (!message) return emptyPermissionParts
 
 
     const parts = data.store.part[message.id] ?? emptyParts
     const parts = data.store.part[message.id] ?? emptyParts

+ 10 - 0
packages/util/src/array.ts

@@ -0,0 +1,10 @@
+export function findLast<T>(
+  items: readonly T[],
+  predicate: (item: T, index: number, items: readonly T[]) => boolean,
+): T | undefined {
+  for (let i = items.length - 1; i >= 0; i -= 1) {
+    const item = items[i]
+    if (predicate(item, i, items)) return item
+  }
+  return undefined
+}