Implement comprehensive tool call rendering with state persistence

- Implement tool-specific rendering for all 14 tool types (read, edit, write, bash, webfetch, todowrite, task, etc.)
- Each tool shows contextually relevant information (file previews, diffs, command output, todo lists)
- Add metadata-driven content display using preview, diff, output, and todos from tool state
- Implement status-based rendering (pending, running, completed, error) with animations
- Create global state store for expandable items (tool calls and reasoning sections)
- Fix state persistence: expanded tool calls and reasoning sections remain expanded when new messages arrive
- Fix scroll position preservation during live message updates
- Fix reasoning toggle loop by replacing native details element with custom expandable
- Add comprehensive documentation in TOOL_CALL_IMPLEMENTATION.md
- Reduce font sizes for better readability in expanded tool content
- Add proper keying to For loops to prevent component recreation
- Match TUI patterns for tool names, actions, and content formatting
This commit is contained in:
Shantur Rathore
2025-10-23 01:18:25 +01:00
parent fa77b4e82e
commit d7f619486e
15 changed files with 3059 additions and 106 deletions

View File

@@ -1,5 +1,6 @@
import { Show, Match, Switch } from "solid-js"
import ToolCall from "./tool-call"
import { isItemExpanded, toggleItemExpanded } from "../stores/tool-call-state"
interface MessagePartProps {
part: any
@@ -7,6 +8,13 @@ interface MessagePartProps {
export default function MessagePart(props: MessagePartProps) {
const partType = () => props.part?.type || ""
const reasoningId = () => `reasoning-${props.part?.id || ""}`
const isReasoningExpanded = () => isItemExpanded(reasoningId())
function handleReasoningClick(e: Event) {
e.preventDefault()
toggleItemExpanded(reasoningId())
}
return (
<Switch>
@@ -17,7 +25,7 @@ export default function MessagePart(props: MessagePartProps) {
</Match>
<Match when={partType() === "tool"}>
<ToolCall toolCall={props.part} />
<ToolCall toolCall={props.part} toolCallId={props.part?.id} />
</Match>
<Match when={partType() === "error"}>
@@ -26,10 +34,15 @@ export default function MessagePart(props: MessagePartProps) {
<Match when={partType() === "reasoning"}>
<div class="message-reasoning">
<details>
<summary class="text-sm text-gray-500 cursor-pointer">Reasoning</summary>
<div class="message-text mt-2">{props.part.text || ""}</div>
</details>
<div class="reasoning-container">
<div class="reasoning-header" onClick={handleReasoningClick}>
<span class="reasoning-icon">{isReasoningExpanded() ? "▼" : ""}</span>
<span class="reasoning-label">Reasoning</span>
</div>
<Show when={isReasoningExpanded()}>
<div class="message-text mt-2">{props.part.text || ""}</div>
</Show>
</div>
</div>
</Match>
</Switch>