summaryrefslogtreecommitdiffhomepage
path: root/src/features/chat
diff options
context:
space:
mode:
Diffstat (limited to 'src/features/chat')
-rw-r--r--src/features/chat/ui.test.ts28
-rw-r--r--src/features/chat/ui/ChatView.svelte21
2 files changed, 43 insertions, 6 deletions
diff --git a/src/features/chat/ui.test.ts b/src/features/chat/ui.test.ts
index bea5e77..189be2e 100644
--- a/src/features/chat/ui.test.ts
+++ b/src/features/chat/ui.test.ts
@@ -378,6 +378,34 @@ describe("ChatView", () => {
expect(screen.getByText(/1\.2s/)).toBeInTheDocument();
});
+ it("renders a per-step cache hit badge coloured by level", () => {
+ const step = {
+ stepId: "t1#0" as StepId,
+ usage: { inputTokens: 1000, outputTokens: 10, cacheReadTokens: 750 },
+ decodeMs: 100,
+ };
+ const chunks: RenderedChunk[] = [
+ { seq: 1, role: "user", chunk: { type: "text", text: "Hi" }, provisional: false },
+ {
+ seq: 2,
+ role: "assistant",
+ chunk: {
+ type: "tool-call",
+ toolCallId: "tc1",
+ toolName: "t",
+ input: {},
+ stepId: step.stepId,
+ },
+ provisional: false,
+ },
+ ];
+ const turnMetrics: TurnMetricsEntry[] = [{ turnId: "t1", steps: [step], total: null }];
+ render(ChatView, { props: { chunks, turnMetrics } });
+ const badge = screen.getByTestId("step-cache-badge");
+ expect(badge).toHaveTextContent("75%");
+ expect(badge).toHaveClass("badge-success");
+ });
+
it("renders cache hit-rate badges (Last turn + Chat Total) coloured by level", () => {
const chunks: RenderedChunk[] = [
{ seq: 1, role: "user", chunk: { type: "text", text: "Hi" }, provisional: false },
diff --git a/src/features/chat/ui/ChatView.svelte b/src/features/chat/ui/ChatView.svelte
index 182b3d6..8f153bf 100644
--- a/src/features/chat/ui/ChatView.svelte
+++ b/src/features/chat/ui/ChatView.svelte
@@ -248,14 +248,23 @@
{#each keyedRows as { row, key } (key)}
{#if row.kind === "step-metrics"}
{@const sv = viewStepMetrics(row.step, row.index)}
+ {@const stepCache = viewCacheRate(row.step.usage)}
<div class="chat chat-start">
<div class="chat-bubble w-full max-w-5xl bg-transparent p-0">
- <div class="text-xs opacity-70">
- {sv.label} · {sv.tokensLabel}
- {#if sv.tps}
- · {sv.tps}{/if}
- {#if sv.ttft}
- · {sv.ttft} to first token{/if}
+ <div class="flex flex-wrap items-center gap-x-1 text-xs">
+ <span class="opacity-70">
+ {sv.label} · {sv.tokensLabel}
+ {#if sv.tps}
+ · {sv.tps}{/if}
+ {#if sv.ttft}
+ · {sv.ttft} to first token{/if}
+ ·
+ </span>
+ <span class="opacity-70">cache:</span>
+ <span
+ class="badge badge-xs {badgeClass[stepCache.level]}"
+ data-testid="step-cache-badge">{stepCache.pct}%</span
+ >
</div>
</div>
</div>