<script lang="ts">
import type { Message } from "../../api/types.js";
import {
parseContent,
enrichSegments,
} from "../../utils/content-parser.js";
import { formatTimestamp } from "../../utils/format.js";
import { copyToClipboard } from "../../utils/clipboard.js";
import AppIcon from "../layout/AppIcon.svelte";
import ToolBlock from "./ToolBlock.svelte";
interface Props {
messages: Message[];
timestamp: string;
highlightQuery?: string;
isCurrentHighlight?: boolean;
}
let {
messages,
timestamp,
highlightQuery = "",
isCurrentHighlight = false,
}: Props = $props();
let copied = $state(false);
let toolSegments = $derived(
messages.flatMap((m) =>
enrichSegments(
parseContent(m.content, m.has_tool_use),
m.tool_calls,
).filter((s) => s.type === "tool"),
),
);
let label = $derived(
toolSegments.length === 1
? "1 tool call"
: `${toolSegments.length} tool calls`,
);
let copyTimer: ReturnType<typeof setTimeout>;
async function handleCopy() {
const combined = messages.map((m) => m.content).join("\n\n");
try {
await copyToClipboard(combined);
clearTimeout(copyTimer);
copied = true;
copyTimer = setTimeout(() => { copied = false; }, 1500);
} catch { /* clipboard unavailable */ }
}
</script>
<div class="tool-group">
<div class="tool-group-header">
<span class="gear-icon">
<AppIcon name="filter" size={12} />
</span>
<span class="group-label">{label}</span>
<button
type="button"
class="copy-btn"
title={copied ? "Copied!" : "Copy tool calls"}
onclick={handleCopy}
>
{#if copied}
<AppIcon name="check" size={14} />
{:else}
<AppIcon name="copy" size={14} />
{/if}
</button>
<span class="group-timestamp">
{formatTimestamp(timestamp)}
</span>
</div>
<div class="tool-group-body">
{#each toolSegments as segment}
<ToolBlock
content={segment.content}
label={segment.label}
toolCall={segment.toolCall}
{highlightQuery}
{isCurrentHighlight}
/>
{/each}
</div>
</div>
<style>
.tool-group {
border-left: 3px solid var(--vscode-editorWarning-foreground);
background: var(--wb-tool-bg);
border-radius: 0 var(--wsb-radius-md) var(--wsb-radius-md) 0;
padding: var(--wb-spacing-8) var(--wb-spacing-12);
}
.tool-group-header {
display: flex;
align-items: center;
gap: var(--wb-spacing-8);
margin-bottom: var(--wb-spacing-6);
}
.gear-icon {
display: flex;
align-items: center;
flex-shrink: 0;
}
.group-label {
font-size: var(--wb-font-size-12);
font-weight: 600;
color: var(--vscode-editorWarning-foreground);
}
.group-timestamp {
font-size: var(--wb-font-size-12);
color: var(--vscode-disabledForeground);
margin-left: auto;
}
.copy-btn {
display: flex;
align-items: center;
justify-content: center;
width: var(--wb-control-size-26);
height: var(--wb-control-size-26);
border: none;
border-radius: var(--wsb-radius-sm, var(--wb-corner-radius-4));
background: transparent;
color: var(--vscode-disabledForeground);
cursor: pointer;
opacity: 0;
transition: opacity 0.15s, background 0.15s, color 0.15s;
flex-shrink: 0;
}
.tool-group:hover .copy-btn,
.copy-btn:focus-visible {
opacity: 1;
}
@media (hover: none) {
.copy-btn {
opacity: 1;
}
}
.copy-btn:hover {
background: var(--vscode-list-hoverBackground);
color: var(--vscode-foreground);
}
.copy-btn:active {
transform: scale(0.92);
}
.tool-group-body {
display: flex;
flex-direction: column;
gap: var(--wb-spacing-2);
}
.tool-group-body :global(.tool-block) {
margin: 0;
border-left: none;
border-radius: 0;
}
</style>