Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions claude_tap/viewer_assets/detail_trace.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ function renderDetail(e) {
const jsonSection = section(t('section_json'), `<div class="json-view">${renderJSONTree(e)}</div>`, false, JSON.stringify(e, null, 2));
html += actionBarHtml;
if (usage) html += renderTokenUsage(usage);
html += renderCacheDiagnostic(e);
html += toolsSection + systemSection + messagesSection + responseSection;
if (streamEvents.length) html += streamSection;
html += jsonSection;
Expand Down Expand Up @@ -203,6 +204,7 @@ function renderTraceDetail(entry, ctx) {

let html = renderTraceFormatControls();
if (ctx.usage) html += renderTokenUsage(ctx.usage);
html += renderCacheDiagnostic(entry);
html += '<div class="trace-grid">';
html += renderTraceBlock(
t('tok_input'),
Expand Down
354 changes: 354 additions & 0 deletions claude_tap/viewer_assets/diff.js

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions claude_tap/viewer_assets/viewer.css
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,17 @@ body { font-family: var(--sans); background: var(--bg); color: var(--text); heig
.tok-label { color: var(--text-tertiary); font-size: 11px; }
.tok-val { color: var(--text-secondary); font-weight: 600; font-family: var(--mono); font-size: 11px; }

/* ─── Cache diagnostics ─── */
.cache-diag-card {
display: flex; align-items: center; gap: 8px; margin: 6px 0 10px; padding: 7px 11px;
background: var(--amber-bg); border: 1px solid var(--amber);
border-radius: var(--radius-sm); font-size: 12px; line-height: 1.4;
}
.cache-diag-card.low-confidence { border-style: dashed; }
.cache-diag-icon { font-size: 13px; flex-shrink: 0; }
.cache-diag-title { font-weight: 600; color: var(--amber); margin-right: 4px; }
.cache-diag-desc { color: var(--text-secondary); }

/* ─── JSON viewer ─── */
.json-view {
font-family: var(--mono); font-size: 12px; white-space: pre-wrap; word-break: break-word;
Expand Down
72 changes: 64 additions & 8 deletions claude_tap/viewer_i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,14 @@
"diff_sys_new": "Current",
"diff_fallback_warning": "No exact thread match found — showing closest same-model request",
"diff_select_target": "Compare against:",
"diff_select_auto": "Auto"
"diff_select_auto": "Auto",
"cache_diag_title": "Cache Diagnostic:",
"cache_miss_system": "System prompt modified since the previous turn",
"cache_miss_tools": "Tool schemas modified since the previous turn",
"cache_miss_history": "Message history prefix modified or truncated",
"cache_miss_ttl": "Cache expired (idle longer than {minutes} min)",
"cache_miss_initial": "Initial prompt cache creation",
"cache_miss_unknown": "Cache rebuilt from scratch, cause not identifiable from the captured turns"
},
"zh-CN": {
"title": "claude-tap",
Expand Down Expand Up @@ -181,7 +188,14 @@
"diff_sys_new": "本次",
"diff_fallback_warning": "未找到精确线程匹配 — 显示最近的同模型请求",
"diff_select_target": "对比对象:",
"diff_select_auto": "自动"
"diff_select_auto": "自动",
"cache_diag_title": "缓存诊断:",
"cache_miss_system": "System Prompt 相比上一轮发生变动",
"cache_miss_tools": "工具定义相比上一轮发生变更",
"cache_miss_history": "历史消息前缀发生变动或截断",
"cache_miss_ttl": "缓存过期(闲置超过 {minutes} 分钟)",
"cache_miss_initial": "初始 Prompt 缓存创建",
"cache_miss_unknown": "缓存被完全重建,但从已捕获的轮次无法判定原因"
},
"ja": {
"title": "claude-tap",
Expand Down Expand Up @@ -273,7 +287,14 @@
"diff_sys_new": "今回",
"diff_fallback_warning": "正確なスレッド一致が見つかりません — 同モデルの直近のリクエストを表示",
"diff_select_target": "比較対象:",
"diff_select_auto": "自動"
"diff_select_auto": "自動",
"cache_diag_title": "キャッシュ診断:",
"cache_miss_system": "前のターンからシステムプロンプトが変更されました",
"cache_miss_tools": "前のターンからツール定義が変更されました",
"cache_miss_history": "メッセージ履歴のプレフィックスが変更または切り詰められました",
"cache_miss_ttl": "キャッシュ期限切れ({minutes} 分以上アイドル)",
"cache_miss_initial": "初期プロンプトキャッシュ作成",
"cache_miss_unknown": "キャッシュが再構築されましたが、記録されたターンから原因を特定できません"
},
"ko": {
"title": "claude-tap",
Expand Down Expand Up @@ -365,7 +386,14 @@
"diff_sys_new": "현재",
"diff_fallback_warning": "정확한 스레드 일치를 찾을 수 없습니다 — 가장 가까운 동일 모델 요청을 표시",
"diff_select_target": "비교 대상:",
"diff_select_auto": "자동"
"diff_select_auto": "자동",
"cache_diag_title": "캐시 진단:",
"cache_miss_system": "이전 턴 이후 시스템 프롬프트가 변경되었습니다",
"cache_miss_tools": "이전 턴 이후 도구 정의가 변경되었습니다",
"cache_miss_history": "메시지 기록 접두사가 수정되거나 잘렸습니다",
"cache_miss_ttl": "캐시 만료됨 ({minutes}분 이상 유휴)",
"cache_miss_initial": "초기 프롬프트 캐시 생성",
"cache_miss_unknown": "캐시가 재생성되었으나 기록된 턴에서 원인을 확인할 수 없습니다"
},
"fr": {
"title": "claude-tap",
Expand Down Expand Up @@ -457,7 +485,14 @@
"diff_sys_new": "Actuel",
"diff_fallback_warning": "Aucune correspondance de fil exacte trouvée — affichage de la requête du même modèle la plus proche",
"diff_select_target": "Comparer avec :",
"diff_select_auto": "Auto"
"diff_select_auto": "Auto",
"cache_diag_title": "Diagnostic du cache :",
"cache_miss_system": "Prompt système modifié depuis le tour précédent",
"cache_miss_tools": "Schémas d'outils modifiés depuis le tour précédent",
"cache_miss_history": "Préfixe de l'historique modifié ou tronqué",
"cache_miss_ttl": "Cache expiré (inactif plus de {minutes} min)",
"cache_miss_initial": "Création initiale du cache de prompt",
"cache_miss_unknown": "Cache reconstruit, cause non identifiable à partir des tours capturés"
},
"ar": {
"title": "claude-tap",
Expand Down Expand Up @@ -549,7 +584,14 @@
"diff_sys_new": "الحالي",
"diff_fallback_warning": "لم يتم العثور على تطابق دقيق للخيط — عرض أقرب طلب لنفس النموذج",
"diff_select_target": "مقارنة مع:",
"diff_select_auto": "تلقائي"
"diff_select_auto": "تلقائي",
"cache_diag_title": "تشخيص الذاكرة المؤقتة:",
"cache_miss_system": "تم تعديل مطالبة النظام منذ الجولة السابقة",
"cache_miss_tools": "تم تعديل مخططات الأدوات منذ الجولة السابقة",
"cache_miss_history": "تم تعديل أو اقتطاع بادئة سجل الرسائل",
"cache_miss_ttl": "انتهت صلاحية الذاكرة المؤقتة (خمول أكثر من {minutes} دقيقة)",
"cache_miss_initial": "إنشاء ذاكرة التخزين المؤقت للمطالبة الأولية",
"cache_miss_unknown": "تمت إعادة بناء الذاكرة المؤقتة، ولا يمكن تحديد السبب من الجولات المسجلة"
},
"de": {
"title": "claude-tap",
Expand Down Expand Up @@ -641,7 +683,14 @@
"diff_sys_new": "Aktuelle",
"diff_fallback_warning": "Keine exakte Thread-Übereinstimmung gefunden — zeige nächste Anfrage desselben Modells",
"diff_select_target": "Vergleichen mit:",
"diff_select_auto": "Auto"
"diff_select_auto": "Auto",
"cache_diag_title": "Cache-Diagnose:",
"cache_miss_system": "System-Prompt seit der vorherigen Runde geändert",
"cache_miss_tools": "Tool-Schemas seit der vorherigen Runde geändert",
"cache_miss_history": "Präfix des Nachrichtenverlaufs geändert oder gekürzt",
"cache_miss_ttl": "Cache abgelaufen (länger als {minutes} Min. inaktiv)",
"cache_miss_initial": "Erste Prompt-Cache-Erstellung",
"cache_miss_unknown": "Cache neu aufgebaut, Ursache aus den erfassten Runden nicht bestimmbar"
},
"ru": {
"title": "claude-tap",
Expand Down Expand Up @@ -733,6 +782,13 @@
"diff_sys_new": "Текущий",
"diff_fallback_warning": "Точное совпадение потока не найдено — показан ближайший запрос той же модели",
"diff_select_target": "Сравнить с:",
"diff_select_auto": "Авто"
"diff_select_auto": "Авто",
"cache_diag_title": "Диагностика кэша:",
"cache_miss_system": "Системный промпт изменен с предыдущего шага",
"cache_miss_tools": "Схемы инструментов изменены с предыдущего шага",
"cache_miss_history": "Префикс истории сообщений изменен или усечен",
"cache_miss_ttl": "Кэш истек (простой более {minutes} мин)",
"cache_miss_initial": "Начальное создание кэша промпта",
"cache_miss_unknown": "Кэш пересоздан, причину невозможно определить по записанным шагам"
}
}
7 changes: 7 additions & 0 deletions scripts/check_coverage.py
Original file line number Diff line number Diff line change
Expand Up @@ -691,6 +691,13 @@ def collect_viewer_js_coverage() -> tuple[float, set[str], int, int]:
visualNavigate(-1);
vsRenderVisible();
if (entries.length > 1) compareSidebarModelOrder(entries[0], entries[1]);
// Cache diagnosis reads the unfiltered history to find the turn
// whose cache a cold write was meant to reuse, so it has to run
// while the full corpus is loaded -- the live-mode block below
// narrows `entries` to a single websocket record.
for (const entry of entries) {
renderCacheDiagnostic(entry);
}
}"""
)
page.evaluate(
Expand Down
Loading
Loading