nandi/oripublic Fork 0
2434cc7fb724f02b34c0189dfd5fb30c1a8a68e3
Commits
Clone
git clone https://git.rickub.com/nandi/ori.git
git clone ssh://git@rickub.com/nandi/ori.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

forked from bots-garden/ori

ToolCallCard.tsx · 102 lines · 2.9 KBTypeScript Blame HistoryRaw
✨ Introduce new feature(s): ACP web client — Go backend (agent, bridge, httpserver, mockagent) + React SPA (Zed-like agent panel), tests, quality gate PASS 2434cc7 k33g yesterday1/**
2 * ToolCallCard shows one tool call the agent is running, in the spirit of
3 * Zed's agent panel: a collapsible card with the tool kind, a live status,
4 * touched locations, and the call's output (text, or a file diff).
5 *
6 * @example
7 * <ToolCallCard call={{ toolCallId: "c1", title: "Reading main.go",
8 * toolKind: "read", status: "in_progress", contents: [], locations: [] }} />
9 */
10
11import type { ToolCall } from "../reducer";
12import type { AcpToolCallContent } from "../protocol";
13import { Markdown } from "./Markdown";
14
15const kindIcons: Record<string, string> = {
16 read: "📖",
17 edit: "✏️",
18 delete: "🗑️",
19 move: "📦",
20 search: "🔍",
21 execute: "⚡",
22 think: "💭",
23 fetch: "🌐",
24 switch_mode: "🔀",
25 other: "🔧",
26};
27
28const statusLabels: Record<string, string> = {
29 pending: "pending",
30 in_progress: "running",
31 completed: "done",
32 failed: "failed",
33};
34
35export function ToolCallCard({ call }: { call: ToolCall }) {
36 return (
37 <details className={`tool tool-${call.status}`}>
38 <summary className="tool-summary">
39 <span className="tool-icon" aria-hidden>
40 {kindIcons[call.toolKind] ?? kindIcons.other}
41 </span>
42 <span className="tool-title">{call.title}</span>
43 <span className={`tool-status tool-status-${call.status}`}>
44 {statusLabels[call.status] ?? call.status}
45 </span>
46 </summary>
47 <div className="tool-body">
48 {call.locations.length > 0 && (
49 <ul className="tool-locations">
50 {call.locations.map((location, index) => (
51 // biome-ignore lint/suspicious/noArrayIndexKey: tool-call locations carry no id and the list is replaced wholesale on every update.
52 <li key={index}>
53 <code>
54 {location.path}
55 {location.line != null ? `:${location.line}` : ""}
56 </code>
57 </li>
58 ))}
59 </ul>
60 )}
61 {call.contents.map((content, index) => (
62 // biome-ignore lint/suspicious/noArrayIndexKey: tool-call contents carry no id and the list is replaced wholesale on every update.
63 <ToolContent key={index} content={content} />
64 ))}
65 </div>
66 </details>
67 );
68}
69
70function ToolContent({ content }: { content: AcpToolCallContent }) {
71 switch (content.type) {
72 case "content":
73 return content.content?.text ? (
74 <Markdown text={content.content.text} />
75 ) : null;
76 case "diff":
77 return (
78 <div className="tool-diff">
79 <code className="tool-diff-path">{content.path}</code>
80 {content.oldText != null && (
81 <pre className="tool-diff-old">
82 {prefixLines(content.oldText, "- ")}
83 </pre>
84 )}
85 <pre className="tool-diff-new">
86 {prefixLines(content.newText ?? "", "+ ")}
87 </pre>
88 </div>
89 );
90 case "terminal":
91 return <p className="tool-terminal">terminal: {content.terminalId}</p>;
92 default:
93 return null;
94 }
95}
96
97function prefixLines(text: string, prefix: string): string {
98 return text
99 .split("\n")
100 .map((line) => prefix + line)
101 .join("\n");
102}