diff --git a/packages/ui/src/components/message-part.css b/packages/ui/src/components/message-part.css index 5d2703960..ffeb4cb28 100644 --- a/packages/ui/src/components/message-part.css +++ b/packages/ui/src/components/message-part.css @@ -287,6 +287,44 @@ } } +[data-component="task-tools"] { + padding: 8px 12px; + display: flex; + flex-direction: column; + gap: 6px; + + [data-slot="task-tool-item"] { + display: flex; + align-items: center; + gap: 8px; + color: var(--text-weak); + + [data-slot="icon-svg"] { + flex-shrink: 0; + color: var(--icon-weak); + } + } + + [data-slot="task-tool-title"] { + font-family: var(--font-family-sans); + font-size: var(--font-size-small); + font-weight: var(--font-weight-medium); + line-height: var(--line-height-large); + color: var(--text-weak); + } + + [data-slot="task-tool-subtitle"] { + font-family: var(--font-family-sans); + font-size: var(--font-size-small); + font-weight: var(--font-weight-regular); + line-height: var(--line-height-large); + color: var(--text-weaker); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } +} + [data-component="diagnostics"] { display: flex; flex-direction: column; diff --git a/packages/ui/src/components/message-part.tsx b/packages/ui/src/components/message-part.tsx index 01a6fb5f5..f2fa0f320 100644 --- a/packages/ui/src/components/message-part.tsx +++ b/packages/ui/src/components/message-part.tsx @@ -87,6 +87,110 @@ function getDirectory(path: string | undefined) { return relativizeProjectPaths(_getDirectory(path), data.directory) } +export function getSessionToolParts(store: ReturnType["store"], sessionId: string): ToolPart[] { + const messages = store.message[sessionId]?.filter((m) => m.role === "assistant") + if (!messages) return [] + + const parts: ToolPart[] = [] + for (const m of messages) { + const msgParts = store.part[m.id] + if (msgParts) { + for (const p of msgParts) { + if (p && p.type === "tool") parts.push(p as ToolPart) + } + } + } + return parts +} + +import type { IconProps } from "./icon" + +export type ToolInfo = { + icon: IconProps["name"] + title: string + subtitle?: string +} + +export function getToolInfo(tool: string, input: Record = {}): ToolInfo { + switch (tool) { + case "read": + return { + icon: "glasses", + title: "Read", + subtitle: input.filePath ? getFilename(input.filePath) : undefined, + } + case "list": + return { + icon: "bullet-list", + title: "List", + subtitle: input.path ? getFilename(input.path) : undefined, + } + case "glob": + return { + icon: "magnifying-glass-menu", + title: "Glob", + subtitle: input.pattern, + } + case "grep": + return { + icon: "magnifying-glass-menu", + title: "Grep", + subtitle: input.pattern, + } + case "webfetch": + return { + icon: "window-cursor", + title: "Webfetch", + subtitle: input.url, + } + case "task": + return { + icon: "task", + title: `${input.subagent_type || "task"} Agent`, + subtitle: input.description, + } + case "bash": + return { + icon: "console", + title: "Shell", + subtitle: input.description, + } + case "edit": + return { + icon: "code-lines", + title: "Edit", + subtitle: input.filePath ? getFilename(input.filePath) : undefined, + } + case "write": + return { + icon: "code-lines", + title: "Write", + subtitle: input.filePath ? getFilename(input.filePath) : undefined, + } + case "todowrite": + return { + icon: "checklist", + title: "To-dos", + } + case "todoread": + return { + icon: "checklist", + title: "Read to-dos", + } + default: + return { + icon: "mcp", + title: tool, + } + } +} + +function getToolPartInfo(part: ToolPart): ToolInfo { + const state = part.state as any + const input = state.input || {} + return getToolInfo(part.tool, input) +} + export function registerPartComponent(type: string, component: PartComponent) { PART_MAPPING[type] = component } @@ -453,23 +557,37 @@ ToolRegistry.register({ ToolRegistry.register({ name: "task", render(props) { + const summary = () => + (props.metadata.summary ?? []) as { id: string; tool: string; state: { status: string; title?: string } }[] + return ( - {/* */} - {/* {(output) => ( */} - {/*
*/} - {/* */} - {/*
*/} - {/* )} */} - {/*
*/} +
+
+ + {(item) => { + const info = getToolInfo(item.tool) + return ( +
+ + {info.title} + + {item.state.title} + +
+ ) + }} +
+
+
) }, diff --git a/packages/ui/src/styles/utilities.css b/packages/ui/src/styles/utilities.css index 66136d724..8c954f1fe 100644 --- a/packages/ui/src/styles/utilities.css +++ b/packages/ui/src/styles/utilities.css @@ -12,16 +12,16 @@ /* } */ ::-webkit-scrollbar-track { - background: var(--theme-background-panel); + background: transparent; } ::-webkit-scrollbar-thumb { - background-color: var(--theme-border-subtle); + background-color: var(--surface-float-base); border-radius: var(--radius-md); } * { - scrollbar-color: var(--theme-border-subtle) var(--theme-background-panel); + scrollbar-color: var(--surface-float-base) transparent; } }