Optimize task tool summary recompute on version changes
This commit is contained in:
@@ -491,10 +491,15 @@ export default function ToolCall(props: ToolCallProps) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const messageVersionAccessor = createMemo(() => props.messageVersion)
|
||||||
|
const partVersionAccessor = createMemo(() => props.partVersion)
|
||||||
|
|
||||||
const rendererContext: ToolRendererContext = {
|
const rendererContext: ToolRendererContext = {
|
||||||
toolCall: toolCallMemo,
|
toolCall: toolCallMemo,
|
||||||
toolState,
|
toolState,
|
||||||
toolName,
|
toolName,
|
||||||
|
messageVersion: messageVersionAccessor,
|
||||||
|
partVersion: partVersionAccessor,
|
||||||
renderMarkdown: renderMarkdownContent,
|
renderMarkdown: renderMarkdownContent,
|
||||||
renderDiff: renderDiffContent,
|
renderDiff: renderDiffContent,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { For } from "solid-js"
|
import { For, createMemo } from "solid-js"
|
||||||
import type { ToolState } from "@opencode-ai/sdk"
|
|
||||||
import type { ToolRenderer } from "../types"
|
import type { ToolRenderer } from "../types"
|
||||||
import { getRelativePath, getToolIcon, getToolName, readToolStatePayload } from "../utils"
|
import { getRelativePath, getToolIcon, getToolName, readToolStatePayload } from "../utils"
|
||||||
|
|
||||||
@@ -9,39 +8,6 @@ interface TaskSummaryItem {
|
|||||||
input: Record<string, any>
|
input: Record<string, any>
|
||||||
}
|
}
|
||||||
|
|
||||||
const taskSummaryCache = new Map<string, { signature: string; items: TaskSummaryItem[] }>()
|
|
||||||
|
|
||||||
function normalizeTaskSummary(state?: ToolState, toolCallId?: string): TaskSummaryItem[] {
|
|
||||||
if (!state) return []
|
|
||||||
const { metadata } = readToolStatePayload(state)
|
|
||||||
const rawSummary = Array.isArray((metadata as any).summary) ? ((metadata as any).summary as any[]) : []
|
|
||||||
if (rawSummary.length === 0) {
|
|
||||||
if (toolCallId) taskSummaryCache.delete(toolCallId)
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
const signature = JSON.stringify(rawSummary)
|
|
||||||
if (toolCallId) {
|
|
||||||
const cached = taskSummaryCache.get(toolCallId)
|
|
||||||
if (cached && cached.signature === signature) {
|
|
||||||
return cached.items
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const normalized: TaskSummaryItem[] = rawSummary.map((entry, index) => {
|
|
||||||
const tool = typeof entry?.tool === "string" ? (entry.tool as string) : "unknown"
|
|
||||||
const input = typeof (entry as any)?.state?.input === "object" && entry.state?.input ? entry.state.input : {}
|
|
||||||
const id = typeof entry?.id === "string" && entry.id.length > 0 ? entry.id : `${tool}-${index}`
|
|
||||||
return { id, tool, input }
|
|
||||||
})
|
|
||||||
|
|
||||||
if (toolCallId) {
|
|
||||||
taskSummaryCache.set(toolCallId, { signature, items: normalized })
|
|
||||||
}
|
|
||||||
|
|
||||||
return normalized
|
|
||||||
}
|
|
||||||
|
|
||||||
function describeTaskItem(item: TaskSummaryItem): string {
|
function describeTaskItem(item: TaskSummaryItem): string {
|
||||||
const input = item.input || {}
|
const input = item.input || {}
|
||||||
switch (item.tool) {
|
switch (item.tool) {
|
||||||
@@ -74,17 +40,32 @@ export const taskRenderer: ToolRenderer = {
|
|||||||
}
|
}
|
||||||
return base
|
return base
|
||||||
},
|
},
|
||||||
renderBody({ toolState, toolCall }) {
|
renderBody({ toolState, toolCall, messageVersion, partVersion }) {
|
||||||
const state = toolState()
|
const items = createMemo(() => {
|
||||||
if (!state) return null
|
// Track the reactive change points so we only recompute when the part/message changes
|
||||||
|
messageVersion?.()
|
||||||
|
partVersion?.()
|
||||||
|
|
||||||
const items = normalizeTaskSummary(state, toolCall().id || "__unknown__")
|
const state = toolState()
|
||||||
if (items.length === 0) return null
|
if (!state) return []
|
||||||
|
|
||||||
|
const { metadata } = readToolStatePayload(state)
|
||||||
|
const summary = Array.isArray((metadata as any).summary) ? ((metadata as any).summary as any[]) : []
|
||||||
|
|
||||||
|
return summary.map((entry, index) => {
|
||||||
|
const tool = typeof entry?.tool === "string" ? (entry.tool as string) : "unknown"
|
||||||
|
const input = typeof (entry as any)?.state?.input === "object" && entry.state?.input ? entry.state.input : {}
|
||||||
|
const id = typeof entry?.id === "string" && entry.id.length > 0 ? entry.id : `${tool}-${index}`
|
||||||
|
return { id, tool, input }
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
if (items().length === 0) return null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="message-text tool-call-markdown tool-call-task-container">
|
<div class="message-text tool-call-markdown tool-call-task-container">
|
||||||
<div class="tool-call-task-summary">
|
<div class="tool-call-task-summary">
|
||||||
<For each={items}>
|
<For each={items()}>
|
||||||
{(item) => {
|
{(item) => {
|
||||||
const icon = getToolIcon(item.tool)
|
const icon = getToolIcon(item.tool)
|
||||||
const description = describeTaskItem(item)
|
const description = describeTaskItem(item)
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ export interface ToolRendererContext {
|
|||||||
toolCall: Accessor<ToolCallPart>
|
toolCall: Accessor<ToolCallPart>
|
||||||
toolState: Accessor<ToolState | undefined>
|
toolState: Accessor<ToolState | undefined>
|
||||||
toolName: Accessor<string>
|
toolName: Accessor<string>
|
||||||
|
messageVersion?: Accessor<number | undefined>
|
||||||
|
partVersion?: Accessor<number | undefined>
|
||||||
renderMarkdown(options: MarkdownRenderOptions): JSXElement | null
|
renderMarkdown(options: MarkdownRenderOptions): JSXElement | null
|
||||||
renderDiff(payload: DiffPayload, options?: DiffRenderOptions): JSXElement | null
|
renderDiff(payload: DiffPayload, options?: DiffRenderOptions): JSXElement | null
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user