@mariozechner/pi-coding-agent 0.9.4 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/README.md +88 -14
- package/dist/export-html.d.ts.map +1 -1
- package/dist/export-html.js +213 -28
- package/dist/export-html.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +132 -9
- package/dist/main.js.map +1 -1
- package/dist/tools/edit.d.ts.map +1 -1
- package/dist/tools/edit.js +6 -3
- package/dist/tools/edit.js.map +1 -1
- package/dist/tui/footer.d.ts +6 -0
- package/dist/tui/footer.d.ts.map +1 -1
- package/dist/tui/footer.js +37 -1
- package/dist/tui/footer.js.map +1 -1
- package/dist/tui/tui-renderer.d.ts.map +1 -1
- package/dist/tui/tui-renderer.js +2 -0
- package/dist/tui/tui-renderer.js.map +1 -1
- package/package.json +4 -4
package/dist/export-html.js
CHANGED
|
@@ -227,11 +227,31 @@ function formatToolExecution(toolName, args, result) {
|
|
|
227
227
|
}
|
|
228
228
|
return { html, bgColor };
|
|
229
229
|
}
|
|
230
|
+
/**
|
|
231
|
+
* Format timestamp for display
|
|
232
|
+
*/
|
|
233
|
+
function formatTimestamp(timestamp) {
|
|
234
|
+
if (!timestamp)
|
|
235
|
+
return "";
|
|
236
|
+
const date = new Date(typeof timestamp === "string" ? timestamp : timestamp);
|
|
237
|
+
return date.toLocaleTimeString(undefined, { hour: "2-digit", minute: "2-digit", second: "2-digit" });
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Format model change event
|
|
241
|
+
*/
|
|
242
|
+
function formatModelChange(event) {
|
|
243
|
+
const timestamp = formatTimestamp(event.timestamp);
|
|
244
|
+
const timestampHtml = timestamp ? `<div class="message-timestamp">${timestamp}</div>` : "";
|
|
245
|
+
const modelInfo = `${event.provider}/${event.modelId}`;
|
|
246
|
+
return `<div class="model-change">${timestampHtml}<div class="model-change-text">Switched to model: <span class="model-name">${escapeHtml(modelInfo)}</span></div></div>`;
|
|
247
|
+
}
|
|
230
248
|
/**
|
|
231
249
|
* Format a message as HTML (matching TUI component styling)
|
|
232
250
|
*/
|
|
233
251
|
function formatMessage(message, toolResultsMap) {
|
|
234
252
|
let html = "";
|
|
253
|
+
const timestamp = message.timestamp;
|
|
254
|
+
const timestampHtml = timestamp ? `<div class="message-timestamp">${formatTimestamp(timestamp)}</div>` : "";
|
|
235
255
|
if (message.role === "user") {
|
|
236
256
|
const userMsg = message;
|
|
237
257
|
let textContent = "";
|
|
@@ -243,11 +263,12 @@ function formatMessage(message, toolResultsMap) {
|
|
|
243
263
|
textContent = textBlocks.map((c) => c.text).join("");
|
|
244
264
|
}
|
|
245
265
|
if (textContent.trim()) {
|
|
246
|
-
html += `<div class="user-message">${escapeHtml(textContent).replace(/\n/g, "<br>")}</div>`;
|
|
266
|
+
html += `<div class="user-message">${timestampHtml}${escapeHtml(textContent).replace(/\n/g, "<br>")}</div>`;
|
|
247
267
|
}
|
|
248
268
|
}
|
|
249
269
|
else if (message.role === "assistant") {
|
|
250
270
|
const assistantMsg = message;
|
|
271
|
+
html += timestampHtml ? `<div class="assistant-message">${timestampHtml}` : "";
|
|
251
272
|
// Render text and thinking content
|
|
252
273
|
for (const content of assistantMsg.content) {
|
|
253
274
|
if (content.type === "text" && content.text.trim()) {
|
|
@@ -276,6 +297,10 @@ function formatMessage(message, toolResultsMap) {
|
|
|
276
297
|
html += `<div class="error-text">Error: ${escapeHtml(errorMsg)}</div>`;
|
|
277
298
|
}
|
|
278
299
|
}
|
|
300
|
+
// Close the assistant message wrapper if we opened one
|
|
301
|
+
if (timestampHtml) {
|
|
302
|
+
html += "</div>";
|
|
303
|
+
}
|
|
279
304
|
}
|
|
280
305
|
return html;
|
|
281
306
|
}
|
|
@@ -296,18 +321,61 @@ export function exportSessionToHtml(sessionManager, state, outputPath) {
|
|
|
296
321
|
let sessionHeader = null;
|
|
297
322
|
const messages = [];
|
|
298
323
|
const toolResultsMap = new Map();
|
|
324
|
+
const sessionEvents = []; // Track all events including model changes
|
|
325
|
+
const modelsUsed = new Set(); // Track unique models used
|
|
326
|
+
// Cumulative token and cost stats
|
|
327
|
+
const tokenStats = {
|
|
328
|
+
input: 0,
|
|
329
|
+
output: 0,
|
|
330
|
+
cacheRead: 0,
|
|
331
|
+
cacheWrite: 0,
|
|
332
|
+
};
|
|
333
|
+
const costStats = {
|
|
334
|
+
input: 0,
|
|
335
|
+
output: 0,
|
|
336
|
+
cacheRead: 0,
|
|
337
|
+
cacheWrite: 0,
|
|
338
|
+
};
|
|
299
339
|
for (const line of lines) {
|
|
300
340
|
try {
|
|
301
341
|
const entry = JSON.parse(line);
|
|
302
342
|
if (entry.type === "session") {
|
|
303
343
|
sessionHeader = entry;
|
|
344
|
+
// Track initial model from session header
|
|
345
|
+
if (entry.modelId) {
|
|
346
|
+
const modelInfo = entry.provider ? `${entry.provider}/${entry.modelId}` : entry.modelId;
|
|
347
|
+
modelsUsed.add(modelInfo);
|
|
348
|
+
}
|
|
304
349
|
}
|
|
305
350
|
else if (entry.type === "message") {
|
|
306
351
|
messages.push(entry.message);
|
|
352
|
+
sessionEvents.push(entry);
|
|
307
353
|
// Build map of tool call ID to result
|
|
308
354
|
if (entry.message.role === "toolResult") {
|
|
309
355
|
toolResultsMap.set(entry.message.toolCallId, entry.message);
|
|
310
356
|
}
|
|
357
|
+
// Accumulate token and cost stats from assistant messages
|
|
358
|
+
if (entry.message.role === "assistant" && entry.message.usage) {
|
|
359
|
+
const usage = entry.message.usage;
|
|
360
|
+
tokenStats.input += usage.input || 0;
|
|
361
|
+
tokenStats.output += usage.output || 0;
|
|
362
|
+
tokenStats.cacheRead += usage.cacheRead || 0;
|
|
363
|
+
tokenStats.cacheWrite += usage.cacheWrite || 0;
|
|
364
|
+
if (usage.cost) {
|
|
365
|
+
costStats.input += usage.cost.input || 0;
|
|
366
|
+
costStats.output += usage.cost.output || 0;
|
|
367
|
+
costStats.cacheRead += usage.cost.cacheRead || 0;
|
|
368
|
+
costStats.cacheWrite += usage.cost.cacheWrite || 0;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
else if (entry.type === "model_change") {
|
|
373
|
+
sessionEvents.push(entry);
|
|
374
|
+
// Track model from model change event
|
|
375
|
+
if (entry.modelId) {
|
|
376
|
+
const modelInfo = entry.provider ? `${entry.provider}/${entry.modelId}` : entry.modelId;
|
|
377
|
+
modelsUsed.add(modelInfo);
|
|
378
|
+
}
|
|
311
379
|
}
|
|
312
380
|
}
|
|
313
381
|
catch {
|
|
@@ -327,12 +395,33 @@ export function exportSessionToHtml(sessionManager, state, outputPath) {
|
|
|
327
395
|
toolCallsCount += assistantMsg.content.filter((c) => c.type === "toolCall").length;
|
|
328
396
|
}
|
|
329
397
|
}
|
|
330
|
-
//
|
|
398
|
+
// Get last assistant message for context percentage calculation (skip aborted messages)
|
|
399
|
+
const lastAssistantMessage = messages
|
|
400
|
+
.slice()
|
|
401
|
+
.reverse()
|
|
402
|
+
.find((m) => m.role === "assistant" && m.stopReason !== "aborted");
|
|
403
|
+
// Calculate context percentage from last message (input + output + cacheRead + cacheWrite)
|
|
404
|
+
const contextTokens = lastAssistantMessage
|
|
405
|
+
? lastAssistantMessage.usage.input +
|
|
406
|
+
lastAssistantMessage.usage.output +
|
|
407
|
+
lastAssistantMessage.usage.cacheRead +
|
|
408
|
+
lastAssistantMessage.usage.cacheWrite
|
|
409
|
+
: 0;
|
|
410
|
+
// Get the model info from the last assistant message
|
|
411
|
+
const lastModel = lastAssistantMessage?.model || state.model?.id || "unknown";
|
|
412
|
+
const lastProvider = lastAssistantMessage?.provider || "";
|
|
413
|
+
const lastModelInfo = lastProvider ? `${lastProvider}/${lastModel}` : lastModel;
|
|
414
|
+
const contextWindow = state.model?.contextWindow || 0;
|
|
415
|
+
const contextPercent = contextWindow > 0 ? ((contextTokens / contextWindow) * 100).toFixed(1) : "0.0";
|
|
416
|
+
// Generate messages HTML (including model changes in chronological order)
|
|
331
417
|
let messagesHtml = "";
|
|
332
|
-
for (const
|
|
333
|
-
if (message.role !== "toolResult") {
|
|
418
|
+
for (const event of sessionEvents) {
|
|
419
|
+
if (event.type === "message" && event.message.role !== "toolResult") {
|
|
334
420
|
// Skip toolResult messages as they're rendered with their tool calls
|
|
335
|
-
messagesHtml += formatMessage(message, toolResultsMap);
|
|
421
|
+
messagesHtml += formatMessage(event.message, toolResultsMap);
|
|
422
|
+
}
|
|
423
|
+
else if (event.type === "model_change") {
|
|
424
|
+
messagesHtml += formatModelChange(event);
|
|
336
425
|
}
|
|
337
426
|
}
|
|
338
427
|
// Generate HTML (matching TUI aesthetic)
|
|
@@ -350,8 +439,8 @@ export function exportSessionToHtml(sessionManager, state, outputPath) {
|
|
|
350
439
|
}
|
|
351
440
|
|
|
352
441
|
body {
|
|
353
|
-
font-family:
|
|
354
|
-
font-size:
|
|
442
|
+
font-family: ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, 'DejaVu Sans Mono', monospace;
|
|
443
|
+
font-size: 12px;
|
|
355
444
|
line-height: 1.6;
|
|
356
445
|
color: ${COLORS.text};
|
|
357
446
|
background: ${COLORS.bodyBg};
|
|
@@ -371,7 +460,7 @@ export function exportSessionToHtml(sessionManager, state, outputPath) {
|
|
|
371
460
|
}
|
|
372
461
|
|
|
373
462
|
.header h1 {
|
|
374
|
-
font-size:
|
|
463
|
+
font-size: 14px;
|
|
375
464
|
font-weight: bold;
|
|
376
465
|
margin-bottom: 12px;
|
|
377
466
|
color: ${COLORS.cyan};
|
|
@@ -380,8 +469,8 @@ export function exportSessionToHtml(sessionManager, state, outputPath) {
|
|
|
380
469
|
.header-info {
|
|
381
470
|
display: flex;
|
|
382
471
|
flex-direction: column;
|
|
383
|
-
gap:
|
|
384
|
-
font-size:
|
|
472
|
+
gap: 3px;
|
|
473
|
+
font-size: 11px;
|
|
385
474
|
}
|
|
386
475
|
|
|
387
476
|
.info-item {
|
|
@@ -393,7 +482,7 @@ export function exportSessionToHtml(sessionManager, state, outputPath) {
|
|
|
393
482
|
.info-label {
|
|
394
483
|
font-weight: 600;
|
|
395
484
|
margin-right: 8px;
|
|
396
|
-
min-width:
|
|
485
|
+
min-width: 100px;
|
|
397
486
|
}
|
|
398
487
|
|
|
399
488
|
.info-value {
|
|
@@ -401,12 +490,24 @@ export function exportSessionToHtml(sessionManager, state, outputPath) {
|
|
|
401
490
|
flex: 1;
|
|
402
491
|
}
|
|
403
492
|
|
|
493
|
+
.info-value.cost {
|
|
494
|
+
font-family: 'SF Mono', monospace;
|
|
495
|
+
}
|
|
496
|
+
|
|
404
497
|
.messages {
|
|
405
498
|
display: flex;
|
|
406
499
|
flex-direction: column;
|
|
407
500
|
gap: 16px;
|
|
408
501
|
}
|
|
409
502
|
|
|
503
|
+
/* Message timestamp */
|
|
504
|
+
.message-timestamp {
|
|
505
|
+
font-size: 10px;
|
|
506
|
+
color: ${COLORS.textDim};
|
|
507
|
+
margin-bottom: 4px;
|
|
508
|
+
opacity: 0.8;
|
|
509
|
+
}
|
|
510
|
+
|
|
410
511
|
/* User message - matching TUI UserMessageComponent */
|
|
411
512
|
.user-message {
|
|
412
513
|
background: ${COLORS.userMessageBg};
|
|
@@ -414,6 +515,13 @@ export function exportSessionToHtml(sessionManager, state, outputPath) {
|
|
|
414
515
|
border-radius: 4px;
|
|
415
516
|
white-space: pre-wrap;
|
|
416
517
|
word-wrap: break-word;
|
|
518
|
+
overflow-wrap: break-word;
|
|
519
|
+
word-break: break-word;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
/* Assistant message wrapper */
|
|
523
|
+
.assistant-message {
|
|
524
|
+
padding: 0;
|
|
417
525
|
}
|
|
418
526
|
|
|
419
527
|
/* Assistant text - matching TUI AssistantMessageComponent */
|
|
@@ -421,6 +529,8 @@ export function exportSessionToHtml(sessionManager, state, outputPath) {
|
|
|
421
529
|
padding: 12px 16px;
|
|
422
530
|
white-space: pre-wrap;
|
|
423
531
|
word-wrap: break-word;
|
|
532
|
+
overflow-wrap: break-word;
|
|
533
|
+
word-break: break-word;
|
|
424
534
|
}
|
|
425
535
|
|
|
426
536
|
/* Thinking text - gray italic */
|
|
@@ -430,6 +540,25 @@ export function exportSessionToHtml(sessionManager, state, outputPath) {
|
|
|
430
540
|
font-style: italic;
|
|
431
541
|
white-space: pre-wrap;
|
|
432
542
|
word-wrap: break-word;
|
|
543
|
+
overflow-wrap: break-word;
|
|
544
|
+
word-break: break-word;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
/* Model change */
|
|
548
|
+
.model-change {
|
|
549
|
+
padding: 8px 16px;
|
|
550
|
+
background: rgb(40, 40, 50);
|
|
551
|
+
border-radius: 4px;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
.model-change-text {
|
|
555
|
+
color: ${COLORS.textDim};
|
|
556
|
+
font-size: 11px;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
.model-name {
|
|
560
|
+
color: ${COLORS.cyan};
|
|
561
|
+
font-weight: bold;
|
|
433
562
|
}
|
|
434
563
|
|
|
435
564
|
/* Tool execution - matching TUI ToolExecutionComponent */
|
|
@@ -449,6 +578,7 @@ export function exportSessionToHtml(sessionManager, state, outputPath) {
|
|
|
449
578
|
|
|
450
579
|
.tool-path {
|
|
451
580
|
color: ${COLORS.cyan};
|
|
581
|
+
word-break: break-all;
|
|
452
582
|
}
|
|
453
583
|
|
|
454
584
|
.line-count {
|
|
@@ -457,13 +587,21 @@ export function exportSessionToHtml(sessionManager, state, outputPath) {
|
|
|
457
587
|
|
|
458
588
|
.tool-command {
|
|
459
589
|
font-weight: bold;
|
|
590
|
+
white-space: pre-wrap;
|
|
591
|
+
word-wrap: break-word;
|
|
592
|
+
overflow-wrap: break-word;
|
|
593
|
+
word-break: break-word;
|
|
460
594
|
}
|
|
461
595
|
|
|
462
596
|
.tool-output {
|
|
463
597
|
margin-top: 12px;
|
|
464
598
|
color: ${COLORS.textDim};
|
|
465
599
|
white-space: pre-wrap;
|
|
600
|
+
word-wrap: break-word;
|
|
601
|
+
overflow-wrap: break-word;
|
|
602
|
+
word-break: break-word;
|
|
466
603
|
font-family: inherit;
|
|
604
|
+
overflow-x: auto;
|
|
467
605
|
}
|
|
468
606
|
|
|
469
607
|
.tool-output > div {
|
|
@@ -474,6 +612,9 @@ export function exportSessionToHtml(sessionManager, state, outputPath) {
|
|
|
474
612
|
margin: 0;
|
|
475
613
|
font-family: inherit;
|
|
476
614
|
color: inherit;
|
|
615
|
+
white-space: pre-wrap;
|
|
616
|
+
word-wrap: break-word;
|
|
617
|
+
overflow-wrap: break-word;
|
|
477
618
|
}
|
|
478
619
|
|
|
479
620
|
/* Expandable tool output */
|
|
@@ -521,7 +662,9 @@ export function exportSessionToHtml(sessionManager, state, outputPath) {
|
|
|
521
662
|
color: ${COLORS.textDim};
|
|
522
663
|
white-space: pre-wrap;
|
|
523
664
|
word-wrap: break-word;
|
|
524
|
-
|
|
665
|
+
overflow-wrap: break-word;
|
|
666
|
+
word-break: break-word;
|
|
667
|
+
font-size: 11px;
|
|
525
668
|
}
|
|
526
669
|
|
|
527
670
|
.tools-list {
|
|
@@ -539,7 +682,7 @@ export function exportSessionToHtml(sessionManager, state, outputPath) {
|
|
|
539
682
|
|
|
540
683
|
.tools-content {
|
|
541
684
|
color: ${COLORS.textDim};
|
|
542
|
-
font-size:
|
|
685
|
+
font-size: 11px;
|
|
543
686
|
}
|
|
544
687
|
|
|
545
688
|
.tool-item {
|
|
@@ -554,25 +697,31 @@ export function exportSessionToHtml(sessionManager, state, outputPath) {
|
|
|
554
697
|
/* Diff styling */
|
|
555
698
|
.tool-diff {
|
|
556
699
|
margin-top: 12px;
|
|
557
|
-
font-size:
|
|
558
|
-
font-family:
|
|
700
|
+
font-size: 11px;
|
|
701
|
+
font-family: ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, 'DejaVu Sans Mono', monospace;
|
|
559
702
|
overflow-x: auto;
|
|
560
703
|
max-width: 100%;
|
|
561
704
|
}
|
|
562
705
|
|
|
563
706
|
.diff-line-old {
|
|
564
707
|
color: ${COLORS.red};
|
|
565
|
-
white-space: pre;
|
|
708
|
+
white-space: pre-wrap;
|
|
709
|
+
word-wrap: break-word;
|
|
710
|
+
overflow-wrap: break-word;
|
|
566
711
|
}
|
|
567
712
|
|
|
568
713
|
.diff-line-new {
|
|
569
714
|
color: ${COLORS.green};
|
|
570
|
-
white-space: pre;
|
|
715
|
+
white-space: pre-wrap;
|
|
716
|
+
word-wrap: break-word;
|
|
717
|
+
overflow-wrap: break-word;
|
|
571
718
|
}
|
|
572
719
|
|
|
573
720
|
.diff-line-context {
|
|
574
721
|
color: ${COLORS.textDim};
|
|
575
|
-
white-space: pre;
|
|
722
|
+
white-space: pre-wrap;
|
|
723
|
+
word-wrap: break-word;
|
|
724
|
+
overflow-wrap: break-word;
|
|
576
725
|
}
|
|
577
726
|
|
|
578
727
|
/* Error text */
|
|
@@ -586,7 +735,7 @@ export function exportSessionToHtml(sessionManager, state, outputPath) {
|
|
|
586
735
|
padding: 20px;
|
|
587
736
|
text-align: center;
|
|
588
737
|
color: ${COLORS.textDim};
|
|
589
|
-
font-size:
|
|
738
|
+
font-size: 10px;
|
|
590
739
|
}
|
|
591
740
|
|
|
592
741
|
@media print {
|
|
@@ -614,8 +763,10 @@ export function exportSessionToHtml(sessionManager, state, outputPath) {
|
|
|
614
763
|
<span class="info-value">${sessionHeader?.timestamp ? new Date(sessionHeader.timestamp).toLocaleString() : timestamp}</span>
|
|
615
764
|
</div>
|
|
616
765
|
<div class="info-item">
|
|
617
|
-
<span class="info-label">
|
|
618
|
-
<span class="info-value">${
|
|
766
|
+
<span class="info-label">Models:</span>
|
|
767
|
+
<span class="info-value">${Array.from(modelsUsed)
|
|
768
|
+
.map((m) => escapeHtml(m))
|
|
769
|
+
.join(", ") || escapeHtml(sessionHeader?.model || state.model.id)}</span>
|
|
619
770
|
</div>
|
|
620
771
|
</div>
|
|
621
772
|
</div>
|
|
@@ -635,21 +786,55 @@ export function exportSessionToHtml(sessionManager, state, outputPath) {
|
|
|
635
786
|
<span class="info-label">Tool Calls:</span>
|
|
636
787
|
<span class="info-value">${toolCallsCount}</span>
|
|
637
788
|
</div>
|
|
789
|
+
</div>
|
|
790
|
+
</div>
|
|
791
|
+
|
|
792
|
+
<div class="header">
|
|
793
|
+
<h1>Tokens & Cost</h1>
|
|
794
|
+
<div class="header-info">
|
|
795
|
+
<div class="info-item">
|
|
796
|
+
<span class="info-label">Input:</span>
|
|
797
|
+
<span class="info-value">${tokenStats.input.toLocaleString()} tokens</span>
|
|
798
|
+
</div>
|
|
799
|
+
<div class="info-item">
|
|
800
|
+
<span class="info-label">Output:</span>
|
|
801
|
+
<span class="info-value">${tokenStats.output.toLocaleString()} tokens</span>
|
|
802
|
+
</div>
|
|
803
|
+
<div class="info-item">
|
|
804
|
+
<span class="info-label">Cache Read:</span>
|
|
805
|
+
<span class="info-value">${tokenStats.cacheRead.toLocaleString()} tokens</span>
|
|
806
|
+
</div>
|
|
638
807
|
<div class="info-item">
|
|
639
|
-
<span class="info-label">
|
|
640
|
-
<span class="info-value">${
|
|
808
|
+
<span class="info-label">Cache Write:</span>
|
|
809
|
+
<span class="info-value">${tokenStats.cacheWrite.toLocaleString()} tokens</span>
|
|
641
810
|
</div>
|
|
642
811
|
<div class="info-item">
|
|
643
812
|
<span class="info-label">Total:</span>
|
|
644
|
-
<span class="info-value">${
|
|
813
|
+
<span class="info-value">${(tokenStats.input + tokenStats.output + tokenStats.cacheRead + tokenStats.cacheWrite).toLocaleString()} tokens</span>
|
|
814
|
+
</div>
|
|
815
|
+
<div class="info-item">
|
|
816
|
+
<span class="info-label">Input Cost:</span>
|
|
817
|
+
<span class="info-value cost">$${costStats.input.toFixed(4)}</span>
|
|
818
|
+
</div>
|
|
819
|
+
<div class="info-item">
|
|
820
|
+
<span class="info-label">Output Cost:</span>
|
|
821
|
+
<span class="info-value cost">$${costStats.output.toFixed(4)}</span>
|
|
822
|
+
</div>
|
|
823
|
+
<div class="info-item">
|
|
824
|
+
<span class="info-label">Cache Read Cost:</span>
|
|
825
|
+
<span class="info-value cost">$${costStats.cacheRead.toFixed(4)}</span>
|
|
826
|
+
</div>
|
|
827
|
+
<div class="info-item">
|
|
828
|
+
<span class="info-label">Cache Write Cost:</span>
|
|
829
|
+
<span class="info-value cost">$${costStats.cacheWrite.toFixed(4)}</span>
|
|
645
830
|
</div>
|
|
646
831
|
<div class="info-item">
|
|
647
|
-
<span class="info-label">
|
|
648
|
-
<span class="info-value"
|
|
832
|
+
<span class="info-label">Total Cost:</span>
|
|
833
|
+
<span class="info-value cost"><strong>$${(costStats.input + costStats.output + costStats.cacheRead + costStats.cacheWrite).toFixed(4)}</strong></span>
|
|
649
834
|
</div>
|
|
650
835
|
<div class="info-item">
|
|
651
|
-
<span class="info-label">
|
|
652
|
-
<span class="info-value">${
|
|
836
|
+
<span class="info-label">Context Usage:</span>
|
|
837
|
+
<span class="info-value">${contextTokens.toLocaleString()} / ${contextWindow.toLocaleString()} tokens (${contextPercent}%) - ${escapeHtml(lastModelInfo)}</span>
|
|
653
838
|
</div>
|
|
654
839
|
</div>
|
|
655
840
|
</div>
|