wave-code 0.0.5 → 0.0.6
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/README.md +2 -2
- package/dist/components/ChatInterface.d.ts.map +1 -1
- package/dist/components/ChatInterface.js +4 -24
- package/dist/components/CommandSelector.js +4 -4
- package/dist/components/DiffViewer.d.ts +1 -1
- package/dist/components/DiffViewer.d.ts.map +1 -1
- package/dist/components/DiffViewer.js +15 -15
- package/dist/components/FileSelector.js +2 -2
- package/dist/components/InputBox.d.ts.map +1 -1
- package/dist/components/InputBox.js +21 -50
- package/dist/components/Markdown.d.ts +6 -0
- package/dist/components/Markdown.d.ts.map +1 -0
- package/dist/components/Markdown.js +22 -0
- package/dist/components/MessageItem.d.ts +9 -0
- package/dist/components/MessageItem.d.ts.map +1 -0
- package/dist/components/MessageItem.js +15 -0
- package/dist/components/MessageList.d.ts +1 -1
- package/dist/components/MessageList.d.ts.map +1 -1
- package/dist/components/MessageList.js +33 -33
- package/dist/components/SubagentBlock.d.ts +0 -1
- package/dist/components/SubagentBlock.d.ts.map +1 -1
- package/dist/components/SubagentBlock.js +29 -30
- package/dist/components/ToolResultDisplay.js +5 -5
- package/dist/contexts/useChat.d.ts +2 -2
- package/dist/contexts/useChat.d.ts.map +1 -1
- package/dist/contexts/useChat.js +18 -9
- package/dist/hooks/useInputManager.d.ts +3 -1
- package/dist/hooks/useInputManager.d.ts.map +1 -1
- package/dist/hooks/useInputManager.js +15 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -2
- package/dist/managers/InputManager.d.ts +3 -1
- package/dist/managers/InputManager.d.ts.map +1 -1
- package/dist/managers/InputManager.js +44 -24
- package/dist/print-cli.d.ts +1 -0
- package/dist/print-cli.d.ts.map +1 -1
- package/dist/print-cli.js +88 -23
- package/dist/utils/usageSummary.d.ts +6 -0
- package/dist/utils/usageSummary.d.ts.map +1 -1
- package/dist/utils/usageSummary.js +72 -0
- package/package.json +10 -6
- package/src/components/ChatInterface.tsx +13 -43
- package/src/components/CommandSelector.tsx +5 -5
- package/src/components/DiffViewer.tsx +18 -16
- package/src/components/FileSelector.tsx +2 -2
- package/src/components/InputBox.tsx +22 -74
- package/src/components/Markdown.tsx +29 -0
- package/src/components/MessageItem.tsx +104 -0
- package/src/components/MessageList.tsx +142 -202
- package/src/components/SubagentBlock.tsx +56 -84
- package/src/components/ToolResultDisplay.tsx +5 -5
- package/src/contexts/useChat.tsx +22 -13
- package/src/hooks/useInputManager.ts +21 -3
- package/src/index.ts +12 -2
- package/src/managers/InputManager.ts +55 -25
- package/src/print-cli.ts +103 -21
- package/src/utils/usageSummary.ts +109 -0
|
@@ -11,6 +11,7 @@ export const useInputManager = (
|
|
|
11
11
|
callbacks: Partial<InputManagerCallbacks> = {},
|
|
12
12
|
) => {
|
|
13
13
|
const managerRef = useRef<InputManager | null>(null);
|
|
14
|
+
const [isManagerReady, setIsManagerReady] = useState(false);
|
|
14
15
|
|
|
15
16
|
// React state that mirrors InputManager state
|
|
16
17
|
const [inputText, setInputText] = useState("");
|
|
@@ -65,10 +66,13 @@ export const useInputManager = (
|
|
|
65
66
|
setShowMcpManager(show);
|
|
66
67
|
},
|
|
67
68
|
onImagesStateChange: setAttachedImages,
|
|
69
|
+
onShowBashManager: () => setShowBashManager(true),
|
|
70
|
+
onShowMcpManager: () => setShowMcpManager(true),
|
|
68
71
|
...callbacks,
|
|
69
72
|
});
|
|
70
73
|
|
|
71
74
|
managerRef.current = manager;
|
|
75
|
+
setIsManagerReady(true);
|
|
72
76
|
} else {
|
|
73
77
|
// Update callbacks on existing manager
|
|
74
78
|
managerRef.current.updateCallbacks({
|
|
@@ -93,6 +97,8 @@ export const useInputManager = (
|
|
|
93
97
|
setShowMcpManager(show);
|
|
94
98
|
},
|
|
95
99
|
onImagesStateChange: setAttachedImages,
|
|
100
|
+
onShowBashManager: () => setShowBashManager(true),
|
|
101
|
+
onShowMcpManager: () => setShowMcpManager(true),
|
|
96
102
|
...callbacks,
|
|
97
103
|
});
|
|
98
104
|
}
|
|
@@ -253,9 +259,12 @@ export const useInputManager = (
|
|
|
253
259
|
managerRef.current?.activateMemoryTypeSelector(message);
|
|
254
260
|
}, []);
|
|
255
261
|
|
|
256
|
-
const handleMemoryTypeSelect = useCallback(
|
|
257
|
-
|
|
258
|
-
|
|
262
|
+
const handleMemoryTypeSelect = useCallback(
|
|
263
|
+
async (type: "project" | "user") => {
|
|
264
|
+
await managerRef.current?.handleMemoryTypeSelect(type);
|
|
265
|
+
},
|
|
266
|
+
[],
|
|
267
|
+
);
|
|
259
268
|
|
|
260
269
|
const handleCancelMemoryTypeSelect = useCallback(() => {
|
|
261
270
|
managerRef.current?.handleCancelMemoryTypeSelect();
|
|
@@ -296,6 +305,11 @@ export const useInputManager = (
|
|
|
296
305
|
managerRef.current?.setCursorPosition(position);
|
|
297
306
|
}, []);
|
|
298
307
|
|
|
308
|
+
// Complex handlers that combine multiple operations
|
|
309
|
+
const handleBashHistoryExecuteAndSend = useCallback((command: string) => {
|
|
310
|
+
managerRef.current?.handleBashHistoryExecuteAndSend(command);
|
|
311
|
+
}, []);
|
|
312
|
+
|
|
299
313
|
return {
|
|
300
314
|
// State
|
|
301
315
|
inputText,
|
|
@@ -315,6 +329,7 @@ export const useInputManager = (
|
|
|
315
329
|
showBashManager,
|
|
316
330
|
showMcpManager,
|
|
317
331
|
attachedImages,
|
|
332
|
+
isManagerReady,
|
|
318
333
|
|
|
319
334
|
// Methods
|
|
320
335
|
insertTextAtCursor,
|
|
@@ -409,6 +424,9 @@ export const useInputManager = (
|
|
|
409
424
|
managerRef.current?.clearLongTextMap();
|
|
410
425
|
}, []),
|
|
411
426
|
|
|
427
|
+
// Complex handlers combining multiple operations
|
|
428
|
+
handleBashHistoryExecuteAndSend,
|
|
429
|
+
|
|
412
430
|
// Main input handler
|
|
413
431
|
handleInput: useCallback(
|
|
414
432
|
async (
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import yargs from "yargs";
|
|
2
2
|
import { hideBin } from "yargs/helpers";
|
|
3
3
|
import { startCli } from "./cli.js";
|
|
4
|
-
import { listSessions } from "wave-agent-sdk";
|
|
4
|
+
import { listSessions, getSessionFilePath } from "wave-agent-sdk";
|
|
5
5
|
|
|
6
6
|
// Export main function for external use
|
|
7
7
|
export async function main() {
|
|
@@ -21,6 +21,10 @@ export async function main() {
|
|
|
21
21
|
description: "Print response without interactive mode",
|
|
22
22
|
type: "string",
|
|
23
23
|
})
|
|
24
|
+
.option("show-stats", {
|
|
25
|
+
description: "Show timing and usage statistics in print mode",
|
|
26
|
+
type: "boolean",
|
|
27
|
+
})
|
|
24
28
|
.option("list-sessions", {
|
|
25
29
|
description: "List all available sessions",
|
|
26
30
|
type: "boolean",
|
|
@@ -31,7 +35,10 @@ export async function main() {
|
|
|
31
35
|
.example("$0 --restore session_123", "Restore specific session")
|
|
32
36
|
.example("$0 --continue", "Continue from last session")
|
|
33
37
|
.example("$0 --print 'Hello'", "Send message in print mode")
|
|
34
|
-
.example(
|
|
38
|
+
.example(
|
|
39
|
+
"$0 -p 'Hello' --show-stats",
|
|
40
|
+
"Send message in print mode with statistics",
|
|
41
|
+
)
|
|
35
42
|
.example("$0 --list-sessions", "List all available sessions")
|
|
36
43
|
.help("h")
|
|
37
44
|
.parseAsync();
|
|
@@ -53,9 +60,11 @@ export async function main() {
|
|
|
53
60
|
for (const session of sessions) {
|
|
54
61
|
const startedAt = new Date(session.startedAt).toLocaleString();
|
|
55
62
|
const lastActiveAt = new Date(session.lastActiveAt).toLocaleString();
|
|
63
|
+
const filePath = await getSessionFilePath(session.id, session.workdir);
|
|
56
64
|
|
|
57
65
|
console.log(`ID: ${session.id}`);
|
|
58
66
|
console.log(` Workdir: ${session.workdir}`);
|
|
67
|
+
console.log(` File Path: ${filePath}`);
|
|
59
68
|
console.log(` Started: ${startedAt}`);
|
|
60
69
|
console.log(` Last Active: ${lastActiveAt}`);
|
|
61
70
|
console.log(` Last Message Tokens: ${session.latestTotalTokens}`);
|
|
@@ -76,6 +85,7 @@ export async function main() {
|
|
|
76
85
|
restoreSessionId: argv.restore,
|
|
77
86
|
continueLastSession: argv.continue,
|
|
78
87
|
message: argv.print,
|
|
88
|
+
showStats: argv.showStats,
|
|
79
89
|
});
|
|
80
90
|
}
|
|
81
91
|
|
|
@@ -487,6 +487,16 @@ export class InputManager {
|
|
|
487
487
|
return command; // Return command to execute
|
|
488
488
|
}
|
|
489
489
|
|
|
490
|
+
handleBashHistoryExecuteAndSend(command: string): void {
|
|
491
|
+
const commandToExecute = this.handleBashHistoryExecute(command);
|
|
492
|
+
// Clear input box and execute command, ensure command starts with !
|
|
493
|
+
const bashCommand = commandToExecute.startsWith("!")
|
|
494
|
+
? commandToExecute
|
|
495
|
+
: `!${commandToExecute}`;
|
|
496
|
+
this.clearInput();
|
|
497
|
+
this.callbacks.onSendMessage?.(bashCommand);
|
|
498
|
+
}
|
|
499
|
+
|
|
490
500
|
checkForExclamationDeletion(cursorPosition: number): boolean {
|
|
491
501
|
if (
|
|
492
502
|
this.showBashHistorySelector &&
|
|
@@ -506,13 +516,18 @@ export class InputManager {
|
|
|
506
516
|
this.callbacks.onMemoryTypeSelectorStateChange?.(true, message);
|
|
507
517
|
}
|
|
508
518
|
|
|
509
|
-
handleMemoryTypeSelect(type: "project" | "user"): void {
|
|
510
|
-
|
|
511
|
-
|
|
519
|
+
async handleMemoryTypeSelect(type: "project" | "user"): Promise<void> {
|
|
520
|
+
const currentMessage = this.inputText.trim();
|
|
521
|
+
if (currentMessage.startsWith("#")) {
|
|
522
|
+
await this.callbacks.onSaveMemory?.(currentMessage, type);
|
|
523
|
+
}
|
|
524
|
+
// Close the selector
|
|
512
525
|
this.showMemoryTypeSelector = false;
|
|
513
526
|
this.memoryMessage = "";
|
|
514
|
-
|
|
515
527
|
this.callbacks.onMemoryTypeSelectorStateChange?.(false, "");
|
|
528
|
+
|
|
529
|
+
// Clear input box
|
|
530
|
+
this.clearInput();
|
|
516
531
|
}
|
|
517
532
|
|
|
518
533
|
handleCancelMemoryTypeSelect(): void {
|
|
@@ -631,6 +646,29 @@ export class InputManager {
|
|
|
631
646
|
};
|
|
632
647
|
}
|
|
633
648
|
|
|
649
|
+
// Update search queries for active selectors
|
|
650
|
+
private updateSearchQueriesForActiveSelectors(
|
|
651
|
+
inputText: string,
|
|
652
|
+
cursorPosition: number,
|
|
653
|
+
): void {
|
|
654
|
+
if (this.showFileSelector && this.atPosition >= 0) {
|
|
655
|
+
const queryStart = this.atPosition + 1;
|
|
656
|
+
const queryEnd = cursorPosition;
|
|
657
|
+
const newQuery = inputText.substring(queryStart, queryEnd);
|
|
658
|
+
this.updateFileSearchQuery(newQuery);
|
|
659
|
+
} else if (this.showCommandSelector && this.slashPosition >= 0) {
|
|
660
|
+
const queryStart = this.slashPosition + 1;
|
|
661
|
+
const queryEnd = cursorPosition;
|
|
662
|
+
const newQuery = inputText.substring(queryStart, queryEnd);
|
|
663
|
+
this.updateCommandSearchQuery(newQuery);
|
|
664
|
+
} else if (this.showBashHistorySelector && this.exclamationPosition >= 0) {
|
|
665
|
+
const queryStart = this.exclamationPosition + 1;
|
|
666
|
+
const queryEnd = cursorPosition;
|
|
667
|
+
const newQuery = inputText.substring(queryStart, queryEnd);
|
|
668
|
+
this.updateBashHistorySearchQuery(newQuery);
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
|
|
634
672
|
// Handle special character input that might trigger selectors
|
|
635
673
|
handleSpecialCharInput(char: string): void {
|
|
636
674
|
if (char === "@") {
|
|
@@ -644,25 +682,10 @@ export class InputManager {
|
|
|
644
682
|
// Memory message detection will be handled in submit
|
|
645
683
|
} else {
|
|
646
684
|
// Update search queries for active selectors
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
this.updateFileSearchQuery(newQuery);
|
|
652
|
-
} else if (this.showCommandSelector && this.slashPosition >= 0) {
|
|
653
|
-
const queryStart = this.slashPosition + 1;
|
|
654
|
-
const queryEnd = this.cursorPosition;
|
|
655
|
-
const newQuery = this.inputText.substring(queryStart, queryEnd);
|
|
656
|
-
this.updateCommandSearchQuery(newQuery);
|
|
657
|
-
} else if (
|
|
658
|
-
this.showBashHistorySelector &&
|
|
659
|
-
this.exclamationPosition >= 0
|
|
660
|
-
) {
|
|
661
|
-
const queryStart = this.exclamationPosition + 1;
|
|
662
|
-
const queryEnd = this.cursorPosition;
|
|
663
|
-
const newQuery = this.inputText.substring(queryStart, queryEnd);
|
|
664
|
-
this.updateBashHistorySearchQuery(newQuery);
|
|
665
|
-
}
|
|
685
|
+
this.updateSearchQueriesForActiveSelectors(
|
|
686
|
+
this.inputText,
|
|
687
|
+
this.cursorPosition,
|
|
688
|
+
);
|
|
666
689
|
}
|
|
667
690
|
}
|
|
668
691
|
|
|
@@ -891,13 +914,19 @@ export class InputManager {
|
|
|
891
914
|
this.checkForAtDeletion(newCursorPosition);
|
|
892
915
|
this.checkForSlashDeletion(newCursorPosition);
|
|
893
916
|
this.checkForExclamationDeletion(newCursorPosition);
|
|
917
|
+
|
|
918
|
+
// Update search queries using the same logic as character input
|
|
919
|
+
this.updateSearchQueriesForActiveSelectors(
|
|
920
|
+
newInput,
|
|
921
|
+
newCursorPosition,
|
|
922
|
+
);
|
|
894
923
|
});
|
|
895
924
|
}
|
|
896
925
|
return true;
|
|
897
926
|
}
|
|
898
927
|
|
|
899
|
-
// Arrow keys and
|
|
900
|
-
if (key.upArrow || key.downArrow || key.return) {
|
|
928
|
+
// Arrow keys, Enter and Tab should be handled by selector components
|
|
929
|
+
if (key.upArrow || key.downArrow || key.return || key.tab) {
|
|
901
930
|
// Let selector component handle these keys, but prevent further processing
|
|
902
931
|
// by returning true (indicating we've handled the input)
|
|
903
932
|
return true;
|
|
@@ -909,6 +938,7 @@ export class InputManager {
|
|
|
909
938
|
!("alt" in key && key.alt) &&
|
|
910
939
|
!key.meta &&
|
|
911
940
|
!key.return &&
|
|
941
|
+
!key.tab &&
|
|
912
942
|
!key.escape &&
|
|
913
943
|
!key.leftArrow &&
|
|
914
944
|
!key.rightArrow &&
|
package/src/print-cli.ts
CHANGED
|
@@ -1,15 +1,35 @@
|
|
|
1
1
|
import { Agent, AgentCallbacks } from "wave-agent-sdk";
|
|
2
|
-
import { logger } from "./utils/logger.js";
|
|
3
2
|
import { displayUsageSummary } from "./utils/usageSummary.js";
|
|
4
3
|
|
|
5
4
|
export interface PrintCliOptions {
|
|
6
5
|
restoreSessionId?: string;
|
|
7
6
|
continueLastSession?: boolean;
|
|
8
7
|
message?: string;
|
|
8
|
+
showStats?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function displayTimingInfo(startTime: Date, showStats: boolean): void {
|
|
12
|
+
// Skip timing info in test environment or if stats are disabled
|
|
13
|
+
if (process.env.NODE_ENV === "test" || process.env.VITEST || !showStats) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const endTime = new Date();
|
|
18
|
+
const duration = endTime.getTime() - startTime.getTime();
|
|
19
|
+
|
|
20
|
+
process.stdout.write(`\n\n📅 Start time: ${startTime.toISOString()}\n`);
|
|
21
|
+
process.stdout.write(`📅 End time: ${endTime.toISOString()}\n`);
|
|
22
|
+
process.stdout.write(`⏱️ Duration: ${duration}ms\n`);
|
|
9
23
|
}
|
|
10
24
|
|
|
11
25
|
export async function startPrintCli(options: PrintCliOptions): Promise<void> {
|
|
12
|
-
const
|
|
26
|
+
const startTime = new Date();
|
|
27
|
+
const {
|
|
28
|
+
restoreSessionId,
|
|
29
|
+
continueLastSession,
|
|
30
|
+
message,
|
|
31
|
+
showStats = false,
|
|
32
|
+
} = options;
|
|
13
33
|
|
|
14
34
|
if (
|
|
15
35
|
(!message || message.trim() === "") &&
|
|
@@ -26,12 +46,64 @@ export async function startPrintCli(options: PrintCliOptions): Promise<void> {
|
|
|
26
46
|
|
|
27
47
|
// Setup callbacks for agent
|
|
28
48
|
const callbacks: AgentCallbacks = {
|
|
29
|
-
onAssistantMessageAdded: (
|
|
30
|
-
//
|
|
31
|
-
|
|
32
|
-
|
|
49
|
+
onAssistantMessageAdded: () => {
|
|
50
|
+
// Assistant message started - no content to output yet
|
|
51
|
+
process.stdout.write("\n");
|
|
52
|
+
},
|
|
53
|
+
onAssistantContentUpdated: (chunk: string) => {
|
|
54
|
+
// FR-001: Stream content updates for real-time display - output only the new chunk
|
|
55
|
+
process.stdout.write(chunk);
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
// Tool block callback - display tool name when tool starts
|
|
59
|
+
onToolBlockUpdated: (params) => {
|
|
60
|
+
// Print tool name only during 'running' stage (happens once per tool call)
|
|
61
|
+
if (params.stage === "running" && params.name) {
|
|
62
|
+
process.stdout.write(`\n🔧 ${params.name}`);
|
|
63
|
+
if (params.compactParams) {
|
|
64
|
+
process.stdout.write(` ${params.compactParams}`);
|
|
65
|
+
}
|
|
66
|
+
process.stdout.write(`\n`);
|
|
33
67
|
}
|
|
34
68
|
},
|
|
69
|
+
|
|
70
|
+
// Subagent block callbacks
|
|
71
|
+
onSubAgentBlockAdded: (subagentId: string, parameters) => {
|
|
72
|
+
// Display subagent creation with indentation
|
|
73
|
+
process.stdout.write(
|
|
74
|
+
`\n🤖 Subagent [${parameters.subagent_type}]: ${parameters.description}\n`,
|
|
75
|
+
);
|
|
76
|
+
},
|
|
77
|
+
onSubAgentBlockUpdated: (subagentId: string, status) => {
|
|
78
|
+
// Display subagent status updates
|
|
79
|
+
const statusIconMap = {
|
|
80
|
+
active: "🔄",
|
|
81
|
+
completed: "✅",
|
|
82
|
+
error: "❌",
|
|
83
|
+
aborted: "⚠️",
|
|
84
|
+
} as const;
|
|
85
|
+
|
|
86
|
+
const statusIcon = statusIconMap[status] ?? "🔄";
|
|
87
|
+
process.stdout.write(` ${statusIcon} Subagent status: ${status}\n`);
|
|
88
|
+
},
|
|
89
|
+
// Subagent message callbacks
|
|
90
|
+
onSubagentAssistantMessageAdded: () => {
|
|
91
|
+
// Subagent assistant message started - add indentation
|
|
92
|
+
process.stdout.write("\n ");
|
|
93
|
+
},
|
|
94
|
+
onSubagentAssistantContentUpdated: (_subagentId: string, chunk: string) => {
|
|
95
|
+
// Stream subagent content with indentation - output only the new chunk
|
|
96
|
+
process.stdout.write(chunk);
|
|
97
|
+
},
|
|
98
|
+
onSubagentUserMessageAdded: (_subagentId: string, params) => {
|
|
99
|
+
// Display subagent user messages with indentation
|
|
100
|
+
process.stdout.write(`\n 👤 User: ${params.content}\n`);
|
|
101
|
+
},
|
|
102
|
+
// Error block callback
|
|
103
|
+
onErrorBlockAdded: (error: string) => {
|
|
104
|
+
// Display error blocks with distinct formatting
|
|
105
|
+
process.stdout.write(`\n❌ Error: ${error}\n`);
|
|
106
|
+
},
|
|
35
107
|
};
|
|
36
108
|
|
|
37
109
|
try {
|
|
@@ -40,7 +112,6 @@ export async function startPrintCli(options: PrintCliOptions): Promise<void> {
|
|
|
40
112
|
callbacks,
|
|
41
113
|
restoreSessionId,
|
|
42
114
|
continueLastSession,
|
|
43
|
-
logger,
|
|
44
115
|
});
|
|
45
116
|
|
|
46
117
|
// Send message if provided and not empty
|
|
@@ -49,29 +120,40 @@ export async function startPrintCli(options: PrintCliOptions): Promise<void> {
|
|
|
49
120
|
}
|
|
50
121
|
|
|
51
122
|
// Display usage summary before exit
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
123
|
+
if (showStats) {
|
|
124
|
+
try {
|
|
125
|
+
const usages = agent.usages;
|
|
126
|
+
const sessionFilePath = agent.sessionFilePath;
|
|
127
|
+
displayUsageSummary(usages, sessionFilePath);
|
|
128
|
+
} catch {
|
|
129
|
+
// Silently ignore usage summary errors
|
|
130
|
+
}
|
|
58
131
|
}
|
|
59
132
|
|
|
133
|
+
// Display timing information
|
|
134
|
+
displayTimingInfo(startTime, showStats);
|
|
135
|
+
|
|
60
136
|
// Destroy agent and exit after sendMessage completes
|
|
61
|
-
agent.destroy();
|
|
137
|
+
await agent.destroy();
|
|
62
138
|
process.exit(0);
|
|
63
139
|
} catch (error) {
|
|
64
140
|
console.error("Failed to send message:", error);
|
|
65
141
|
if (agent!) {
|
|
66
142
|
// Display usage summary even on error
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
143
|
+
if (showStats) {
|
|
144
|
+
try {
|
|
145
|
+
const usages = agent.usages;
|
|
146
|
+
const sessionFilePath = agent.sessionFilePath;
|
|
147
|
+
displayUsageSummary(usages, sessionFilePath);
|
|
148
|
+
} catch {
|
|
149
|
+
// Silently ignore usage summary errors
|
|
150
|
+
}
|
|
73
151
|
}
|
|
74
|
-
|
|
152
|
+
|
|
153
|
+
// Display timing information even on error
|
|
154
|
+
displayTimingInfo(startTime, showStats);
|
|
155
|
+
|
|
156
|
+
await agent.destroy();
|
|
75
157
|
}
|
|
76
158
|
process.exit(1);
|
|
77
159
|
}
|
|
@@ -12,6 +12,13 @@ export interface TokenSummary {
|
|
|
12
12
|
agent_calls: number;
|
|
13
13
|
compressions: number;
|
|
14
14
|
};
|
|
15
|
+
// Cache-related tokens (for Claude models)
|
|
16
|
+
cache_read_input_tokens?: number;
|
|
17
|
+
cache_creation_input_tokens?: number;
|
|
18
|
+
cache_creation?: {
|
|
19
|
+
ephemeral_5m_input_tokens: number;
|
|
20
|
+
ephemeral_1h_input_tokens: number;
|
|
21
|
+
};
|
|
15
22
|
}
|
|
16
23
|
|
|
17
24
|
/**
|
|
@@ -45,6 +52,36 @@ export function calculateTokenSummary(
|
|
|
45
52
|
summary.completion_tokens += usage.completion_tokens;
|
|
46
53
|
summary.total_tokens += usage.total_tokens;
|
|
47
54
|
|
|
55
|
+
// Handle cache tokens if present and non-zero
|
|
56
|
+
if (usage.cache_read_input_tokens && usage.cache_read_input_tokens > 0) {
|
|
57
|
+
summary.cache_read_input_tokens =
|
|
58
|
+
(summary.cache_read_input_tokens || 0) + usage.cache_read_input_tokens;
|
|
59
|
+
}
|
|
60
|
+
if (
|
|
61
|
+
usage.cache_creation_input_tokens &&
|
|
62
|
+
usage.cache_creation_input_tokens > 0
|
|
63
|
+
) {
|
|
64
|
+
summary.cache_creation_input_tokens =
|
|
65
|
+
(summary.cache_creation_input_tokens || 0) +
|
|
66
|
+
usage.cache_creation_input_tokens;
|
|
67
|
+
}
|
|
68
|
+
if (
|
|
69
|
+
usage.cache_creation &&
|
|
70
|
+
(usage.cache_creation.ephemeral_5m_input_tokens > 0 ||
|
|
71
|
+
usage.cache_creation.ephemeral_1h_input_tokens > 0)
|
|
72
|
+
) {
|
|
73
|
+
if (!summary.cache_creation) {
|
|
74
|
+
summary.cache_creation = {
|
|
75
|
+
ephemeral_5m_input_tokens: 0,
|
|
76
|
+
ephemeral_1h_input_tokens: 0,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
summary.cache_creation.ephemeral_5m_input_tokens +=
|
|
80
|
+
usage.cache_creation.ephemeral_5m_input_tokens || 0;
|
|
81
|
+
summary.cache_creation.ephemeral_1h_input_tokens +=
|
|
82
|
+
usage.cache_creation.ephemeral_1h_input_tokens || 0;
|
|
83
|
+
}
|
|
84
|
+
|
|
48
85
|
// Track operation types
|
|
49
86
|
if (usage.operation_type === "agent") {
|
|
50
87
|
summary.operations.agent_calls += 1;
|
|
@@ -93,6 +130,11 @@ export function displayUsageSummary(
|
|
|
93
130
|
let totalTokens = 0;
|
|
94
131
|
let totalAgentCalls = 0;
|
|
95
132
|
let totalCompressions = 0;
|
|
133
|
+
let totalCacheRead = 0;
|
|
134
|
+
let totalCacheCreation = 0;
|
|
135
|
+
let totalCache5m = 0;
|
|
136
|
+
let totalCache1h = 0;
|
|
137
|
+
let hasCacheData = false;
|
|
96
138
|
|
|
97
139
|
for (const [, summary] of Object.entries(summaries)) {
|
|
98
140
|
console.log(`Model: ${summary.model}`);
|
|
@@ -101,6 +143,52 @@ export function displayUsageSummary(
|
|
|
101
143
|
` Completion tokens: ${summary.completion_tokens.toLocaleString()}`,
|
|
102
144
|
);
|
|
103
145
|
console.log(` Total tokens: ${summary.total_tokens.toLocaleString()}`);
|
|
146
|
+
|
|
147
|
+
// Display cache information if available
|
|
148
|
+
if (
|
|
149
|
+
summary.cache_read_input_tokens ||
|
|
150
|
+
summary.cache_creation_input_tokens ||
|
|
151
|
+
summary.cache_creation
|
|
152
|
+
) {
|
|
153
|
+
hasCacheData = true;
|
|
154
|
+
console.log(" Cache Usage:");
|
|
155
|
+
|
|
156
|
+
if (
|
|
157
|
+
summary.cache_read_input_tokens &&
|
|
158
|
+
summary.cache_read_input_tokens > 0
|
|
159
|
+
) {
|
|
160
|
+
console.log(
|
|
161
|
+
` Read from cache: ${summary.cache_read_input_tokens.toLocaleString()} tokens`,
|
|
162
|
+
);
|
|
163
|
+
totalCacheRead += summary.cache_read_input_tokens;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (
|
|
167
|
+
summary.cache_creation_input_tokens &&
|
|
168
|
+
summary.cache_creation_input_tokens > 0
|
|
169
|
+
) {
|
|
170
|
+
console.log(
|
|
171
|
+
` Created cache: ${summary.cache_creation_input_tokens.toLocaleString()} tokens`,
|
|
172
|
+
);
|
|
173
|
+
totalCacheCreation += summary.cache_creation_input_tokens;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (summary.cache_creation) {
|
|
177
|
+
if (summary.cache_creation.ephemeral_5m_input_tokens > 0) {
|
|
178
|
+
console.log(
|
|
179
|
+
` 5m cache: ${summary.cache_creation.ephemeral_5m_input_tokens.toLocaleString()} tokens`,
|
|
180
|
+
);
|
|
181
|
+
totalCache5m += summary.cache_creation.ephemeral_5m_input_tokens;
|
|
182
|
+
}
|
|
183
|
+
if (summary.cache_creation.ephemeral_1h_input_tokens > 0) {
|
|
184
|
+
console.log(
|
|
185
|
+
` 1h cache: ${summary.cache_creation.ephemeral_1h_input_tokens.toLocaleString()} tokens`,
|
|
186
|
+
);
|
|
187
|
+
totalCache1h += summary.cache_creation.ephemeral_1h_input_tokens;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
104
192
|
console.log(
|
|
105
193
|
` Operations: ${summary.operations.agent_calls} agent calls, ${summary.operations.compressions} compressions`,
|
|
106
194
|
);
|
|
@@ -118,6 +206,27 @@ export function displayUsageSummary(
|
|
|
118
206
|
console.log(` Prompt tokens: ${totalPrompt.toLocaleString()}`);
|
|
119
207
|
console.log(` Completion tokens: ${totalCompletion.toLocaleString()}`);
|
|
120
208
|
console.log(` Total tokens: ${totalTokens.toLocaleString()}`);
|
|
209
|
+
|
|
210
|
+
if (hasCacheData) {
|
|
211
|
+
console.log(" Cache Usage:");
|
|
212
|
+
if (totalCacheRead > 0) {
|
|
213
|
+
console.log(
|
|
214
|
+
` Read from cache: ${totalCacheRead.toLocaleString()} tokens`,
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
if (totalCacheCreation > 0) {
|
|
218
|
+
console.log(
|
|
219
|
+
` Created cache: ${totalCacheCreation.toLocaleString()} tokens`,
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
if (totalCache5m > 0) {
|
|
223
|
+
console.log(` 5m cache: ${totalCache5m.toLocaleString()} tokens`);
|
|
224
|
+
}
|
|
225
|
+
if (totalCache1h > 0) {
|
|
226
|
+
console.log(` 1h cache: ${totalCache1h.toLocaleString()} tokens`);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
121
230
|
console.log(
|
|
122
231
|
` Operations: ${totalAgentCalls} agent calls, ${totalCompressions} compressions`,
|
|
123
232
|
);
|