wave-code 1.0.0 → 1.0.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/dist/cli.js +20 -1
- package/dist/components/App.js +7 -0
- package/dist/components/BtwDisplay.js +13 -3
- package/dist/components/ChatInterface.js +21 -6
- package/dist/components/InputBox.d.ts +0 -3
- package/dist/components/InputBox.js +11 -9
- package/dist/components/LoadingIndicator.d.ts +1 -2
- package/dist/components/LoadingIndicator.js +2 -2
- package/dist/components/Markdown.js +13 -16
- package/dist/components/MessageList.d.ts +2 -1
- package/dist/components/MessageList.js +2 -2
- package/dist/components/StatusLine.d.ts +0 -2
- package/dist/components/StatusLine.js +6 -6
- package/dist/components/TaskList.js +2 -1
- package/dist/components/ToolDisplay.d.ts +1 -0
- package/dist/components/ToolDisplay.js +17 -9
- package/dist/constants/commands.js +0 -6
- package/dist/contexts/useChat.d.ts +3 -5
- package/dist/contexts/useChat.js +242 -82
- package/dist/daemon-cli.d.ts +10 -0
- package/dist/daemon-cli.js +15 -0
- package/dist/hooks/useInputManager.js +99 -22
- package/dist/index.js +10 -0
- package/dist/managers/inputHandlers.js +50 -22
- package/dist/managers/inputReducer.d.ts +12 -2
- package/dist/managers/inputReducer.js +57 -9
- package/dist/stdio/agentBridge.d.ts +23 -0
- package/dist/stdio/agentBridge.js +126 -16
- package/dist/stdio/daemonServer.d.ts +67 -0
- package/dist/stdio/daemonServer.js +191 -0
- package/dist/stdio/index.d.ts +2 -0
- package/dist/stdio/index.js +2 -0
- package/dist/stdio/jsonRpcConnection.d.ts +30 -0
- package/dist/stdio/jsonRpcConnection.js +127 -0
- package/dist/stdio/protocol.d.ts +2 -2
- package/dist/stdio/stdioServer.d.ts +2 -7
- package/dist/stdio/stdioServer.js +9 -100
- package/dist/utils/bracketedPaste.d.ts +39 -0
- package/dist/utils/bracketedPaste.js +122 -0
- package/dist/utils/markdownTable.d.ts +34 -0
- package/dist/utils/markdownTable.js +302 -0
- package/dist/utils/throttle.d.ts +3 -3
- package/package.json +4 -2
- package/src/cli.tsx +20 -1
- package/src/components/App.tsx +5 -0
- package/src/components/BtwDisplay.tsx +36 -12
- package/src/components/ChatInterface.tsx +25 -12
- package/src/components/InputBox.tsx +10 -18
- package/src/components/LoadingIndicator.tsx +1 -4
- package/src/components/Markdown.tsx +15 -18
- package/src/components/MessageList.tsx +6 -0
- package/src/components/StatusLine.tsx +0 -10
- package/src/components/TaskList.tsx +2 -1
- package/src/components/ToolDisplay.tsx +17 -6
- package/src/constants/commands.ts +0 -6
- package/src/contexts/useChat.tsx +310 -95
- package/src/daemon-cli.ts +17 -0
- package/src/hooks/useInputManager.ts +108 -22
- package/src/index.ts +12 -0
- package/src/managers/inputHandlers.ts +49 -22
- package/src/managers/inputReducer.ts +66 -11
- package/src/stdio/agentBridge.ts +188 -17
- package/src/stdio/daemonServer.ts +212 -0
- package/src/stdio/index.ts +2 -0
- package/src/stdio/jsonRpcConnection.ts +160 -0
- package/src/stdio/protocol.ts +5 -2
- package/src/stdio/stdioServer.ts +14 -120
- package/src/utils/bracketedPaste.ts +170 -0
- package/src/utils/markdownTable.ts +359 -0
- package/src/utils/throttle.ts +8 -8
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import React, { useState, useRef, useEffect } from "react";
|
|
1
|
+
import React, { useState, useRef, useEffect, useCallback } from "react";
|
|
2
2
|
import { Box, useStdout, measureElement, Static } from "ink";
|
|
3
3
|
import type { DOMElement } from "ink";
|
|
4
|
+
import { authService } from "wave-agent-sdk";
|
|
4
5
|
import { MessageList } from "./MessageList.js";
|
|
5
6
|
import { InputBox } from "./InputBox.js";
|
|
6
7
|
import { LoadingIndicator } from "./LoadingIndicator.js";
|
|
@@ -37,9 +38,7 @@ export const ChatInterface: React.FC = () => {
|
|
|
37
38
|
workdir,
|
|
38
39
|
remountKey,
|
|
39
40
|
requestRemount,
|
|
40
|
-
|
|
41
|
-
goalElapsed,
|
|
42
|
-
isGoalEvaluating,
|
|
41
|
+
getGatewayConfig,
|
|
43
42
|
} = useChat();
|
|
44
43
|
|
|
45
44
|
const displayMessages = messages;
|
|
@@ -49,6 +48,26 @@ export const ChatInterface: React.FC = () => {
|
|
|
49
48
|
const terminalHeight = stdout?.rows ?? 24;
|
|
50
49
|
const chatInterfaceRef = useRef<DOMElement>(null);
|
|
51
50
|
|
|
51
|
+
// Compute whether the user has any usable auth/direct-API config,
|
|
52
|
+
// so the welcome page can prompt /login when neither is present.
|
|
53
|
+
const computeAuthState = useCallback((): boolean => {
|
|
54
|
+
if (authService.isSSOAuthenticated()) return true;
|
|
55
|
+
const gateway = getGatewayConfig();
|
|
56
|
+
return Boolean(gateway.apiKey || gateway.baseURL);
|
|
57
|
+
}, [getGatewayConfig]);
|
|
58
|
+
|
|
59
|
+
const [hasAuth, setHasAuth] = useState<boolean>(computeAuthState);
|
|
60
|
+
|
|
61
|
+
// Keep the /login hint in sync with auth state changes (login/logout).
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
const unsubscribe = authService.onAuthChange(() => {
|
|
64
|
+
setHasAuth(computeAuthState());
|
|
65
|
+
});
|
|
66
|
+
return unsubscribe;
|
|
67
|
+
}, [computeAuthState]);
|
|
68
|
+
|
|
69
|
+
const showLoginHint = !hasAuth;
|
|
70
|
+
|
|
52
71
|
// Handle forceStatic mode for overflow and request remount when exiting
|
|
53
72
|
useEffect(() => {
|
|
54
73
|
if (isConfirmationVisible && chatInterfaceRef.current) {
|
|
@@ -79,19 +98,16 @@ export const ChatInterface: React.FC = () => {
|
|
|
79
98
|
version={version}
|
|
80
99
|
workdir={workdir}
|
|
81
100
|
forceStatic={forceStatic}
|
|
101
|
+
showLoginHint={showLoginHint}
|
|
82
102
|
/>
|
|
83
103
|
|
|
84
104
|
{!isConfirmationVisible && !isExpanded && (
|
|
85
105
|
<>
|
|
86
|
-
{(isLoading ||
|
|
87
|
-
isCommandRunning ||
|
|
88
|
-
isCompacting ||
|
|
89
|
-
isGoalEvaluating) && (
|
|
106
|
+
{(isLoading || isCommandRunning || isCompacting) && (
|
|
90
107
|
<LoadingIndicator
|
|
91
108
|
isLoading={isLoading}
|
|
92
109
|
isCommandRunning={isCommandRunning}
|
|
93
110
|
isCompacting={isCompacting}
|
|
94
|
-
isGoalEvaluating={isGoalEvaluating}
|
|
95
111
|
latestTotalTokens={latestTotalTokens}
|
|
96
112
|
/>
|
|
97
113
|
)}
|
|
@@ -101,7 +117,6 @@ export const ChatInterface: React.FC = () => {
|
|
|
101
117
|
isLoading={isLoading}
|
|
102
118
|
isCommandRunning={isCommandRunning}
|
|
103
119
|
isCompacting={isCompacting}
|
|
104
|
-
isGoalEvaluating={isGoalEvaluating}
|
|
105
120
|
sendMessage={sendMessage}
|
|
106
121
|
abortMessage={abortMessage}
|
|
107
122
|
mcpServers={mcpServers}
|
|
@@ -111,8 +126,6 @@ export const ChatInterface: React.FC = () => {
|
|
|
111
126
|
hasSlashCommand={hasSlashCommand}
|
|
112
127
|
latestTotalTokens={latestTotalTokens}
|
|
113
128
|
maxInputTokens={maxInputTokens}
|
|
114
|
-
isGoalActive={isGoalActive}
|
|
115
|
-
goalElapsed={goalElapsed}
|
|
116
129
|
/>
|
|
117
130
|
</>
|
|
118
131
|
)}
|
|
@@ -32,7 +32,6 @@ export interface InputBoxProps {
|
|
|
32
32
|
isLoading?: boolean;
|
|
33
33
|
isCommandRunning?: boolean;
|
|
34
34
|
isCompacting?: boolean;
|
|
35
|
-
isGoalEvaluating?: boolean;
|
|
36
35
|
workdir?: string;
|
|
37
36
|
sendMessage?: (
|
|
38
37
|
message: string,
|
|
@@ -50,16 +49,12 @@ export interface InputBoxProps {
|
|
|
50
49
|
// Token usage
|
|
51
50
|
latestTotalTokens?: number;
|
|
52
51
|
maxInputTokens?: number;
|
|
53
|
-
// Goal state
|
|
54
|
-
isGoalActive?: boolean;
|
|
55
|
-
goalElapsed?: string;
|
|
56
52
|
}
|
|
57
53
|
|
|
58
54
|
export const InputBox: React.FC<InputBoxProps> = ({
|
|
59
55
|
isLoading,
|
|
60
56
|
isCommandRunning,
|
|
61
57
|
isCompacting,
|
|
62
|
-
isGoalEvaluating,
|
|
63
58
|
sendMessage = () => {},
|
|
64
59
|
abortMessage = () => {},
|
|
65
60
|
mcpServers = [],
|
|
@@ -69,8 +64,6 @@ export const InputBox: React.FC<InputBoxProps> = ({
|
|
|
69
64
|
hasSlashCommand = () => false,
|
|
70
65
|
latestTotalTokens = 0,
|
|
71
66
|
maxInputTokens = 200000,
|
|
72
|
-
isGoalActive,
|
|
73
|
-
goalElapsed,
|
|
74
67
|
}) => {
|
|
75
68
|
const {
|
|
76
69
|
permissionMode: chatPermissionMode,
|
|
@@ -84,13 +77,13 @@ export const InputBox: React.FC<InputBoxProps> = ({
|
|
|
84
77
|
askBtw,
|
|
85
78
|
clearMessages,
|
|
86
79
|
compact,
|
|
87
|
-
goalCommand,
|
|
88
80
|
currentModel,
|
|
89
81
|
configuredModels,
|
|
90
82
|
setModel,
|
|
91
83
|
recreateAgent,
|
|
92
84
|
recallQueuedMessage,
|
|
93
85
|
queuedMessages,
|
|
86
|
+
setIsBtwActive,
|
|
94
87
|
} = useChat();
|
|
95
88
|
|
|
96
89
|
// Ref to hold setInputText so queue callbacks can access it before useInputManager returns
|
|
@@ -100,12 +93,7 @@ export const InputBox: React.FC<InputBoxProps> = ({
|
|
|
100
93
|
|
|
101
94
|
// Idle means no AI work in flight. Esc double-press clear only applies when
|
|
102
95
|
// idle; while busy, Esc keeps its abort semantics.
|
|
103
|
-
const isIdle = !(
|
|
104
|
-
isLoading ||
|
|
105
|
-
isCommandRunning ||
|
|
106
|
-
isCompacting ||
|
|
107
|
-
isGoalEvaluating
|
|
108
|
-
);
|
|
96
|
+
const isIdle = !(isLoading || isCommandRunning || isCompacting);
|
|
109
97
|
|
|
110
98
|
const onRecallQueuedMessage = useCallback(() => {
|
|
111
99
|
const msg = recallQueuedMessage();
|
|
@@ -174,7 +162,6 @@ export const InputBox: React.FC<InputBoxProps> = ({
|
|
|
174
162
|
onAskBtw: askBtw,
|
|
175
163
|
onClearMessages: clearMessages,
|
|
176
164
|
onCompact: compact,
|
|
177
|
-
onGoalCommand: goalCommand,
|
|
178
165
|
onHasSlashCommand: hasSlashCommand,
|
|
179
166
|
onAbortMessage: abortMessage,
|
|
180
167
|
onBackgroundCurrentTask: backgroundCurrentTask,
|
|
@@ -192,6 +179,13 @@ export const InputBox: React.FC<InputBoxProps> = ({
|
|
|
192
179
|
setInputTextRef.current = setInputText;
|
|
193
180
|
}, [setInputText]);
|
|
194
181
|
|
|
182
|
+
// Sync the btw overlay's visibility to ChatContext so siblings (TaskList)
|
|
183
|
+
// can hide while the side-question is on display (aligned with Claude Code,
|
|
184
|
+
// which suppresses the expanded task list while a local-jsx command shows).
|
|
185
|
+
useEffect(() => {
|
|
186
|
+
setIsBtwActive(btwState.question !== "" || btwState.answer !== undefined);
|
|
187
|
+
}, [btwState.question, btwState.answer, setIsBtwActive]);
|
|
188
|
+
|
|
195
189
|
// Sync permission mode from useChat to InputManager
|
|
196
190
|
useEffect(() => {
|
|
197
191
|
setPermissionMode(chatPermissionMode);
|
|
@@ -349,7 +343,7 @@ export const InputBox: React.FC<InputBoxProps> = ({
|
|
|
349
343
|
<WorkflowManager onCancel={() => setShowWorkflowManager(false)} />
|
|
350
344
|
)}
|
|
351
345
|
|
|
352
|
-
{btwState.question
|
|
346
|
+
{btwState.question || btwState.answer
|
|
353
347
|
? null
|
|
354
348
|
: showBackgroundTaskManager ||
|
|
355
349
|
showMcpManager ||
|
|
@@ -384,8 +378,6 @@ export const InputBox: React.FC<InputBoxProps> = ({
|
|
|
384
378
|
<StatusLine
|
|
385
379
|
permissionMode={permissionMode}
|
|
386
380
|
isShellCommand={isShellCommand}
|
|
387
|
-
isGoalActive={isGoalActive}
|
|
388
|
-
goalElapsed={goalElapsed}
|
|
389
381
|
latestTotalTokens={latestTotalTokens}
|
|
390
382
|
maxInputTokens={maxInputTokens}
|
|
391
383
|
/>
|
|
@@ -5,7 +5,6 @@ export interface LoadingIndicatorProps {
|
|
|
5
5
|
isLoading?: boolean;
|
|
6
6
|
isCommandRunning?: boolean;
|
|
7
7
|
isCompacting?: boolean;
|
|
8
|
-
isGoalEvaluating?: boolean;
|
|
9
8
|
latestTotalTokens?: number;
|
|
10
9
|
}
|
|
11
10
|
|
|
@@ -13,12 +12,11 @@ export const LoadingIndicator = ({
|
|
|
13
12
|
isLoading = false,
|
|
14
13
|
isCommandRunning = false,
|
|
15
14
|
isCompacting = false,
|
|
16
|
-
isGoalEvaluating = false,
|
|
17
15
|
latestTotalTokens = 0,
|
|
18
16
|
}: LoadingIndicatorProps) => {
|
|
19
17
|
return (
|
|
20
18
|
<Box flexDirection="column">
|
|
21
|
-
{isLoading && !isCompacting &&
|
|
19
|
+
{isLoading && !isCompacting && (
|
|
22
20
|
<Box>
|
|
23
21
|
<Text color="yellow">✻ AI is thinking... </Text>
|
|
24
22
|
{latestTotalTokens > 0 && (
|
|
@@ -51,7 +49,6 @@ export const LoadingIndicator = ({
|
|
|
51
49
|
{isCompacting && (
|
|
52
50
|
<Text color="magenta">✻ Compacting message history...</Text>
|
|
53
51
|
)}
|
|
54
|
-
{isGoalEvaluating && <Text color="cyan">✻ Evaluating goal...</Text>}
|
|
55
52
|
</Box>
|
|
56
53
|
);
|
|
57
54
|
};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import React, { useMemo } from "react";
|
|
2
|
-
import { Box, Text } from "ink";
|
|
2
|
+
import { Box, Text, useStdout } from "ink";
|
|
3
3
|
import { Renderer, marked, type Tokens } from "marked";
|
|
4
4
|
import chalk from "chalk";
|
|
5
5
|
import { highlightToAnsi } from "../utils/highlightUtils.js";
|
|
6
|
+
import { renderMarkdownTable } from "../utils/markdownTable.js";
|
|
6
7
|
|
|
7
8
|
export interface MarkdownProps {
|
|
8
9
|
children: string;
|
|
@@ -19,6 +20,10 @@ const unescapeHtml = (html: string) => {
|
|
|
19
20
|
};
|
|
20
21
|
|
|
21
22
|
class AnsiRenderer extends Renderer<string> {
|
|
23
|
+
constructor(private readonly columns: number) {
|
|
24
|
+
super();
|
|
25
|
+
}
|
|
26
|
+
|
|
22
27
|
override code({ text, lang }: Tokens.Code): string {
|
|
23
28
|
const prefix = lang ? `\`\`\`${lang}` : "```";
|
|
24
29
|
const suffix = "```";
|
|
@@ -82,20 +87,10 @@ class AnsiRenderer extends Renderer<string> {
|
|
|
82
87
|
}
|
|
83
88
|
|
|
84
89
|
override table(token: Tokens.Table): string {
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
return `\n${header}\n${body}\n`;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
override tablerow({ text }: Tokens.TableRow): string {
|
|
93
|
-
return text + "\n";
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
override tablecell(token: Tokens.TableCell): string {
|
|
97
|
-
const text = token.header ? chalk.bold(token.text) : token.text;
|
|
98
|
-
return text + " | ";
|
|
90
|
+
const table = renderMarkdownTable(token, this.columns, (tokens) =>
|
|
91
|
+
this.parser.parseInline(tokens),
|
|
92
|
+
);
|
|
93
|
+
return `\n${table}\n`;
|
|
99
94
|
}
|
|
100
95
|
|
|
101
96
|
override strong({ tokens }: Tokens.Strong): string {
|
|
@@ -140,17 +135,19 @@ class AnsiRenderer extends Renderer<string> {
|
|
|
140
135
|
}
|
|
141
136
|
}
|
|
142
137
|
|
|
143
|
-
const
|
|
138
|
+
const createRenderer = (columns: number) => new AnsiRenderer(columns);
|
|
144
139
|
|
|
145
140
|
// Markdown component using custom ANSI renderer
|
|
146
141
|
export const Markdown = React.memo(({ children }: MarkdownProps) => {
|
|
142
|
+
const { stdout } = useStdout();
|
|
143
|
+
const columns = stdout?.columns ?? 80;
|
|
147
144
|
const ansiContent = useMemo(() => {
|
|
148
145
|
return marked.parse(children, {
|
|
149
|
-
renderer,
|
|
146
|
+
renderer: createRenderer(columns),
|
|
150
147
|
gfm: true,
|
|
151
148
|
breaks: true,
|
|
152
149
|
}) as string;
|
|
153
|
-
}, [children]);
|
|
150
|
+
}, [children, columns]);
|
|
154
151
|
|
|
155
152
|
return (
|
|
156
153
|
<Box flexDirection="column">
|
|
@@ -13,6 +13,7 @@ export interface MessageListProps {
|
|
|
13
13
|
forceStatic?: boolean;
|
|
14
14
|
version?: string;
|
|
15
15
|
workdir?: string;
|
|
16
|
+
showLoginHint?: boolean;
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
export const MessageList = React.memo(
|
|
@@ -22,6 +23,7 @@ export const MessageList = React.memo(
|
|
|
22
23
|
forceStatic = false,
|
|
23
24
|
version,
|
|
24
25
|
workdir,
|
|
26
|
+
showLoginHint = false,
|
|
25
27
|
}: MessageListProps) => {
|
|
26
28
|
const maxMessages = isExpanded
|
|
27
29
|
? MAX_MESSAGES_EXPANDED
|
|
@@ -135,6 +137,10 @@ export const MessageList = React.memo(
|
|
|
135
137
|
</Static>
|
|
136
138
|
)}
|
|
137
139
|
|
|
140
|
+
{/* Login hint — rendered in the dynamic area (not Static) so it can
|
|
141
|
+
disappear in real time when the user authenticates. */}
|
|
142
|
+
{showLoginHint && <Text color="gray">Type /login to authenticate</Text>}
|
|
143
|
+
|
|
138
144
|
{/* Dynamic blocks */}
|
|
139
145
|
{dynamicBlocks.length > 0 && (
|
|
140
146
|
<Box flexDirection="column">
|
|
@@ -4,8 +4,6 @@ import { Box, Text } from "ink";
|
|
|
4
4
|
export interface StatusLineProps {
|
|
5
5
|
permissionMode: string;
|
|
6
6
|
isShellCommand: boolean;
|
|
7
|
-
isGoalActive?: boolean;
|
|
8
|
-
goalElapsed?: string;
|
|
9
7
|
latestTotalTokens?: number;
|
|
10
8
|
maxInputTokens?: number;
|
|
11
9
|
}
|
|
@@ -13,8 +11,6 @@ export interface StatusLineProps {
|
|
|
13
11
|
export const StatusLine: React.FC<StatusLineProps> = ({
|
|
14
12
|
permissionMode,
|
|
15
13
|
isShellCommand,
|
|
16
|
-
isGoalActive,
|
|
17
|
-
goalElapsed,
|
|
18
14
|
latestTotalTokens = 0,
|
|
19
15
|
maxInputTokens = 200000,
|
|
20
16
|
}) => {
|
|
@@ -34,12 +30,6 @@ export const StatusLine: React.FC<StatusLineProps> = ({
|
|
|
34
30
|
</Text>
|
|
35
31
|
) : (
|
|
36
32
|
<Box>
|
|
37
|
-
{isGoalActive && (
|
|
38
|
-
<Text color="gray">
|
|
39
|
-
<Text color="cyan">◎ /goal</Text> active{" "}
|
|
40
|
-
{goalElapsed && <Text>({goalElapsed})</Text>} |{" "}
|
|
41
|
-
</Text>
|
|
42
|
-
)}
|
|
43
33
|
<Text color="gray">
|
|
44
34
|
Mode:{" "}
|
|
45
35
|
<Text
|
|
@@ -91,7 +91,7 @@ function getDisplayLimit(rows: number | undefined): number {
|
|
|
91
91
|
|
|
92
92
|
export const TaskList: React.FC = () => {
|
|
93
93
|
const tasks = useTasks();
|
|
94
|
-
const { isTaskListVisible } = useChat();
|
|
94
|
+
const { isTaskListVisible, isBtwActive } = useChat();
|
|
95
95
|
const { stdout } = useStdout();
|
|
96
96
|
|
|
97
97
|
const completionTimestampsRef = React.useRef<Map<string, number>>(new Map());
|
|
@@ -188,6 +188,7 @@ export const TaskList: React.FC = () => {
|
|
|
188
188
|
if (
|
|
189
189
|
tasks.length === 0 ||
|
|
190
190
|
!isTaskListVisible ||
|
|
191
|
+
isBtwActive ||
|
|
191
192
|
autoHidden ||
|
|
192
193
|
(allCompleted && !hadIncompleteRef.current)
|
|
193
194
|
) {
|
|
@@ -9,6 +9,22 @@ interface ToolDisplayProps {
|
|
|
9
9
|
isExpanded?: boolean;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
// Status dot color for a tool block. In-flight stages (start/streaming/running)
|
|
13
|
+
// never show red — the outcome isn't known until the tool reaches "end".
|
|
14
|
+
// An explicit error overrides everything.
|
|
15
|
+
export const getToolStatusColor = (
|
|
16
|
+
stage: ToolBlock["stage"],
|
|
17
|
+
success?: boolean,
|
|
18
|
+
error?: string | Error,
|
|
19
|
+
): string => {
|
|
20
|
+
if (error) return "red";
|
|
21
|
+
if (stage === "start" || stage === "streaming") return "gray";
|
|
22
|
+
if (stage === "running") return "yellow";
|
|
23
|
+
if (success) return "green";
|
|
24
|
+
if (success === false) return "red";
|
|
25
|
+
return "gray"; // Unknown state or no state information
|
|
26
|
+
};
|
|
27
|
+
|
|
12
28
|
export const ToolDisplay: React.FC<ToolDisplayProps> = ({
|
|
13
29
|
block,
|
|
14
30
|
isExpanded = false,
|
|
@@ -19,12 +35,7 @@ export const ToolDisplay: React.FC<ToolDisplayProps> = ({
|
|
|
19
35
|
// Directly use compactParams
|
|
20
36
|
// (no change needed as we destructured it above)
|
|
21
37
|
|
|
22
|
-
const getStatusColor = () =>
|
|
23
|
-
if (stage === "running") return "yellow";
|
|
24
|
-
if (success) return "green";
|
|
25
|
-
if (error || success === false) return "red";
|
|
26
|
-
return "gray"; // Unknown state or no state information
|
|
27
|
-
};
|
|
38
|
+
const getStatusColor = () => getToolStatusColor(stage, success, error);
|
|
28
39
|
|
|
29
40
|
const hasImages = () => {
|
|
30
41
|
return block.images && block.images.length > 0;
|
|
@@ -80,10 +80,4 @@ export const AVAILABLE_COMMANDS: SlashCommand[] = [
|
|
|
80
80
|
description: "Compact conversation history to reduce context usage",
|
|
81
81
|
handler: () => {},
|
|
82
82
|
},
|
|
83
|
-
{
|
|
84
|
-
id: "goal",
|
|
85
|
-
name: "goal",
|
|
86
|
-
description: "Set, check, or clear an autonomous goal for the session",
|
|
87
|
-
handler: () => {},
|
|
88
|
-
},
|
|
89
83
|
];
|