<script lang="ts">
import { appStore } from '$lib/store.svelte.js';
import DiffView from '../chat/DiffView.svelte';
function isDiff(s: string): boolean {
return s.includes('\n--- ') || s.startsWith('--- ') || s.includes('\n+++ ');
}
let expandedIdx = $state<number | null>(null);
let sorted = $derived([...appStore.tools].reverse());
function truncate(s: string, max: number): string {
return s.length > max ? s.slice(0, max) + '...' : s;
}
function toggle(idx: number) {
expandedIdx = expandedIdx === idx ? null : idx;
}
</script>
<div class="panel">
<div class="header">Tools</div>
{#if sorted.length === 0}
<div class="dim">no tool calls</div>
{:else}
<div class="list">
{#each sorted as tool, i (tool.timestamp)}
<button class="entry" onclick={() => toggle(i)}>
<span class="icon">
{#if tool.success === undefined}
<span class="pending">⟳</span>
{:else if tool.success}
<span class="ok">✓</span>
{:else}
<span class="fail">✗</span>
{/if}
</span>
<span class="name">{tool.name}</span>
<span class="args">{truncate(tool.args, 30)}</span>
</button>
{#if expandedIdx === i}
<div class="detail">
<div class="detail-section">
<span class="label">args:</span>
<pre>{tool.args}</pre>
</div>
{#if tool.result}
<div class="detail-section">
<span class="label">result:</span>
{#if isDiff(tool.result)}
<DiffView diff={tool.result} />
{:else}
<pre>{truncate(tool.result, 500)}</pre>
{/if}
</div>
{/if}
</div>
{/if}
{/each}
</div>
{/if}
</div>
<style>
.panel {
font-family: monospace;
font-size: 0.8rem;
}
.header {
color: var(--accent);
padding: 0.25rem 0.5rem;
font-weight: bold;
text-transform: uppercase;
font-size: 0.7rem;
letter-spacing: 0.08em;
}
.list {
overflow-y: auto;
max-height: 300px;
}
.entry {
all: unset;
cursor: pointer;
display: flex;
align-items: center;
gap: 0.3rem;
padding: 0.2rem 0.5rem;
width: 100%;
box-sizing: border-box;
font-size: 0.7rem;
color: var(--fg);
}
.entry:hover {
background: var(--bg-surface);
}
.entry:focus-visible {
outline: 1px solid var(--accent);
outline-offset: -1px;
}
.icon {
flex-shrink: 0;
width: 0.8rem;
text-align: center;
}
.pending {
color: var(--yellow);
}
.ok {
color: var(--green);
}
.fail {
color: var(--red);
}
.name {
color: var(--cyan);
flex-shrink: 0;
}
.args {
color: var(--fg-dim);
font-size: 0.65rem;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.detail {
background: var(--bg);
border-left: 2px solid var(--border);
margin: 0 0.5rem 0.25rem 1.2rem;
padding: 0.3rem;
font-size: 0.65rem;
}
.detail-section {
margin-bottom: 0.2rem;
}
.label {
color: var(--fg-dim);
}
.detail pre {
margin: 0.1rem 0 0;
color: var(--fg);
white-space: pre-wrap;
word-break: break-all;
font-size: 0.6rem;
}
.dim {
color: var(--fg-dim);
padding: 0.5rem;
font-style: italic;
font-size: 0.7rem;
}
</style>