wave-code 0.0.4 → 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 +46 -101
- 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 -32
- package/dist/components/SubagentBlock.d.ts +1 -2
- package/dist/components/SubagentBlock.d.ts.map +1 -1
- package/dist/components/SubagentBlock.js +29 -20
- package/dist/components/ToolResultDisplay.js +5 -5
- package/dist/contexts/useChat.d.ts +1 -0
- package/dist/contexts/useChat.d.ts.map +1 -1
- package/dist/contexts/useChat.js +29 -2
- package/dist/hooks/useInputManager.d.ts +93 -0
- package/dist/hooks/useInputManager.d.ts.map +1 -0
- package/dist/hooks/useInputManager.js +332 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -10
- package/dist/managers/InputManager.d.ts +171 -0
- package/dist/managers/InputManager.d.ts.map +1 -0
- package/dist/managers/InputManager.js +826 -0
- package/dist/print-cli.d.ts +8 -0
- package/dist/print-cli.d.ts.map +1 -0
- package/dist/print-cli.js +128 -0
- package/dist/utils/constants.d.ts +1 -1
- package/dist/utils/constants.js +1 -1
- package/dist/utils/fileSearch.d.ts +20 -0
- package/dist/utils/fileSearch.d.ts.map +1 -0
- package/dist/utils/fileSearch.js +102 -0
- package/dist/utils/logger.js +3 -3
- package/dist/utils/usageSummary.d.ts +33 -0
- package/dist/utils/usageSummary.d.ts.map +1 -0
- package/dist/utils/usageSummary.js +154 -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 +78 -169
- package/src/components/Markdown.tsx +29 -0
- package/src/components/MessageItem.tsx +104 -0
- package/src/components/MessageList.tsx +142 -198
- package/src/components/SubagentBlock.tsx +56 -73
- package/src/components/ToolResultDisplay.tsx +6 -6
- package/src/contexts/useChat.tsx +34 -2
- package/src/hooks/useInputManager.ts +461 -0
- package/src/index.ts +20 -10
- package/src/managers/InputManager.ts +1132 -0
- package/src/print-cli.ts +160 -0
- package/src/utils/constants.ts +1 -1
- package/src/utils/fileSearch.ts +133 -0
- package/src/utils/logger.ts +3 -3
- package/src/utils/usageSummary.ts +234 -0
- package/dist/hooks/useBashHistorySelector.d.ts +0 -15
- package/dist/hooks/useBashHistorySelector.d.ts.map +0 -1
- package/dist/hooks/useBashHistorySelector.js +0 -61
- package/dist/hooks/useCommandSelector.d.ts +0 -24
- package/dist/hooks/useCommandSelector.d.ts.map +0 -1
- package/dist/hooks/useCommandSelector.js +0 -98
- package/dist/hooks/useFileSelector.d.ts +0 -16
- package/dist/hooks/useFileSelector.d.ts.map +0 -1
- package/dist/hooks/useFileSelector.js +0 -174
- package/dist/hooks/useImageManager.d.ts +0 -13
- package/dist/hooks/useImageManager.d.ts.map +0 -1
- package/dist/hooks/useImageManager.js +0 -46
- package/dist/hooks/useInputHistory.d.ts +0 -11
- package/dist/hooks/useInputHistory.d.ts.map +0 -1
- package/dist/hooks/useInputHistory.js +0 -64
- package/dist/hooks/useInputKeyboardHandler.d.ts +0 -83
- package/dist/hooks/useInputKeyboardHandler.d.ts.map +0 -1
- package/dist/hooks/useInputKeyboardHandler.js +0 -507
- package/dist/hooks/useInputState.d.ts +0 -14
- package/dist/hooks/useInputState.d.ts.map +0 -1
- package/dist/hooks/useInputState.js +0 -57
- package/dist/hooks/useMemoryTypeSelector.d.ts +0 -9
- package/dist/hooks/useMemoryTypeSelector.d.ts.map +0 -1
- package/dist/hooks/useMemoryTypeSelector.js +0 -27
- package/dist/plain-cli.d.ts +0 -7
- package/dist/plain-cli.d.ts.map +0 -1
- package/dist/plain-cli.js +0 -44
- package/src/hooks/useBashHistorySelector.ts +0 -77
- package/src/hooks/useCommandSelector.ts +0 -131
- package/src/hooks/useFileSelector.ts +0 -227
- package/src/hooks/useImageManager.ts +0 -64
- package/src/hooks/useInputHistory.ts +0 -74
- package/src/hooks/useInputKeyboardHandler.ts +0 -778
- package/src/hooks/useInputState.ts +0 -66
- package/src/hooks/useMemoryTypeSelector.ts +0 -40
- package/src/plain-cli.ts +0 -60
|
@@ -1,107 +1,7 @@
|
|
|
1
|
-
import React
|
|
2
|
-
import { Box, Text } from "ink";
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Box, Text, Static } from "ink";
|
|
3
3
|
import type { Message } from "wave-agent-sdk";
|
|
4
|
-
import {
|
|
5
|
-
import { CommandOutputDisplay } from "./CommandOutputDisplay.js";
|
|
6
|
-
import { ToolResultDisplay } from "./ToolResultDisplay.js";
|
|
7
|
-
import { MemoryDisplay } from "./MemoryDisplay.js";
|
|
8
|
-
import { CompressDisplay } from "./CompressDisplay.js";
|
|
9
|
-
import { SubagentBlock } from "./SubagentBlock.js";
|
|
10
|
-
import { usePagination } from "../hooks/usePagination.js";
|
|
11
|
-
|
|
12
|
-
// Function to render a single message
|
|
13
|
-
const renderMessageItem = (
|
|
14
|
-
message: Message,
|
|
15
|
-
originalIndex: number,
|
|
16
|
-
isExpanded: boolean,
|
|
17
|
-
previousMessage?: Message,
|
|
18
|
-
) => {
|
|
19
|
-
const shouldShowHeader = previousMessage?.role !== message.role;
|
|
20
|
-
|
|
21
|
-
return (
|
|
22
|
-
<Box key={`message-${originalIndex}`} flexDirection="column">
|
|
23
|
-
{shouldShowHeader && (
|
|
24
|
-
<Box>
|
|
25
|
-
<Text color={message.role === "user" ? "cyan" : "green"} bold>
|
|
26
|
-
{message.role === "user" ? "👤 You" : "🤖 Assistant"}
|
|
27
|
-
<Text color="gray" dimColor>
|
|
28
|
-
{" "}
|
|
29
|
-
#{originalIndex + 1}
|
|
30
|
-
</Text>
|
|
31
|
-
</Text>
|
|
32
|
-
</Box>
|
|
33
|
-
)}
|
|
34
|
-
|
|
35
|
-
<Box
|
|
36
|
-
marginLeft={2}
|
|
37
|
-
flexDirection="column"
|
|
38
|
-
gap={1}
|
|
39
|
-
marginTop={shouldShowHeader ? 1 : 0}
|
|
40
|
-
>
|
|
41
|
-
{message.blocks.map((block, blockIndex) => (
|
|
42
|
-
<Box key={blockIndex}>
|
|
43
|
-
{block.type === "text" && block.content.trim() && (
|
|
44
|
-
<Box>
|
|
45
|
-
<Text>{block.content}</Text>
|
|
46
|
-
</Box>
|
|
47
|
-
)}
|
|
48
|
-
|
|
49
|
-
{block.type === "error" && (
|
|
50
|
-
<Box>
|
|
51
|
-
<Text color="red">❌ Error: {block.content}</Text>
|
|
52
|
-
</Box>
|
|
53
|
-
)}
|
|
54
|
-
|
|
55
|
-
{block.type === "diff" && (
|
|
56
|
-
<DiffViewer block={block} isExpanded={isExpanded} />
|
|
57
|
-
)}
|
|
58
|
-
|
|
59
|
-
{block.type === "command_output" && (
|
|
60
|
-
<CommandOutputDisplay block={block} isExpanded={isExpanded} />
|
|
61
|
-
)}
|
|
62
|
-
|
|
63
|
-
{block.type === "tool" && (
|
|
64
|
-
<ToolResultDisplay block={block} isExpanded={isExpanded} />
|
|
65
|
-
)}
|
|
66
|
-
|
|
67
|
-
{block.type === "image" && (
|
|
68
|
-
<Box>
|
|
69
|
-
<Text color="magenta" bold>
|
|
70
|
-
📷 Image
|
|
71
|
-
</Text>
|
|
72
|
-
{block.imageUrls && block.imageUrls.length > 0 && (
|
|
73
|
-
<Text color="gray" dimColor>
|
|
74
|
-
{" "}
|
|
75
|
-
({block.imageUrls.length})
|
|
76
|
-
</Text>
|
|
77
|
-
)}
|
|
78
|
-
</Box>
|
|
79
|
-
)}
|
|
80
|
-
|
|
81
|
-
{block.type === "memory" && <MemoryDisplay block={block} />}
|
|
82
|
-
|
|
83
|
-
{block.type === "compress" && (
|
|
84
|
-
<CompressDisplay block={block} isExpanded={isExpanded} />
|
|
85
|
-
)}
|
|
86
|
-
|
|
87
|
-
{block.type === "custom_command" && (
|
|
88
|
-
<Box>
|
|
89
|
-
<Text color="cyan" bold>
|
|
90
|
-
⚡
|
|
91
|
-
</Text>
|
|
92
|
-
<Text>{block.originalInput || `/${block.commandName}`}</Text>
|
|
93
|
-
</Box>
|
|
94
|
-
)}
|
|
95
|
-
|
|
96
|
-
{block.type === "subagent" && (
|
|
97
|
-
<SubagentBlock block={block} isExpanded={isExpanded} />
|
|
98
|
-
)}
|
|
99
|
-
</Box>
|
|
100
|
-
))}
|
|
101
|
-
</Box>
|
|
102
|
-
</Box>
|
|
103
|
-
);
|
|
104
|
-
};
|
|
4
|
+
import { MessageItem } from "./MessageItem.js";
|
|
105
5
|
|
|
106
6
|
export interface MessageListProps {
|
|
107
7
|
messages: Message[];
|
|
@@ -112,109 +12,153 @@ export interface MessageListProps {
|
|
|
112
12
|
isExpanded?: boolean;
|
|
113
13
|
}
|
|
114
14
|
|
|
115
|
-
export const MessageList
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
15
|
+
export const MessageList = React.memo(
|
|
16
|
+
({
|
|
17
|
+
messages,
|
|
18
|
+
isLoading = false,
|
|
19
|
+
isCommandRunning = false,
|
|
20
|
+
isCompressing = false,
|
|
21
|
+
latestTotalTokens = 0,
|
|
22
|
+
isExpanded = false,
|
|
23
|
+
}: MessageListProps) => {
|
|
24
|
+
// Empty message state
|
|
25
|
+
if (messages.length === 0) {
|
|
26
|
+
return (
|
|
27
|
+
<Box flexDirection="column" paddingY={1}>
|
|
28
|
+
<Text color="gray">Welcome to WAVE Code Assistant!</Text>
|
|
29
|
+
</Box>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Limit messages when expanded to prevent long rendering times
|
|
34
|
+
const maxExpandedMessages = 20;
|
|
35
|
+
const shouldLimitMessages =
|
|
36
|
+
isExpanded && messages.length > maxExpandedMessages;
|
|
37
|
+
const displayMessages = shouldLimitMessages
|
|
38
|
+
? messages.slice(-maxExpandedMessages)
|
|
39
|
+
: messages;
|
|
40
|
+
const omittedCount = shouldLimitMessages
|
|
41
|
+
? messages.length - maxExpandedMessages
|
|
42
|
+
: 0;
|
|
43
|
+
|
|
44
|
+
// Compute which messages to render statically vs dynamically
|
|
45
|
+
const shouldRenderLastDynamic = isLoading || isCommandRunning;
|
|
46
|
+
const staticMessages = shouldRenderLastDynamic
|
|
47
|
+
? displayMessages.slice(0, -1)
|
|
48
|
+
: displayMessages;
|
|
49
|
+
const dynamicMessages =
|
|
50
|
+
shouldRenderLastDynamic && displayMessages.length > 0
|
|
51
|
+
? [displayMessages[displayMessages.length - 1]]
|
|
52
|
+
: [];
|
|
135
53
|
|
|
136
|
-
// Empty message state
|
|
137
|
-
if (messages.length === 0) {
|
|
138
54
|
return (
|
|
139
|
-
<Box flexDirection="column"
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
55
|
+
<Box flexDirection="column" paddingX={1} gap={1}>
|
|
56
|
+
{/* Show omitted message count when limiting */}
|
|
57
|
+
{omittedCount > 0 && (
|
|
58
|
+
<Box>
|
|
59
|
+
<Text color="gray" dimColor>
|
|
60
|
+
... {omittedCount} earlier message{omittedCount !== 1 ? "s" : ""}{" "}
|
|
61
|
+
omitted (showing latest {maxExpandedMessages})
|
|
62
|
+
</Text>
|
|
63
|
+
</Box>
|
|
64
|
+
)}
|
|
65
|
+
|
|
66
|
+
{/* Static messages */}
|
|
67
|
+
<Static items={staticMessages}>
|
|
68
|
+
{(message, key) => {
|
|
69
|
+
// Get previous message
|
|
70
|
+
const previousMessage =
|
|
71
|
+
key > 0 ? staticMessages[key - 1] : undefined;
|
|
72
|
+
return (
|
|
73
|
+
<MessageItem
|
|
74
|
+
key={key}
|
|
75
|
+
message={message}
|
|
76
|
+
shouldShowHeader={previousMessage?.role !== message.role}
|
|
77
|
+
isExpanded={isExpanded}
|
|
78
|
+
isStatic={true}
|
|
79
|
+
/>
|
|
80
|
+
);
|
|
81
|
+
}}
|
|
82
|
+
</Static>
|
|
83
|
+
|
|
84
|
+
{/* Dynamic messages */}
|
|
85
|
+
{dynamicMessages.map((message, index) => {
|
|
86
|
+
const messageIndex = staticMessages.length + index;
|
|
151
87
|
const previousMessage =
|
|
152
|
-
|
|
153
|
-
return
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
88
|
+
messageIndex > 0 ? displayMessages[messageIndex - 1] : undefined;
|
|
89
|
+
return (
|
|
90
|
+
<Box key={`dynamic-${index}`} marginTop={-1}>
|
|
91
|
+
<MessageItem
|
|
92
|
+
message={message}
|
|
93
|
+
shouldShowHeader={previousMessage?.role !== message.role}
|
|
94
|
+
isExpanded={isExpanded}
|
|
95
|
+
isStatic={false}
|
|
96
|
+
/>
|
|
97
|
+
</Box>
|
|
158
98
|
);
|
|
159
99
|
})}
|
|
160
|
-
</Box>
|
|
161
100
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
)}
|
|
188
|
-
{isCommandRunning && (
|
|
189
|
-
<Text color="blue">🚀 Command is running...</Text>
|
|
190
|
-
)}
|
|
191
|
-
{isCompressing && (
|
|
192
|
-
<Text color="magenta">🗜️ Compressing message history...</Text>
|
|
193
|
-
)}
|
|
194
|
-
</Box>
|
|
195
|
-
)}
|
|
101
|
+
{(isLoading || isCommandRunning || isCompressing) && (
|
|
102
|
+
<Box flexDirection="column" gap={1}>
|
|
103
|
+
{isLoading && (
|
|
104
|
+
<Box>
|
|
105
|
+
<Text color="yellow">💭 AI is thinking... </Text>
|
|
106
|
+
<Text color="gray" dimColor>
|
|
107
|
+
|{" "}
|
|
108
|
+
</Text>
|
|
109
|
+
<Text color="red" bold>
|
|
110
|
+
Esc
|
|
111
|
+
</Text>
|
|
112
|
+
<Text color="gray" dimColor>
|
|
113
|
+
{" "}
|
|
114
|
+
to abort
|
|
115
|
+
</Text>
|
|
116
|
+
</Box>
|
|
117
|
+
)}
|
|
118
|
+
{isCommandRunning && (
|
|
119
|
+
<Text color="blue">🚀 Command is running...</Text>
|
|
120
|
+
)}
|
|
121
|
+
{isCompressing && (
|
|
122
|
+
<Text color="magenta">🗜️ Compressing message history...</Text>
|
|
123
|
+
)}
|
|
124
|
+
</Box>
|
|
125
|
+
)}
|
|
196
126
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
127
|
+
{/* Bottom info and shortcut key hints */}
|
|
128
|
+
{messages.length > 0 && (
|
|
129
|
+
<Box>
|
|
130
|
+
<Box justifyContent="space-between" width="100%">
|
|
131
|
+
<Box>
|
|
132
|
+
<Text color="gray">
|
|
133
|
+
Messages {messages.length}
|
|
134
|
+
{latestTotalTokens > 0 && (
|
|
135
|
+
<>
|
|
136
|
+
<Text color="gray" dimColor>
|
|
137
|
+
{" "}
|
|
138
|
+
|{" "}
|
|
139
|
+
</Text>
|
|
140
|
+
<Text color="blue" bold>
|
|
141
|
+
{latestTotalTokens.toLocaleString()}
|
|
142
|
+
</Text>
|
|
143
|
+
<Text color="gray" dimColor>
|
|
144
|
+
{" "}
|
|
145
|
+
tokens
|
|
146
|
+
</Text>
|
|
147
|
+
</>
|
|
148
|
+
)}
|
|
149
|
+
</Text>
|
|
150
|
+
</Box>
|
|
206
151
|
<Text color="gray" dimColor>
|
|
207
|
-
{" "}
|
|
208
|
-
|
|
152
|
+
<Text color="cyan">Ctrl+O</Text> Toggle{" "}
|
|
153
|
+
{isExpanded ? "Collapse" : "Expand"}
|
|
209
154
|
</Text>
|
|
210
155
|
</Box>
|
|
211
|
-
<Text color="gray" dimColor>
|
|
212
|
-
<Text color="cyan">Ctrl+O</Text> Toggle{" "}
|
|
213
|
-
{isExpanded ? "Collapse" : "Expand"}
|
|
214
|
-
</Text>
|
|
215
156
|
</Box>
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
157
|
+
)}
|
|
158
|
+
</Box>
|
|
159
|
+
);
|
|
160
|
+
},
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
// Add display name for debugging
|
|
164
|
+
MessageList.displayName = "MessageList";
|
|
@@ -1,46 +1,18 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { Box, Text } from "ink";
|
|
3
|
-
import type {
|
|
4
|
-
|
|
5
|
-
Message,
|
|
6
|
-
MessageBlock,
|
|
7
|
-
} from "wave-agent-sdk/src/types.js";
|
|
8
|
-
import { ToolResultDisplay } from "./ToolResultDisplay.js";
|
|
9
|
-
|
|
10
|
-
// Component to render individual message blocks
|
|
11
|
-
interface MessageBlockRendererProps {
|
|
12
|
-
block: MessageBlock;
|
|
13
|
-
isExpanded: boolean;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const MessageBlockRenderer: React.FC<MessageBlockRendererProps> = ({
|
|
17
|
-
block,
|
|
18
|
-
isExpanded,
|
|
19
|
-
}) => {
|
|
20
|
-
switch (block.type) {
|
|
21
|
-
case "text":
|
|
22
|
-
return <Text>{block.content}</Text>;
|
|
23
|
-
|
|
24
|
-
case "error":
|
|
25
|
-
return <Text color="red">❌ Error: {block.content}</Text>;
|
|
26
|
-
|
|
27
|
-
case "tool":
|
|
28
|
-
return <ToolResultDisplay block={block} isExpanded={isExpanded} />;
|
|
29
|
-
|
|
30
|
-
default:
|
|
31
|
-
return null;
|
|
32
|
-
}
|
|
33
|
-
};
|
|
3
|
+
import type { SubagentBlock as SubagentBlockType } from "wave-agent-sdk";
|
|
4
|
+
import { useChat } from "../contexts/useChat.js";
|
|
34
5
|
|
|
35
6
|
interface SubagentBlockProps {
|
|
36
7
|
block: SubagentBlockType;
|
|
37
|
-
isExpanded?: boolean;
|
|
38
8
|
}
|
|
39
9
|
|
|
40
|
-
export const SubagentBlock: React.FC<SubagentBlockProps> = ({
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
10
|
+
export const SubagentBlock: React.FC<SubagentBlockProps> = ({ block }) => {
|
|
11
|
+
const { subagentMessages } = useChat();
|
|
12
|
+
|
|
13
|
+
// Get messages for this subagent from context
|
|
14
|
+
const messages = subagentMessages[block.subagentId] || [];
|
|
15
|
+
|
|
44
16
|
// Status indicator mapping
|
|
45
17
|
const getStatusIndicator = (status: SubagentBlockType["status"]) => {
|
|
46
18
|
switch (status) {
|
|
@@ -59,14 +31,40 @@ export const SubagentBlock: React.FC<SubagentBlockProps> = ({
|
|
|
59
31
|
|
|
60
32
|
const statusInfo = getStatusIndicator(block.status);
|
|
61
33
|
|
|
62
|
-
//
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
:
|
|
34
|
+
// Find the last 2 tool names and their compact params, and count total tools
|
|
35
|
+
const getLastTwoTools = (): {
|
|
36
|
+
tools: Array<{ name: string; compactParams?: string }>;
|
|
37
|
+
totalToolCount: number;
|
|
38
|
+
} => {
|
|
39
|
+
const tools: Array<{ name: string; compactParams?: string }> = [];
|
|
40
|
+
let totalToolCount = 0;
|
|
41
|
+
|
|
42
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
43
|
+
const message = messages[i];
|
|
44
|
+
for (let j = message.blocks.length - 1; j >= 0; j--) {
|
|
45
|
+
const messageBlock = message.blocks[j];
|
|
46
|
+
if (messageBlock.type === "tool" && messageBlock.name) {
|
|
47
|
+
totalToolCount++;
|
|
48
|
+
if (tools.length < 2) {
|
|
49
|
+
tools.push({
|
|
50
|
+
name: messageBlock.name,
|
|
51
|
+
compactParams: messageBlock.compactParams,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return { tools: tools.reverse(), totalToolCount }; // Reverse to show oldest first, newest last
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const { tools: lastTwoTools, totalToolCount } = getLastTwoTools();
|
|
66
61
|
|
|
67
62
|
return (
|
|
68
63
|
<Box
|
|
69
|
-
|
|
64
|
+
borderRight={false}
|
|
65
|
+
borderTop={false}
|
|
66
|
+
borderBottom={false}
|
|
67
|
+
borderStyle="classic"
|
|
70
68
|
borderColor="magenta"
|
|
71
69
|
paddingX={1}
|
|
72
70
|
paddingY={0}
|
|
@@ -74,54 +72,39 @@ export const SubagentBlock: React.FC<SubagentBlockProps> = ({
|
|
|
74
72
|
marginBottom={1}
|
|
75
73
|
>
|
|
76
74
|
{/* Header Section */}
|
|
77
|
-
<Box
|
|
78
|
-
flexDirection="row"
|
|
79
|
-
justifyContent="space-between"
|
|
80
|
-
alignItems="center"
|
|
81
|
-
>
|
|
75
|
+
<Box flexDirection="row" gap={1}>
|
|
82
76
|
<Box flexDirection="row" alignItems="center">
|
|
83
77
|
<Text color="cyan">🤖 {block.subagentName}</Text>
|
|
84
78
|
<Text color={statusInfo.color} dimColor={false}>
|
|
85
79
|
{" "}
|
|
86
80
|
{statusInfo.icon}
|
|
87
81
|
</Text>
|
|
88
|
-
</Box>
|
|
89
|
-
|
|
90
|
-
{!isExpanded && (
|
|
91
82
|
<Text color="gray" dimColor>
|
|
92
|
-
{
|
|
83
|
+
{" "}
|
|
84
|
+
({messages.length} messages)
|
|
93
85
|
</Text>
|
|
94
|
-
|
|
86
|
+
</Box>
|
|
95
87
|
</Box>
|
|
96
88
|
|
|
97
|
-
{/*
|
|
98
|
-
{
|
|
89
|
+
{/* Tool Names Section - Vertical List */}
|
|
90
|
+
{lastTwoTools.length > 0 && (
|
|
99
91
|
<Box flexDirection="column" marginTop={1} gap={1}>
|
|
100
|
-
{
|
|
101
|
-
<
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
92
|
+
{totalToolCount > 2 && (
|
|
93
|
+
<Text color="gray" dimColor>
|
|
94
|
+
...
|
|
95
|
+
</Text>
|
|
96
|
+
)}
|
|
97
|
+
{lastTwoTools.map((tool, index) => (
|
|
98
|
+
<Box key={index} flexDirection="row">
|
|
99
|
+
<Text color="magenta">🔧 </Text>
|
|
100
|
+
<Text color="white">{tool.name}</Text>
|
|
101
|
+
{tool.compactParams && (
|
|
102
|
+
<Text color="gray"> {tool.compactParams}</Text>
|
|
111
103
|
)}
|
|
112
104
|
</Box>
|
|
113
105
|
))}
|
|
114
106
|
</Box>
|
|
115
107
|
)}
|
|
116
|
-
|
|
117
|
-
{/* Show truncation indicator if there are more messages */}
|
|
118
|
-
{!isExpanded && block.messages.length > 2 && (
|
|
119
|
-
<Box marginTop={1}>
|
|
120
|
-
<Text color="gray" dimColor>
|
|
121
|
-
... and {block.messages.length - 2} more messages (Ctrl+O to expand)
|
|
122
|
-
</Text>
|
|
123
|
-
</Box>
|
|
124
|
-
)}
|
|
125
108
|
</Box>
|
|
126
109
|
);
|
|
127
110
|
};
|
|
@@ -11,23 +11,23 @@ export const ToolResultDisplay: React.FC<ToolResultDisplayProps> = ({
|
|
|
11
11
|
block,
|
|
12
12
|
isExpanded = false,
|
|
13
13
|
}) => {
|
|
14
|
-
const { parameters, result, compactParams,
|
|
14
|
+
const { parameters, result, compactParams, stage, success, error, name } =
|
|
15
15
|
block;
|
|
16
16
|
|
|
17
17
|
// Directly use compactParams
|
|
18
18
|
// (no change needed as we destructured it above)
|
|
19
19
|
|
|
20
20
|
const getStatusColor = () => {
|
|
21
|
-
if (
|
|
21
|
+
if (stage === "running") return "yellow";
|
|
22
22
|
if (success) return "green";
|
|
23
23
|
if (error || success === false) return "red";
|
|
24
24
|
return "gray"; // Unknown state or no state information
|
|
25
25
|
};
|
|
26
26
|
|
|
27
27
|
const getStatusText = () => {
|
|
28
|
-
if (
|
|
28
|
+
if (stage === "running") return "🔄";
|
|
29
29
|
if (success) return "";
|
|
30
|
-
if (error || success === false) return "❌
|
|
30
|
+
if (error || success === false) return "❌";
|
|
31
31
|
return ""; // Don't display text for unknown state
|
|
32
32
|
};
|
|
33
33
|
|
|
@@ -70,7 +70,7 @@ export const ToolResultDisplay: React.FC<ToolResultDisplayProps> = ({
|
|
|
70
70
|
<Text color="white">{toolName}</Text>
|
|
71
71
|
{/* Display compactParams in collapsed state */}
|
|
72
72
|
{!isExpanded && compactParams && (
|
|
73
|
-
<Text color="gray">
|
|
73
|
+
<Text color="gray"> {compactParams}</Text>
|
|
74
74
|
)}
|
|
75
75
|
<Text color={getStatusColor()}> {getStatusText()}</Text>
|
|
76
76
|
{/* Display image indicator */}
|
|
@@ -78,7 +78,7 @@ export const ToolResultDisplay: React.FC<ToolResultDisplayProps> = ({
|
|
|
78
78
|
</Box>
|
|
79
79
|
|
|
80
80
|
{/* Display shortResult in collapsed state */}
|
|
81
|
-
{!isExpanded && shortResult && (
|
|
81
|
+
{!isExpanded && shortResult && !error && (
|
|
82
82
|
<Box
|
|
83
83
|
paddingLeft={2}
|
|
84
84
|
borderLeft
|
package/src/contexts/useChat.tsx
CHANGED
|
@@ -16,6 +16,7 @@ import type {
|
|
|
16
16
|
} from "wave-agent-sdk";
|
|
17
17
|
import { Agent, AgentCallbacks } from "wave-agent-sdk";
|
|
18
18
|
import { logger } from "../utils/logger.js";
|
|
19
|
+
import { displayUsageSummary } from "../utils/usageSummary.js";
|
|
19
20
|
|
|
20
21
|
// Main Chat Context
|
|
21
22
|
export interface ChatContextType {
|
|
@@ -49,6 +50,8 @@ export interface ChatContextType {
|
|
|
49
50
|
// Slash Command functionality
|
|
50
51
|
slashCommands: SlashCommand[];
|
|
51
52
|
hasSlashCommand: (commandId: string) => boolean;
|
|
53
|
+
// Subagent messages
|
|
54
|
+
subagentMessages: Record<string, Message[]>;
|
|
52
55
|
}
|
|
53
56
|
|
|
54
57
|
const ChatContext = createContext<ChatContextType | null>(null);
|
|
@@ -91,12 +94,23 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({ children }) => {
|
|
|
91
94
|
// Command state
|
|
92
95
|
const [slashCommands, setSlashCommands] = useState<SlashCommand[]>([]);
|
|
93
96
|
|
|
97
|
+
// Subagent messages state
|
|
98
|
+
const [subagentMessages, setSubagentMessages] = useState<
|
|
99
|
+
Record<string, Message[]>
|
|
100
|
+
>({});
|
|
101
|
+
|
|
94
102
|
const agentRef = useRef<Agent | null>(null);
|
|
95
103
|
|
|
96
104
|
// Listen for Ctrl+O hotkey to toggle collapse/expand state
|
|
97
105
|
useInput((input, key) => {
|
|
98
106
|
if (key.ctrl && input === "o") {
|
|
99
|
-
|
|
107
|
+
// Clear terminal screen when expanded state changes
|
|
108
|
+
process.stdout.write("\x1Bc", () => {
|
|
109
|
+
setIsExpanded((prev) => {
|
|
110
|
+
const newExpanded = !prev;
|
|
111
|
+
return newExpanded;
|
|
112
|
+
});
|
|
113
|
+
});
|
|
100
114
|
}
|
|
101
115
|
});
|
|
102
116
|
|
|
@@ -111,7 +125,9 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({ children }) => {
|
|
|
111
125
|
setMcpServers([...servers]);
|
|
112
126
|
},
|
|
113
127
|
onSessionIdChange: (sessionId) => {
|
|
114
|
-
|
|
128
|
+
process.stdout.write("\x1Bc", () => {
|
|
129
|
+
setSessionId(sessionId);
|
|
130
|
+
});
|
|
115
131
|
},
|
|
116
132
|
onLatestTotalTokensChange: (tokens) => {
|
|
117
133
|
setlatestTotalTokens(tokens);
|
|
@@ -125,6 +141,12 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({ children }) => {
|
|
|
125
141
|
onShellsChange: (shells) => {
|
|
126
142
|
setBackgroundShells([...shells]);
|
|
127
143
|
},
|
|
144
|
+
onSubagentMessagesChange: (subagentId, messages) => {
|
|
145
|
+
setSubagentMessages((prev) => ({
|
|
146
|
+
...prev,
|
|
147
|
+
[subagentId]: [...messages],
|
|
148
|
+
}));
|
|
149
|
+
},
|
|
128
150
|
};
|
|
129
151
|
|
|
130
152
|
try {
|
|
@@ -165,6 +187,15 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({ children }) => {
|
|
|
165
187
|
useEffect(() => {
|
|
166
188
|
return () => {
|
|
167
189
|
if (agentRef.current) {
|
|
190
|
+
try {
|
|
191
|
+
// Display usage summary before cleanup
|
|
192
|
+
const usages = agentRef.current.usages;
|
|
193
|
+
const sessionFilePath = agentRef.current.sessionFilePath;
|
|
194
|
+
displayUsageSummary(usages, sessionFilePath);
|
|
195
|
+
} catch {
|
|
196
|
+
// Silently ignore usage summary errors during cleanup
|
|
197
|
+
}
|
|
198
|
+
|
|
168
199
|
agentRef.current.destroy();
|
|
169
200
|
}
|
|
170
201
|
};
|
|
@@ -292,6 +323,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({ children }) => {
|
|
|
292
323
|
killBackgroundShell,
|
|
293
324
|
slashCommands,
|
|
294
325
|
hasSlashCommand,
|
|
326
|
+
subagentMessages,
|
|
295
327
|
};
|
|
296
328
|
|
|
297
329
|
return (
|