112 lines
3.6 KiB
TypeScript
112 lines
3.6 KiB
TypeScript
import type { ToolState } from "@opencode-ai/sdk/v2"
|
|
import type { ToolRendererContext, ToolRenderer, ToolCallPart } from "./types"
|
|
import { getDefaultToolAction, getToolName, isToolStateCompleted, isToolStateRunning } from "./utils"
|
|
import { enMessages } from "../../lib/i18n/messages/en"
|
|
import { defaultRenderer } from "./renderers/default"
|
|
import { bashRenderer } from "./renderers/bash"
|
|
import { readRenderer } from "./renderers/read"
|
|
import { writeRenderer } from "./renderers/write"
|
|
import { editRenderer } from "./renderers/edit"
|
|
import { applyPatchRenderer } from "./renderers/apply-patch"
|
|
import { patchRenderer } from "./renderers/patch"
|
|
import { webfetchRenderer } from "./renderers/webfetch"
|
|
import { todoRenderer } from "./renderers/todo"
|
|
import { invalidRenderer } from "./renderers/invalid"
|
|
|
|
const TITLE_RENDERERS: Record<string, ToolRenderer> = {
|
|
bash: bashRenderer,
|
|
read: readRenderer,
|
|
write: writeRenderer,
|
|
edit: editRenderer,
|
|
apply_patch: applyPatchRenderer,
|
|
patch: patchRenderer,
|
|
webfetch: webfetchRenderer,
|
|
todowrite: todoRenderer,
|
|
todoread: todoRenderer,
|
|
invalid: invalidRenderer,
|
|
}
|
|
|
|
interface TitleSnapshot {
|
|
toolName: string
|
|
state?: ToolState
|
|
}
|
|
|
|
function lookupRenderer(toolName: string): ToolRenderer {
|
|
return TITLE_RENDERERS[toolName] ?? defaultRenderer
|
|
}
|
|
|
|
function createStaticToolPart(snapshot: TitleSnapshot): ToolCallPart {
|
|
return {
|
|
id: "",
|
|
type: "tool",
|
|
tool: snapshot.toolName,
|
|
state: snapshot.state,
|
|
} as ToolCallPart
|
|
}
|
|
|
|
function interpolate(template: string, params?: Record<string, unknown>): string {
|
|
if (!params) return template
|
|
return template.replace(/\{(\w+)\}/g, (_match, key: string) => {
|
|
const value = params[key]
|
|
return value === undefined || value === null ? "" : String(value)
|
|
})
|
|
}
|
|
|
|
function createStaticT(): ToolRendererContext["t"] {
|
|
return (key, params) => {
|
|
const template = (enMessages as Record<string, string>)[key] ?? key
|
|
return interpolate(template, params)
|
|
}
|
|
}
|
|
|
|
function createStaticContext(snapshot: TitleSnapshot): ToolRendererContext {
|
|
const toolStateAccessor = () => snapshot.state
|
|
const toolNameAccessor = () => snapshot.toolName
|
|
const toolCallAccessor = () => createStaticToolPart(snapshot)
|
|
const messageVersionAccessor = () => undefined
|
|
const partVersionAccessor = () => undefined
|
|
const t = createStaticT()
|
|
const renderMarkdown: ToolRendererContext["renderMarkdown"] = () => null
|
|
const renderAnsi: ToolRendererContext["renderAnsi"] = () => null
|
|
const renderDiff: ToolRendererContext["renderDiff"] = () => null
|
|
|
|
return {
|
|
toolCall: toolCallAccessor,
|
|
toolState: toolStateAccessor,
|
|
toolName: toolNameAccessor,
|
|
instanceId: "",
|
|
sessionId: "",
|
|
t,
|
|
messageVersion: messageVersionAccessor,
|
|
partVersion: partVersionAccessor,
|
|
renderMarkdown,
|
|
renderAnsi,
|
|
renderDiff,
|
|
renderToolCall: () => null,
|
|
scrollHelpers: undefined,
|
|
}
|
|
}
|
|
|
|
export function resolveTitleForTool(snapshot: TitleSnapshot): string {
|
|
const renderer = lookupRenderer(snapshot.toolName)
|
|
const context = createStaticContext(snapshot)
|
|
const state = snapshot.state
|
|
const defaultAction = renderer.getAction?.(context) ?? getDefaultToolAction(snapshot.toolName)
|
|
|
|
if (!state || state.status === "pending") {
|
|
return defaultAction
|
|
}
|
|
|
|
const stateTitle = typeof (state as { title?: string }).title === "string" ? (state as { title?: string }).title : undefined
|
|
if (stateTitle && stateTitle.length > 0) {
|
|
return stateTitle
|
|
}
|
|
|
|
const customTitle = renderer.getTitle?.(context)
|
|
if (customTitle) {
|
|
return customTitle
|
|
}
|
|
|
|
return getToolName(snapshot.toolName)
|
|
}
|