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
|
@@ -1,111 +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 { DiffViewer } from "./DiffViewer.js";
|
|
6
|
-
import { CommandOutputDisplay } from "./CommandOutputDisplay.js";
|
|
7
|
-
import { ToolResultDisplay } from "./ToolResultDisplay.js";
|
|
8
|
-
import { MemoryDisplay } from "./MemoryDisplay.js";
|
|
9
|
-
import { CompressDisplay } from "./CompressDisplay.js";
|
|
10
|
-
import { SubagentBlock } from "./SubagentBlock.js";
|
|
11
|
-
import { usePagination } from "../hooks/usePagination.js";
|
|
12
|
-
|
|
13
|
-
// Function to render a single message
|
|
14
|
-
const renderMessageItem = (
|
|
15
|
-
message: Message,
|
|
16
|
-
originalIndex: number,
|
|
17
|
-
isExpanded: boolean,
|
|
18
|
-
previousMessage?: Message,
|
|
19
|
-
) => {
|
|
20
|
-
const shouldShowHeader = previousMessage?.role !== message.role;
|
|
21
|
-
|
|
22
|
-
return (
|
|
23
|
-
<Box key={`message-${originalIndex}`} flexDirection="column">
|
|
24
|
-
{shouldShowHeader && (
|
|
25
|
-
<Box>
|
|
26
|
-
<Text color={message.role === "user" ? "cyan" : "green"} bold>
|
|
27
|
-
{message.role === "user" ? "👤 You" : "🤖 Assistant"}
|
|
28
|
-
<Text color="gray" dimColor>
|
|
29
|
-
{" "}
|
|
30
|
-
#{originalIndex + 1}
|
|
31
|
-
</Text>
|
|
32
|
-
</Text>
|
|
33
|
-
</Box>
|
|
34
|
-
)}
|
|
35
|
-
|
|
36
|
-
<Box
|
|
37
|
-
marginLeft={2}
|
|
38
|
-
flexDirection="column"
|
|
39
|
-
gap={1}
|
|
40
|
-
marginTop={shouldShowHeader ? 1 : 0}
|
|
41
|
-
>
|
|
42
|
-
{message.blocks.map((block, blockIndex) => (
|
|
43
|
-
<Box key={blockIndex}>
|
|
44
|
-
{block.type === "text" && block.content.trim() && (
|
|
45
|
-
<Box>
|
|
46
|
-
<Text>
|
|
47
|
-
{block.customCommandContent && (
|
|
48
|
-
<Text color="cyan" bold>
|
|
49
|
-
⚡{" "}
|
|
50
|
-
</Text>
|
|
51
|
-
)}
|
|
52
|
-
{block.source === MessageSource.HOOK && (
|
|
53
|
-
<Text color="magenta" bold>
|
|
54
|
-
🔗{" "}
|
|
55
|
-
</Text>
|
|
56
|
-
)}
|
|
57
|
-
{block.content}
|
|
58
|
-
</Text>
|
|
59
|
-
</Box>
|
|
60
|
-
)}
|
|
61
|
-
|
|
62
|
-
{block.type === "error" && (
|
|
63
|
-
<Box>
|
|
64
|
-
<Text color="red">❌ Error: {block.content}</Text>
|
|
65
|
-
</Box>
|
|
66
|
-
)}
|
|
67
|
-
|
|
68
|
-
{block.type === "diff" && (
|
|
69
|
-
<DiffViewer block={block} isExpanded={isExpanded} />
|
|
70
|
-
)}
|
|
71
|
-
|
|
72
|
-
{block.type === "command_output" && (
|
|
73
|
-
<CommandOutputDisplay block={block} isExpanded={isExpanded} />
|
|
74
|
-
)}
|
|
75
|
-
|
|
76
|
-
{block.type === "tool" && (
|
|
77
|
-
<ToolResultDisplay block={block} isExpanded={isExpanded} />
|
|
78
|
-
)}
|
|
79
|
-
|
|
80
|
-
{block.type === "image" && (
|
|
81
|
-
<Box>
|
|
82
|
-
<Text color="magenta" bold>
|
|
83
|
-
📷 Image
|
|
84
|
-
</Text>
|
|
85
|
-
{block.imageUrls && block.imageUrls.length > 0 && (
|
|
86
|
-
<Text color="gray" dimColor>
|
|
87
|
-
{" "}
|
|
88
|
-
({block.imageUrls.length})
|
|
89
|
-
</Text>
|
|
90
|
-
)}
|
|
91
|
-
</Box>
|
|
92
|
-
)}
|
|
93
|
-
|
|
94
|
-
{block.type === "memory" && <MemoryDisplay block={block} />}
|
|
95
|
-
|
|
96
|
-
{block.type === "compress" && (
|
|
97
|
-
<CompressDisplay block={block} isExpanded={isExpanded} />
|
|
98
|
-
)}
|
|
99
|
-
|
|
100
|
-
{block.type === "subagent" && (
|
|
101
|
-
<SubagentBlock block={block} isExpanded={isExpanded} />
|
|
102
|
-
)}
|
|
103
|
-
</Box>
|
|
104
|
-
))}
|
|
105
|
-
</Box>
|
|
106
|
-
</Box>
|
|
107
|
-
);
|
|
108
|
-
};
|
|
4
|
+
import { MessageItem } from "./MessageItem.js";
|
|
109
5
|
|
|
110
6
|
export interface MessageListProps {
|
|
111
7
|
messages: Message[];
|
|
@@ -116,109 +12,153 @@ export interface MessageListProps {
|
|
|
116
12
|
isExpanded?: boolean;
|
|
117
13
|
}
|
|
118
14
|
|
|
119
|
-
export const MessageList
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
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
|
+
: [];
|
|
139
53
|
|
|
140
|
-
// Empty message state
|
|
141
|
-
if (messages.length === 0) {
|
|
142
54
|
return (
|
|
143
|
-
<Box flexDirection="column"
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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;
|
|
155
87
|
const previousMessage =
|
|
156
|
-
|
|
157
|
-
return
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
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>
|
|
162
98
|
);
|
|
163
99
|
})}
|
|
164
|
-
</Box>
|
|
165
100
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
)}
|
|
192
|
-
{isCommandRunning && (
|
|
193
|
-
<Text color="blue">🚀 Command is running...</Text>
|
|
194
|
-
)}
|
|
195
|
-
{isCompressing && (
|
|
196
|
-
<Text color="magenta">🗜️ Compressing message history...</Text>
|
|
197
|
-
)}
|
|
198
|
-
</Box>
|
|
199
|
-
)}
|
|
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
|
+
)}
|
|
200
126
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
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>
|
|
210
151
|
<Text color="gray" dimColor>
|
|
211
|
-
{" "}
|
|
212
|
-
|
|
152
|
+
<Text color="cyan">Ctrl+O</Text> Toggle{" "}
|
|
153
|
+
{isExpanded ? "Collapse" : "Expand"}
|
|
213
154
|
</Text>
|
|
214
155
|
</Box>
|
|
215
|
-
<Text color="gray" dimColor>
|
|
216
|
-
<Text color="cyan">Ctrl+O</Text> Toggle{" "}
|
|
217
|
-
{isExpanded ? "Collapse" : "Expand"}
|
|
218
|
-
</Text>
|
|
219
156
|
</Box>
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
157
|
+
)}
|
|
158
|
+
</Box>
|
|
159
|
+
);
|
|
160
|
+
},
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
// Add display name for debugging
|
|
164
|
+
MessageList.displayName = "MessageList";
|
|
@@ -1,57 +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";
|
|
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
|
-
const truncateText = (text: string, maxLines: number): string => {
|
|
21
|
-
const lines = text.split("\n");
|
|
22
|
-
if (lines.length <= maxLines) {
|
|
23
|
-
return text;
|
|
24
|
-
}
|
|
25
|
-
return lines.slice(0, maxLines).join("\n") + "\n...";
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
switch (block.type) {
|
|
29
|
-
case "text": {
|
|
30
|
-
const maxLines = isExpanded ? 50 : 10;
|
|
31
|
-
const truncatedContent = truncateText(block.content, maxLines);
|
|
32
|
-
return <Text>{truncatedContent}</Text>;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
case "error":
|
|
36
|
-
return <Text color="red">❌ Error: {block.content}</Text>;
|
|
37
|
-
|
|
38
|
-
case "tool":
|
|
39
|
-
return <ToolResultDisplay block={block} isExpanded={isExpanded} />;
|
|
40
|
-
|
|
41
|
-
default:
|
|
42
|
-
return null;
|
|
43
|
-
}
|
|
44
|
-
};
|
|
3
|
+
import type { SubagentBlock as SubagentBlockType } from "wave-agent-sdk";
|
|
4
|
+
import { useChat } from "../contexts/useChat.js";
|
|
45
5
|
|
|
46
6
|
interface SubagentBlockProps {
|
|
47
7
|
block: SubagentBlockType;
|
|
48
|
-
isExpanded?: boolean;
|
|
49
8
|
}
|
|
50
9
|
|
|
51
|
-
export const SubagentBlock: React.FC<SubagentBlockProps> = ({
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
+
|
|
55
16
|
// Status indicator mapping
|
|
56
17
|
const getStatusIndicator = (status: SubagentBlockType["status"]) => {
|
|
57
18
|
switch (status) {
|
|
@@ -70,14 +31,40 @@ export const SubagentBlock: React.FC<SubagentBlockProps> = ({
|
|
|
70
31
|
|
|
71
32
|
const statusInfo = getStatusIndicator(block.status);
|
|
72
33
|
|
|
73
|
-
//
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
:
|
|
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();
|
|
77
61
|
|
|
78
62
|
return (
|
|
79
63
|
<Box
|
|
80
|
-
|
|
64
|
+
borderRight={false}
|
|
65
|
+
borderTop={false}
|
|
66
|
+
borderBottom={false}
|
|
67
|
+
borderStyle="classic"
|
|
81
68
|
borderColor="magenta"
|
|
82
69
|
paddingX={1}
|
|
83
70
|
paddingY={0}
|
|
@@ -85,54 +72,39 @@ export const SubagentBlock: React.FC<SubagentBlockProps> = ({
|
|
|
85
72
|
marginBottom={1}
|
|
86
73
|
>
|
|
87
74
|
{/* Header Section */}
|
|
88
|
-
<Box
|
|
89
|
-
flexDirection="row"
|
|
90
|
-
justifyContent="space-between"
|
|
91
|
-
alignItems="center"
|
|
92
|
-
>
|
|
75
|
+
<Box flexDirection="row" gap={1}>
|
|
93
76
|
<Box flexDirection="row" alignItems="center">
|
|
94
77
|
<Text color="cyan">🤖 {block.subagentName}</Text>
|
|
95
78
|
<Text color={statusInfo.color} dimColor={false}>
|
|
96
79
|
{" "}
|
|
97
80
|
{statusInfo.icon}
|
|
98
81
|
</Text>
|
|
99
|
-
</Box>
|
|
100
|
-
|
|
101
|
-
{!isExpanded && (
|
|
102
82
|
<Text color="gray" dimColor>
|
|
103
|
-
{
|
|
83
|
+
{" "}
|
|
84
|
+
({messages.length} messages)
|
|
104
85
|
</Text>
|
|
105
|
-
|
|
86
|
+
</Box>
|
|
106
87
|
</Box>
|
|
107
88
|
|
|
108
|
-
{/*
|
|
109
|
-
{
|
|
89
|
+
{/* Tool Names Section - Vertical List */}
|
|
90
|
+
{lastTwoTools.length > 0 && (
|
|
110
91
|
<Box flexDirection="column" marginTop={1} gap={1}>
|
|
111
|
-
{
|
|
112
|
-
<
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
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>
|
|
122
103
|
)}
|
|
123
104
|
</Box>
|
|
124
105
|
))}
|
|
125
106
|
</Box>
|
|
126
107
|
)}
|
|
127
|
-
|
|
128
|
-
{/* Show truncation indicator if there are more messages */}
|
|
129
|
-
{!isExpanded && block.messages.length > 2 && (
|
|
130
|
-
<Box marginTop={1}>
|
|
131
|
-
<Text color="gray" dimColor>
|
|
132
|
-
... and {block.messages.length - 2} more messages (Ctrl+O to expand)
|
|
133
|
-
</Text>
|
|
134
|
-
</Box>
|
|
135
|
-
)}
|
|
136
108
|
</Box>
|
|
137
109
|
);
|
|
138
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 */}
|
package/src/contexts/useChat.tsx
CHANGED
|
@@ -13,7 +13,6 @@ import type {
|
|
|
13
13
|
McpServerStatus,
|
|
14
14
|
BackgroundShell,
|
|
15
15
|
SlashCommand,
|
|
16
|
-
Usage,
|
|
17
16
|
} from "wave-agent-sdk";
|
|
18
17
|
import { Agent, AgentCallbacks } from "wave-agent-sdk";
|
|
19
18
|
import { logger } from "../utils/logger.js";
|
|
@@ -51,8 +50,8 @@ export interface ChatContextType {
|
|
|
51
50
|
// Slash Command functionality
|
|
52
51
|
slashCommands: SlashCommand[];
|
|
53
52
|
hasSlashCommand: (commandId: string) => boolean;
|
|
54
|
-
//
|
|
55
|
-
|
|
53
|
+
// Subagent messages
|
|
54
|
+
subagentMessages: Record<string, Message[]>;
|
|
56
55
|
}
|
|
57
56
|
|
|
58
57
|
const ChatContext = createContext<ChatContextType | null>(null);
|
|
@@ -95,15 +94,23 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({ children }) => {
|
|
|
95
94
|
// Command state
|
|
96
95
|
const [slashCommands, setSlashCommands] = useState<SlashCommand[]>([]);
|
|
97
96
|
|
|
98
|
-
//
|
|
99
|
-
const [
|
|
97
|
+
// Subagent messages state
|
|
98
|
+
const [subagentMessages, setSubagentMessages] = useState<
|
|
99
|
+
Record<string, Message[]>
|
|
100
|
+
>({});
|
|
100
101
|
|
|
101
102
|
const agentRef = useRef<Agent | null>(null);
|
|
102
103
|
|
|
103
104
|
// Listen for Ctrl+O hotkey to toggle collapse/expand state
|
|
104
105
|
useInput((input, key) => {
|
|
105
106
|
if (key.ctrl && input === "o") {
|
|
106
|
-
|
|
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
|
+
});
|
|
107
114
|
}
|
|
108
115
|
});
|
|
109
116
|
|
|
@@ -118,7 +125,9 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({ children }) => {
|
|
|
118
125
|
setMcpServers([...servers]);
|
|
119
126
|
},
|
|
120
127
|
onSessionIdChange: (sessionId) => {
|
|
121
|
-
|
|
128
|
+
process.stdout.write("\x1Bc", () => {
|
|
129
|
+
setSessionId(sessionId);
|
|
130
|
+
});
|
|
122
131
|
},
|
|
123
132
|
onLatestTotalTokensChange: (tokens) => {
|
|
124
133
|
setlatestTotalTokens(tokens);
|
|
@@ -132,8 +141,11 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({ children }) => {
|
|
|
132
141
|
onShellsChange: (shells) => {
|
|
133
142
|
setBackgroundShells([...shells]);
|
|
134
143
|
},
|
|
135
|
-
|
|
136
|
-
|
|
144
|
+
onSubagentMessagesChange: (subagentId, messages) => {
|
|
145
|
+
setSubagentMessages((prev) => ({
|
|
146
|
+
...prev,
|
|
147
|
+
[subagentId]: [...messages],
|
|
148
|
+
}));
|
|
137
149
|
},
|
|
138
150
|
};
|
|
139
151
|
|
|
@@ -163,9 +175,6 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({ children }) => {
|
|
|
163
175
|
// Get initial commands
|
|
164
176
|
const agentSlashCommands = agent.getSlashCommands?.() || [];
|
|
165
177
|
setSlashCommands(agentSlashCommands);
|
|
166
|
-
|
|
167
|
-
// Get initial usages
|
|
168
|
-
setUsages(agent.usages);
|
|
169
178
|
} catch (error) {
|
|
170
179
|
console.error("Failed to initialize AI manager:", error);
|
|
171
180
|
}
|
|
@@ -314,7 +323,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({ children }) => {
|
|
|
314
323
|
killBackgroundShell,
|
|
315
324
|
slashCommands,
|
|
316
325
|
hasSlashCommand,
|
|
317
|
-
|
|
326
|
+
subagentMessages,
|
|
318
327
|
};
|
|
319
328
|
|
|
320
329
|
return (
|