hoomanjs 1.29.2 → 1.30.0
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 +216 -69
- package/dist/acp/acp-agent.d.ts +5 -5
- package/dist/acp/acp-agent.js +55 -54
- package/dist/acp/acp-agent.js.map +1 -1
- package/dist/acp/approvals.d.ts +3 -3
- package/dist/acp/approvals.js +73 -115
- package/dist/acp/approvals.js.map +1 -1
- package/dist/acp/sessions/options.js +11 -25
- package/dist/acp/sessions/options.js.map +1 -1
- package/dist/acp/utils/tool-kind.js +1 -5
- package/dist/acp/utils/tool-kind.js.map +1 -1
- package/dist/chat/app.d.ts +5 -1
- package/dist/chat/app.js +322 -202
- package/dist/chat/app.js.map +1 -1
- package/dist/chat/approvals.d.ts +4 -3
- package/dist/chat/approvals.js +11 -45
- package/dist/chat/approvals.js.map +1 -1
- package/dist/chat/components/ChatMessage.d.ts +1 -2
- package/dist/chat/components/ChatMessage.js +4 -5
- package/dist/chat/components/ChatMessage.js.map +1 -1
- package/dist/chat/components/EmptyChatBanner.js +2 -3
- package/dist/chat/components/EmptyChatBanner.js.map +1 -1
- package/dist/chat/components/StatusBar.js +6 -2
- package/dist/chat/components/StatusBar.js.map +1 -1
- package/dist/chat/components/ThoughtEvent.d.ts +6 -0
- package/dist/chat/components/ThoughtEvent.js +30 -0
- package/dist/chat/components/ThoughtEvent.js.map +1 -0
- package/dist/chat/components/ToolEvent.js +1 -1
- package/dist/chat/components/ToolEvent.js.map +1 -1
- package/dist/chat/components/Transcript.d.ts +7 -2
- package/dist/chat/components/Transcript.js +6 -2
- package/dist/chat/components/Transcript.js.map +1 -1
- package/dist/chat/components/markdown/BlockRenderer.js +7 -7
- package/dist/chat/components/markdown/BlockRenderer.js.map +1 -1
- package/dist/chat/components/markdown/MarkdownMessage.js +1 -1
- package/dist/chat/components/markdown/MarkdownMessage.js.map +1 -1
- package/dist/chat/components/shared.js +2 -0
- package/dist/chat/components/shared.js.map +1 -1
- package/dist/chat/index.d.ts +4 -0
- package/dist/chat/index.js +17 -3
- package/dist/chat/index.js.map +1 -1
- package/dist/chat/steering.d.ts +20 -0
- package/dist/chat/steering.js +67 -0
- package/dist/chat/steering.js.map +1 -0
- package/dist/chat/types.d.ts +5 -1
- package/dist/cli.js +91 -13
- package/dist/cli.js.map +1 -1
- package/dist/configure/app.d.ts +1 -1
- package/dist/configure/app.js +581 -303
- package/dist/configure/app.js.map +1 -1
- package/dist/configure/components/MenuScreen.d.ts +4 -2
- package/dist/configure/components/MenuScreen.js +33 -6
- package/dist/configure/components/MenuScreen.js.map +1 -1
- package/dist/configure/components/SelectMenuItem.d.ts +1 -0
- package/dist/configure/components/SelectMenuItem.js +19 -10
- package/dist/configure/components/SelectMenuItem.js.map +1 -1
- package/dist/configure/index.js +4 -2
- package/dist/configure/index.js.map +1 -1
- package/dist/configure/types.d.ts +14 -12
- package/dist/configure/utils.d.ts +2 -0
- package/dist/configure/utils.js +21 -2
- package/dist/configure/utils.js.map +1 -1
- package/dist/core/agent/index.d.ts +3 -3
- package/dist/core/agent/index.js +20 -25
- package/dist/core/agent/index.js.map +1 -1
- package/dist/core/agent/mode-aware-tool-registry.js +2 -1
- package/dist/core/agent/mode-aware-tool-registry.js.map +1 -1
- package/dist/core/approvals/intervention.d.ts +34 -0
- package/dist/core/approvals/intervention.js +94 -0
- package/dist/core/approvals/intervention.js.map +1 -0
- package/dist/core/config.d.ts +49 -28
- package/dist/core/config.js +85 -26
- package/dist/core/config.js.map +1 -1
- package/dist/core/context/index.d.ts +11 -2
- package/dist/core/context/index.js +54 -4
- package/dist/core/context/index.js.map +1 -1
- package/dist/core/context/model-extractor.d.ts +13 -0
- package/dist/core/context/model-extractor.js +98 -0
- package/dist/core/context/model-extractor.js.map +1 -0
- package/dist/core/index.d.ts +6 -2
- package/dist/core/index.js +6 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/mcp/config.d.ts +28 -0
- package/dist/core/mcp/index.d.ts +5 -3
- package/dist/core/mcp/index.js +4 -2
- package/dist/core/mcp/index.js.map +1 -1
- package/dist/core/mcp/manager.d.ts +14 -1
- package/dist/core/mcp/manager.js +76 -4
- package/dist/core/mcp/manager.js.map +1 -1
- package/dist/core/mcp/oauth/callback-server.d.ts +16 -0
- package/dist/core/mcp/oauth/callback-server.js +134 -0
- package/dist/core/mcp/oauth/callback-server.js.map +1 -0
- package/dist/core/mcp/oauth/identity.d.ts +9 -0
- package/dist/core/mcp/oauth/identity.js +31 -0
- package/dist/core/mcp/oauth/identity.js.map +1 -0
- package/dist/core/mcp/oauth/index.d.ts +11 -0
- package/dist/core/mcp/oauth/index.js +15 -0
- package/dist/core/mcp/oauth/index.js.map +1 -0
- package/dist/core/mcp/oauth/provider.d.ts +43 -0
- package/dist/core/mcp/oauth/provider.js +203 -0
- package/dist/core/mcp/oauth/provider.js.map +1 -0
- package/dist/core/mcp/oauth/service.d.ts +29 -0
- package/dist/core/mcp/oauth/service.js +139 -0
- package/dist/core/mcp/oauth/service.js.map +1 -0
- package/dist/core/mcp/oauth/store.d.ts +14 -0
- package/dist/core/mcp/oauth/store.js +86 -0
- package/dist/core/mcp/oauth/store.js.map +1 -0
- package/dist/core/mcp/oauth/types.d.ts +87 -0
- package/dist/core/mcp/oauth/types.js +45 -0
- package/dist/core/mcp/oauth/types.js.map +1 -0
- package/dist/core/mcp/types.d.ts +56 -0
- package/dist/core/mcp/types.js +3 -0
- package/dist/core/mcp/types.js.map +1 -1
- package/dist/core/memory/file-store.d.ts +24 -0
- package/dist/core/memory/file-store.js +151 -0
- package/dist/core/memory/file-store.js.map +1 -0
- package/dist/core/memory/index.d.ts +2 -5
- package/dist/core/memory/index.js +2 -3
- package/dist/core/memory/index.js.map +1 -1
- package/dist/core/memory/runtime.d.ts +4 -0
- package/dist/core/memory/runtime.js +37 -0
- package/dist/core/memory/runtime.js.map +1 -0
- package/dist/core/models/anthropic.js +24 -1
- package/dist/core/models/anthropic.js.map +1 -1
- package/dist/core/models/moonshot.js +33 -1
- package/dist/core/models/moonshot.js.map +1 -1
- package/dist/core/modes/definitions.d.ts +19 -0
- package/dist/core/modes/definitions.js +99 -0
- package/dist/core/modes/definitions.js.map +1 -0
- package/dist/core/modes/index.d.ts +3 -0
- package/dist/core/modes/index.js +4 -0
- package/dist/core/modes/index.js.map +1 -0
- package/dist/core/modes/registry.d.ts +9 -0
- package/dist/core/modes/registry.js +57 -0
- package/dist/core/modes/registry.js.map +1 -0
- package/dist/core/modes/schema.d.ts +5 -0
- package/dist/core/modes/schema.js +6 -0
- package/dist/core/modes/schema.js.map +1 -0
- package/dist/core/prompts/agents/research.md +8 -8
- package/dist/core/prompts/bundled.d.ts +3 -0
- package/dist/core/prompts/bundled.js +14 -0
- package/dist/core/prompts/bundled.js.map +1 -0
- package/dist/core/prompts/environment.d.ts +0 -1
- package/dist/core/prompts/environment.js +0 -2
- package/dist/core/prompts/environment.js.map +1 -1
- package/dist/core/prompts/index.d.ts +1 -4
- package/dist/core/prompts/index.js +1 -7
- package/dist/core/prompts/index.js.map +1 -1
- package/dist/core/prompts/modes/agent.md +3 -0
- package/dist/core/prompts/modes/ask.md +5 -3
- package/dist/core/prompts/modes/plan.md +2 -2
- package/dist/core/prompts/session-mode-appendix.d.ts +3 -9
- package/dist/core/prompts/session-mode-appendix.js +32 -69
- package/dist/core/prompts/session-mode-appendix.js.map +1 -1
- package/dist/core/prompts/static/environment.md +2 -2
- package/dist/core/prompts/static/init.md +25 -0
- package/dist/core/prompts/static/memory.md +9 -123
- package/dist/core/prompts/static/planning.md +1 -1
- package/dist/core/prompts/static/skills.md +6 -5
- package/dist/core/prompts/static/subagents.md +2 -2
- package/dist/core/prompts/static/web-search.md +2 -1
- package/dist/core/prompts/system.js +8 -22
- package/dist/core/prompts/system.js.map +1 -1
- package/dist/core/skills/built-in/hooman-config/SKILL.md +105 -32
- package/dist/core/skills/built-in/hooman-skills/SKILL.md +1 -1
- package/dist/core/skills/index.d.ts +1 -0
- package/dist/core/skills/index.js +1 -0
- package/dist/core/skills/index.js.map +1 -1
- package/dist/core/skills/plugin.d.ts +7 -0
- package/dist/core/skills/plugin.js +40 -0
- package/dist/core/skills/plugin.js.map +1 -0
- package/dist/core/state/agent-app-state.d.ts +1 -1
- package/dist/core/state/agent-app-state.js +1 -1
- package/dist/core/state/session-mode.d.ts +2 -9
- package/dist/core/state/session-mode.js +4 -12
- package/dist/core/state/session-mode.js.map +1 -1
- package/dist/core/state/tool-approvals.d.ts +4 -8
- package/dist/core/state/tool-approvals.js +14 -76
- package/dist/core/state/tool-approvals.js.map +1 -1
- package/dist/core/subagents/index.d.ts +3 -0
- package/dist/core/subagents/index.js +4 -0
- package/dist/core/subagents/index.js.map +1 -0
- package/dist/core/subagents/research.d.ts +16 -0
- package/dist/core/subagents/research.js +58 -0
- package/dist/core/subagents/research.js.map +1 -0
- package/dist/core/{agents → subagents}/runner.d.ts +6 -5
- package/dist/core/{agents → subagents}/runner.js +8 -10
- package/dist/core/subagents/runner.js.map +1 -0
- package/dist/core/{agents/tools.d.ts → subagents/tool.d.ts} +6 -6
- package/dist/core/{agents/tools.js → subagents/tool.js} +14 -16
- package/dist/core/subagents/tool.js.map +1 -0
- package/dist/core/tools/plan.js +2 -6
- package/dist/core/tools/plan.js.map +1 -1
- package/dist/core/tools/time.js +1 -1
- package/dist/core/tools/time.js.map +1 -1
- package/dist/core/utils/browser.d.ts +1 -0
- package/dist/core/utils/browser.js +25 -0
- package/dist/core/utils/browser.js.map +1 -0
- package/dist/core/utils/paths.d.ts +2 -4
- package/dist/core/utils/paths.js +2 -4
- package/dist/core/utils/paths.js.map +1 -1
- package/dist/daemon/approvals.d.ts +2 -2
- package/dist/daemon/approvals.js +51 -56
- package/dist/daemon/approvals.js.map +1 -1
- package/dist/daemon/index.js +9 -6
- package/dist/daemon/index.js.map +1 -1
- package/dist/exec/approvals.d.ts +2 -4
- package/dist/exec/approvals.js +16 -48
- package/dist/exec/approvals.js.map +1 -1
- package/dist/index.d.ts +13 -18
- package/dist/index.js +9 -11
- package/dist/index.js.map +1 -1
- package/package.json +5 -18
- package/dist/chat/components/ScrollView.d.ts +0 -106
- package/dist/chat/components/ScrollView.js +0 -80
- package/dist/chat/components/ScrollView.js.map +0 -1
- package/dist/chat/components/TranscriptViewport.d.ts +0 -9
- package/dist/chat/components/TranscriptViewport.js +0 -124
- package/dist/chat/components/TranscriptViewport.js.map +0 -1
- package/dist/core/agents/definitions.d.ts +0 -12
- package/dist/core/agents/definitions.js +0 -20
- package/dist/core/agents/definitions.js.map +0 -1
- package/dist/core/agents/index.d.ts +0 -4
- package/dist/core/agents/index.js +0 -5
- package/dist/core/agents/index.js.map +0 -1
- package/dist/core/agents/registry.d.ts +0 -5
- package/dist/core/agents/registry.js +0 -84
- package/dist/core/agents/registry.js.map +0 -1
- package/dist/core/agents/runner.js.map +0 -1
- package/dist/core/agents/tools.js.map +0 -1
- package/dist/core/inference/embedder.d.ts +0 -26
- package/dist/core/inference/embedder.js +0 -85
- package/dist/core/inference/embedder.js.map +0 -1
- package/dist/core/inference/index.d.ts +0 -9
- package/dist/core/inference/index.js +0 -13
- package/dist/core/inference/index.js.map +0 -1
- package/dist/core/inference/loader.d.ts +0 -16
- package/dist/core/inference/loader.js +0 -129
- package/dist/core/inference/loader.js.map +0 -1
- package/dist/core/inference/reranker.d.ts +0 -28
- package/dist/core/inference/reranker.js +0 -66
- package/dist/core/inference/reranker.js.map +0 -1
- package/dist/core/memory/brain.d.ts +0 -25
- package/dist/core/memory/brain.js +0 -137
- package/dist/core/memory/brain.js.map +0 -1
- package/dist/core/memory/database.d.ts +0 -4
- package/dist/core/memory/database.js +0 -87
- package/dist/core/memory/database.js.map +0 -1
- package/dist/core/memory/tools.d.ts +0 -16
- package/dist/core/memory/tools.js +0 -110
- package/dist/core/memory/tools.js.map +0 -1
- package/dist/core/memory/types.d.ts +0 -11
- package/dist/core/memory/types.js +0 -2
- package/dist/core/memory/types.js.map +0 -1
- package/dist/core/prompts/skills.d.ts +0 -15
- package/dist/core/prompts/skills.js +0 -92
- package/dist/core/prompts/skills.js.map +0 -1
- package/dist/core/prompts/static/wiki.md +0 -25
- package/dist/core/wiki/converters.d.ts +0 -12
- package/dist/core/wiki/converters.js +0 -73
- package/dist/core/wiki/converters.js.map +0 -1
- package/dist/core/wiki/database.d.ts +0 -39
- package/dist/core/wiki/database.js +0 -177
- package/dist/core/wiki/database.js.map +0 -1
- package/dist/core/wiki/index.d.ts +0 -7
- package/dist/core/wiki/index.js +0 -5
- package/dist/core/wiki/index.js.map +0 -1
- package/dist/core/wiki/storage.d.ts +0 -38
- package/dist/core/wiki/storage.js +0 -206
- package/dist/core/wiki/storage.js.map +0 -1
- package/dist/core/wiki/tools.d.ts +0 -5
- package/dist/core/wiki/tools.js +0 -32
- package/dist/core/wiki/tools.js.map +0 -1
package/dist/chat/app.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useCallback, useEffect, useMemo, useRef, useState, } from "react";
|
|
3
3
|
import fastq from "fastq";
|
|
4
|
-
import { Box, useApp, useInput
|
|
5
|
-
import {
|
|
4
|
+
import { Box, Static, useApp, useInput } from "ink";
|
|
5
|
+
import { Message, TextBlock, } from "@strands-agents/sdk";
|
|
6
6
|
import { accumulateUsage, createEmptyUsage, } from "../core/utils/strands-usage-accumulate.js";
|
|
7
|
-
import {
|
|
7
|
+
import { modelProviders } from "../core/models/index.js";
|
|
8
|
+
import { MODE_DEFINITIONS, formatModeNames, getModeDefinition, isKnownSessionMode, } from "../core/modes/index.js";
|
|
8
9
|
import { takeFileToolDisplay } from "../core/state/file-tool-display.js";
|
|
9
|
-
import { ChatApprovalController, createChatApprovalHandler, } from "./approvals.js";
|
|
10
10
|
import { ApprovalPrompt } from "./components/ApprovalPrompt.js";
|
|
11
11
|
import { Composer } from "./components/Composer.js";
|
|
12
12
|
import { SelectPicker } from "./components/SelectPicker.js";
|
|
@@ -14,15 +14,16 @@ import { QueuedPrompts } from "./components/QueuedPrompts.js";
|
|
|
14
14
|
import { SlashCommands } from "./components/SlashCommands.js";
|
|
15
15
|
import { StatusBar } from "./components/StatusBar.js";
|
|
16
16
|
import { TodoPanel } from "./components/TodoPanel.js";
|
|
17
|
-
import {
|
|
17
|
+
import { Transcript, TranscriptLine } from "./components/Transcript.js";
|
|
18
18
|
import { getTodoViewState } from "../core/state/todos.js";
|
|
19
19
|
import { isExitRequested } from "../core/state/exit-request.js";
|
|
20
|
-
import { copyAgentAppState } from "../core/state/agent-app-state.js";
|
|
21
20
|
import { getModeState, setSessionMode, } from "../core/state/session-mode.js";
|
|
22
21
|
import { isYoloEnabled, setYoloEnabled } from "../core/state/yolo.js";
|
|
23
22
|
import { applySessionMode } from "../core/agent/sync-tool-registry-mode.js";
|
|
24
23
|
import { attachmentPathsToPromptBlocks } from "../core/utils/attachments.js";
|
|
25
24
|
import { isMouseInput } from "./mouse.js";
|
|
25
|
+
import { readBundledPrompt } from "../core/prompts/bundled.js";
|
|
26
|
+
import { runWithAgentMemoryScope } from "../core/memory/index.js";
|
|
26
27
|
function emptyTurnUsage() {
|
|
27
28
|
return { ...createEmptyUsage(), latencyMs: 0 };
|
|
28
29
|
}
|
|
@@ -38,6 +39,8 @@ function normalizePromptSubmission(value) {
|
|
|
38
39
|
};
|
|
39
40
|
}
|
|
40
41
|
const INPUT_HINT = "shift/meta+enter or \\+enter: newline | esc/ctrl+c: cancel or exit";
|
|
42
|
+
const INPUT_HINT_WITH_STEERING = "enter on empty input: steer active turn with queued prompts | shift/meta+enter or \\+enter: newline | esc/ctrl+c: cancel or exit";
|
|
43
|
+
const INIT_AGENTS_PROMPT = readBundledPrompt("static", "init.md");
|
|
41
44
|
function nowId() {
|
|
42
45
|
return `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
43
46
|
}
|
|
@@ -129,16 +132,23 @@ function parseYoloToggleArg(raw) {
|
|
|
129
132
|
}
|
|
130
133
|
function parseSessionModeArg(raw) {
|
|
131
134
|
const t = raw.trim().toLowerCase();
|
|
132
|
-
if (t
|
|
135
|
+
if (isKnownSessionMode(t)) {
|
|
133
136
|
return t;
|
|
134
137
|
}
|
|
135
138
|
return undefined;
|
|
136
139
|
}
|
|
140
|
+
function sessionModeLabel(mode) {
|
|
141
|
+
return getModeDefinition(mode)?.name ?? mode;
|
|
142
|
+
}
|
|
137
143
|
function listModelsText(config) {
|
|
138
144
|
const current = currentModelName(config);
|
|
139
145
|
const options = config.llms.map((entry) => {
|
|
140
146
|
const marker = entry.name === current ? "*" : "-";
|
|
141
|
-
|
|
147
|
+
const resolved = config.resolveLlm(entry.name);
|
|
148
|
+
if (!resolved) {
|
|
149
|
+
return `${marker} ${entry.name} (${entry.options.provider}/${entry.options.model})`;
|
|
150
|
+
}
|
|
151
|
+
return `${marker} ${entry.name} (${entry.options.provider} -> ${resolved.options.provider}/${resolved.options.model})`;
|
|
142
152
|
});
|
|
143
153
|
return [
|
|
144
154
|
`Current model: ${current}`,
|
|
@@ -148,9 +158,13 @@ function listModelsText(config) {
|
|
|
148
158
|
].join("\n");
|
|
149
159
|
}
|
|
150
160
|
const SLASH_COMMANDS = [
|
|
161
|
+
{
|
|
162
|
+
name: "init",
|
|
163
|
+
description: "Generate or refresh AGENTS.md for this project.",
|
|
164
|
+
},
|
|
151
165
|
{
|
|
152
166
|
name: "mode",
|
|
153
|
-
description:
|
|
167
|
+
description: `Session mode: ${formatModeNames()}.`,
|
|
154
168
|
},
|
|
155
169
|
{
|
|
156
170
|
name: "model",
|
|
@@ -175,11 +189,8 @@ function matchingSlashCommands(input) {
|
|
|
175
189
|
}
|
|
176
190
|
return SLASH_COMMANDS.filter((item) => item.name.startsWith(query));
|
|
177
191
|
}
|
|
178
|
-
export function ChatApp({ agent, config, sessionId, manager, registry, prompt, onExit, }) {
|
|
192
|
+
export function ChatApp({ agent, config, sessionId, manager, registry, approvals, steering, prompt, onExit, }) {
|
|
179
193
|
const { exit } = useApp();
|
|
180
|
-
const { rows } = useWindowSize();
|
|
181
|
-
const [currentAgent, setCurrentAgent] = useState(agent);
|
|
182
|
-
const [currentManager, setCurrentManager] = useState(manager);
|
|
183
194
|
const [input, setInput] = useState("");
|
|
184
195
|
const [running, setRunning] = useState(false);
|
|
185
196
|
const [status, setStatus] = useState("ready");
|
|
@@ -198,16 +209,23 @@ export function ChatApp({ agent, config, sessionId, manager, registry, prompt, o
|
|
|
198
209
|
}, []);
|
|
199
210
|
const [slashHighlightIndex, setSlashHighlightIndex] = useState(0);
|
|
200
211
|
const [queuedPrompts, setQueuedPrompts] = useState([]);
|
|
201
|
-
const [liveReasoning, setLiveReasoning] = useState("");
|
|
202
|
-
const [followRequest, setFollowRequest] = useState(0);
|
|
203
212
|
const [todoState, setTodoState] = useState(() => getTodoViewState(agent));
|
|
204
|
-
const controllerRef = useRef(new ChatApprovalController());
|
|
205
213
|
const mountedRef = useRef(true);
|
|
206
214
|
const runningRef = useRef(false);
|
|
207
215
|
const assistantLineIdRef = useRef(null);
|
|
216
|
+
const assistantCommittedTextRef = useRef("");
|
|
217
|
+
const streamedAssistantBlockRef = useRef(null);
|
|
218
|
+
const thoughtLineIdRef = useRef(null);
|
|
219
|
+
const thoughtTextRef = useRef("");
|
|
220
|
+
const thoughtStartedAtRef = useRef(null);
|
|
208
221
|
const toolLineIdsRef = useRef(new Map());
|
|
209
222
|
const pendingToolLineIdsRef = useRef([]);
|
|
210
223
|
const initialRanRef = useRef(false);
|
|
224
|
+
const queuedPromptsRef = useRef([]);
|
|
225
|
+
const skippedQueueIdsRef = useRef(new Set());
|
|
226
|
+
useEffect(() => {
|
|
227
|
+
queuedPromptsRef.current = queuedPrompts;
|
|
228
|
+
}, [queuedPrompts]);
|
|
211
229
|
useEffect(() => {
|
|
212
230
|
let cancelled = false;
|
|
213
231
|
void registry
|
|
@@ -240,23 +258,20 @@ export function ChatApp({ agent, config, sessionId, manager, registry, prompt, o
|
|
|
240
258
|
};
|
|
241
259
|
}, [running, turnStartedAt]);
|
|
242
260
|
useEffect(() => {
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
-
setPendingApproval(controller.pending);
|
|
261
|
+
const cleanupListener = approvals.subscribe(() => {
|
|
262
|
+
setPendingApproval(approvals.pending);
|
|
246
263
|
});
|
|
247
|
-
const cleanupHook = currentAgent.addHook(BeforeToolCallEvent, createChatApprovalHandler(controller));
|
|
248
264
|
return () => {
|
|
249
265
|
cleanupListener();
|
|
250
|
-
cleanupHook();
|
|
251
266
|
};
|
|
252
|
-
}, [
|
|
267
|
+
}, [approvals]);
|
|
253
268
|
useEffect(() => {
|
|
254
269
|
let active = true;
|
|
255
270
|
const refresh = () => {
|
|
256
271
|
if (!active) {
|
|
257
272
|
return;
|
|
258
273
|
}
|
|
259
|
-
setTodoState(getTodoViewState(
|
|
274
|
+
setTodoState(getTodoViewState(agent));
|
|
260
275
|
};
|
|
261
276
|
refresh();
|
|
262
277
|
const timer = setInterval(refresh, running ? 200 : 800);
|
|
@@ -264,8 +279,8 @@ export function ChatApp({ agent, config, sessionId, manager, registry, prompt, o
|
|
|
264
279
|
active = false;
|
|
265
280
|
clearInterval(timer);
|
|
266
281
|
};
|
|
267
|
-
}, [
|
|
268
|
-
const totalTools =
|
|
282
|
+
}, [agent, running]);
|
|
283
|
+
const totalTools = agent.tools?.length ?? 0;
|
|
269
284
|
const slashCommands = useMemo(() => matchingSlashCommands(input), [input]);
|
|
270
285
|
useEffect(() => {
|
|
271
286
|
setSlashHighlightIndex((i) => {
|
|
@@ -317,26 +332,98 @@ export function ChatApp({ agent, config, sessionId, manager, registry, prompt, o
|
|
|
317
332
|
return next;
|
|
318
333
|
});
|
|
319
334
|
}, []);
|
|
335
|
+
const replaceAssistantText = useCallback((text) => {
|
|
336
|
+
const id = assistantLineIdRef.current;
|
|
337
|
+
if (!id) {
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
setLines((prev) => prev.map((line) => (line.id === id ? { ...line, content: text } : line)));
|
|
341
|
+
}, []);
|
|
320
342
|
const appendAssistantText = useCallback((text) => {
|
|
343
|
+
streamedAssistantBlockRef.current = `${streamedAssistantBlockRef.current ?? ""}${text}`;
|
|
344
|
+
replaceAssistantText(`${assistantCommittedTextRef.current}${streamedAssistantBlockRef.current}`);
|
|
345
|
+
}, [replaceAssistantText]);
|
|
346
|
+
const commitAssistantBlock = useCallback((text) => {
|
|
347
|
+
assistantCommittedTextRef.current = `${assistantCommittedTextRef.current}${text}`;
|
|
348
|
+
streamedAssistantBlockRef.current = null;
|
|
349
|
+
replaceAssistantText(assistantCommittedTextRef.current);
|
|
350
|
+
}, [replaceAssistantText]);
|
|
351
|
+
const finalizeAssistantLine = useCallback(() => {
|
|
321
352
|
const id = assistantLineIdRef.current;
|
|
322
353
|
if (!id) {
|
|
323
354
|
return;
|
|
324
355
|
}
|
|
325
|
-
|
|
356
|
+
updateLine(id, { done: true });
|
|
357
|
+
assistantLineIdRef.current = null;
|
|
358
|
+
assistantCommittedTextRef.current = "";
|
|
359
|
+
streamedAssistantBlockRef.current = null;
|
|
360
|
+
}, [updateLine]);
|
|
361
|
+
const ensureAssistantLine = useCallback(() => {
|
|
362
|
+
const existing = assistantLineIdRef.current;
|
|
363
|
+
if (existing) {
|
|
364
|
+
return existing;
|
|
365
|
+
}
|
|
366
|
+
const id = nowId();
|
|
367
|
+
assistantLineIdRef.current = id;
|
|
368
|
+
assistantCommittedTextRef.current = "";
|
|
369
|
+
streamedAssistantBlockRef.current = null;
|
|
370
|
+
appendLine({
|
|
371
|
+
id,
|
|
372
|
+
role: "assistant",
|
|
373
|
+
content: "",
|
|
374
|
+
done: false,
|
|
375
|
+
});
|
|
376
|
+
return id;
|
|
377
|
+
}, [appendLine]);
|
|
378
|
+
const estimateReasoningTokens = useCallback((text) => {
|
|
379
|
+
const trimmed = text.trim();
|
|
380
|
+
if (!trimmed) {
|
|
381
|
+
return 0;
|
|
382
|
+
}
|
|
383
|
+
return Math.max(1, Math.round(trimmed.length / 4));
|
|
326
384
|
}, []);
|
|
327
|
-
const
|
|
328
|
-
const
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
385
|
+
const finalizeThoughtLine = useCallback(() => {
|
|
386
|
+
const id = thoughtLineIdRef.current;
|
|
387
|
+
if (!id) {
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
const finishedAt = Date.now();
|
|
391
|
+
updateLine(id, {
|
|
392
|
+
done: true,
|
|
393
|
+
finishedAt,
|
|
394
|
+
estimatedTokens: estimateReasoningTokens(thoughtTextRef.current),
|
|
395
|
+
});
|
|
396
|
+
thoughtLineIdRef.current = null;
|
|
397
|
+
thoughtTextRef.current = "";
|
|
398
|
+
thoughtStartedAtRef.current = null;
|
|
399
|
+
}, [estimateReasoningTokens, updateLine]);
|
|
400
|
+
const ensureThoughtLine = useCallback(() => {
|
|
401
|
+
const existing = thoughtLineIdRef.current;
|
|
402
|
+
if (existing) {
|
|
403
|
+
return existing;
|
|
404
|
+
}
|
|
405
|
+
finalizeAssistantLine();
|
|
406
|
+
const startedAt = Date.now();
|
|
407
|
+
const id = nowId();
|
|
408
|
+
thoughtLineIdRef.current = id;
|
|
409
|
+
thoughtTextRef.current = "";
|
|
410
|
+
thoughtStartedAtRef.current = startedAt;
|
|
411
|
+
appendLine({
|
|
412
|
+
id,
|
|
413
|
+
role: "thought",
|
|
414
|
+
content: "",
|
|
415
|
+
done: false,
|
|
416
|
+
startedAt,
|
|
417
|
+
});
|
|
418
|
+
return id;
|
|
419
|
+
}, [appendLine, finalizeAssistantLine]);
|
|
420
|
+
const appendThoughtText = useCallback((text) => {
|
|
421
|
+
const id = ensureThoughtLine();
|
|
422
|
+
thoughtTextRef.current = `${thoughtTextRef.current}${text}`;
|
|
423
|
+
setLines((prev) => prev.map((line) => line.id === id
|
|
424
|
+
? { ...line, content: `${line.content}${text}` }
|
|
425
|
+
: line));
|
|
426
|
+
}, [ensureThoughtLine]);
|
|
340
427
|
const handleModelCommand = useCallback(async (args) => {
|
|
341
428
|
if (runningRef.current) {
|
|
342
429
|
appendLine({
|
|
@@ -374,7 +461,8 @@ export function ChatApp({ agent, config, sessionId, manager, registry, prompt, o
|
|
|
374
461
|
})),
|
|
375
462
|
});
|
|
376
463
|
try {
|
|
377
|
-
await
|
|
464
|
+
const provider = await modelProviders[config.llm.provider]();
|
|
465
|
+
agent.model = provider.create(config.llm.model, config.llm.params);
|
|
378
466
|
}
|
|
379
467
|
catch (error) {
|
|
380
468
|
config.update({
|
|
@@ -391,7 +479,7 @@ export function ChatApp({ agent, config, sessionId, manager, registry, prompt, o
|
|
|
391
479
|
done: true,
|
|
392
480
|
});
|
|
393
481
|
}
|
|
394
|
-
}, [appendLine, config
|
|
482
|
+
}, [agent, appendLine, config]);
|
|
395
483
|
const handleYoloCommand = useCallback(async (args) => {
|
|
396
484
|
if (runningRef.current) {
|
|
397
485
|
appendLine({
|
|
@@ -419,13 +507,13 @@ export function ChatApp({ agent, config, sessionId, manager, registry, prompt, o
|
|
|
419
507
|
});
|
|
420
508
|
return;
|
|
421
509
|
}
|
|
422
|
-
const prev = isYoloEnabled(
|
|
510
|
+
const prev = isYoloEnabled(agent);
|
|
423
511
|
if (prev === enabled) {
|
|
424
512
|
return;
|
|
425
513
|
}
|
|
426
|
-
setYoloEnabled(
|
|
514
|
+
setYoloEnabled(agent, enabled);
|
|
427
515
|
bumpSessionChrome();
|
|
428
|
-
}, [appendLine, bumpSessionChrome
|
|
516
|
+
}, [agent, appendLine, bumpSessionChrome]);
|
|
429
517
|
const handleModeCommand = useCallback(async (args) => {
|
|
430
518
|
if (runningRef.current) {
|
|
431
519
|
appendLine({
|
|
@@ -448,19 +536,19 @@ export function ChatApp({ agent, config, sessionId, manager, registry, prompt, o
|
|
|
448
536
|
id: nowId(),
|
|
449
537
|
role: "system",
|
|
450
538
|
title: "mode",
|
|
451
|
-
content: `Unknown mode "${trimmed}". Use
|
|
539
|
+
content: `Unknown mode "${trimmed}". Use agent, ask, or plan, or open the picker with /mode.`,
|
|
452
540
|
done: true,
|
|
453
541
|
});
|
|
454
542
|
return;
|
|
455
543
|
}
|
|
456
|
-
const prev = getModeState(
|
|
544
|
+
const prev = getModeState(agent).mode;
|
|
457
545
|
if (prev === mode) {
|
|
458
546
|
return;
|
|
459
547
|
}
|
|
460
|
-
setSessionMode(
|
|
461
|
-
applySessionMode(
|
|
548
|
+
setSessionMode(agent, mode);
|
|
549
|
+
applySessionMode(agent);
|
|
462
550
|
bumpSessionChrome();
|
|
463
|
-
}, [appendLine, bumpSessionChrome
|
|
551
|
+
}, [agent, appendLine, bumpSessionChrome]);
|
|
464
552
|
const runTurn = useCallback(async (prompt) => {
|
|
465
553
|
const trimmed = prompt.text.trim();
|
|
466
554
|
if (!trimmed && prompt.attachments.length === 0) {
|
|
@@ -471,7 +559,6 @@ export function ChatApp({ agent, config, sessionId, manager, registry, prompt, o
|
|
|
471
559
|
setRunning(true);
|
|
472
560
|
setStatus("thinking");
|
|
473
561
|
setTurnStartedAt(Date.now());
|
|
474
|
-
setLiveReasoning("");
|
|
475
562
|
setTurnCount((value) => value + 1);
|
|
476
563
|
appendLine({
|
|
477
564
|
id: nowId(),
|
|
@@ -483,14 +570,6 @@ export function ChatApp({ agent, config, sessionId, manager, registry, prompt, o
|
|
|
483
570
|
: trimmed,
|
|
484
571
|
done: true,
|
|
485
572
|
});
|
|
486
|
-
const assistantId = nowId();
|
|
487
|
-
assistantLineIdRef.current = assistantId;
|
|
488
|
-
appendLine({
|
|
489
|
-
id: assistantId,
|
|
490
|
-
role: "assistant",
|
|
491
|
-
content: "",
|
|
492
|
-
done: false,
|
|
493
|
-
});
|
|
494
573
|
try {
|
|
495
574
|
const streamInput = attachmentBlocks.length > 0
|
|
496
575
|
? [
|
|
@@ -503,136 +582,142 @@ export function ChatApp({ agent, config, sessionId, manager, registry, prompt, o
|
|
|
503
582
|
}),
|
|
504
583
|
]
|
|
505
584
|
: trimmed;
|
|
506
|
-
|
|
507
|
-
const
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
const toolUseId = getToolUseId(block);
|
|
517
|
-
if (toolUseId) {
|
|
518
|
-
toolLineIdsRef.current.set(toolUseId, toolId);
|
|
519
|
-
}
|
|
520
|
-
else {
|
|
521
|
-
pendingToolLineIdsRef.current.push(toolId);
|
|
585
|
+
await runWithAgentMemoryScope(agent, async () => {
|
|
586
|
+
for await (const event of agent.stream(streamInput)) {
|
|
587
|
+
const e = event;
|
|
588
|
+
switch (e.type) {
|
|
589
|
+
case "contentBlockEvent": {
|
|
590
|
+
const block = e.contentBlock;
|
|
591
|
+
if (block.type === "textBlock") {
|
|
592
|
+
finalizeThoughtLine();
|
|
593
|
+
ensureAssistantLine();
|
|
594
|
+
commitAssistantBlock(block.text ?? "");
|
|
522
595
|
}
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
596
|
+
else if (block.type === "toolUseBlock") {
|
|
597
|
+
finalizeThoughtLine();
|
|
598
|
+
finalizeAssistantLine();
|
|
599
|
+
const toolId = nowId();
|
|
600
|
+
const toolUseId = getToolUseId(block);
|
|
601
|
+
if (toolUseId) {
|
|
602
|
+
toolLineIdsRef.current.set(toolUseId, toolId);
|
|
603
|
+
}
|
|
604
|
+
else {
|
|
605
|
+
pendingToolLineIdsRef.current.push(toolId);
|
|
606
|
+
}
|
|
607
|
+
appendLine({
|
|
608
|
+
id: toolId,
|
|
609
|
+
role: "tool",
|
|
610
|
+
title: "tool",
|
|
611
|
+
toolName: block.name ?? "unknown",
|
|
612
|
+
content: stringifyUnknown(block.input ?? {}),
|
|
613
|
+
phase: "running",
|
|
614
|
+
done: false,
|
|
615
|
+
});
|
|
534
616
|
}
|
|
617
|
+
break;
|
|
535
618
|
}
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
if (toolLineId && toolUseId) {
|
|
546
|
-
toolLineIdsRef.current.delete(toolUseId);
|
|
547
|
-
}
|
|
548
|
-
toolLineId ??= pendingToolLineIdsRef.current.shift();
|
|
549
|
-
if (!toolLineId) {
|
|
550
|
-
const firstTrackedTool = toolLineIdsRef.current
|
|
551
|
-
.entries()
|
|
552
|
-
.next();
|
|
553
|
-
if (!firstTrackedTool.done) {
|
|
554
|
-
const [trackedToolUseId, trackedToolLineId] = firstTrackedTool.value;
|
|
555
|
-
toolLineIdsRef.current.delete(trackedToolUseId);
|
|
556
|
-
toolLineId = trackedToolLineId;
|
|
619
|
+
case "toolResultEvent": {
|
|
620
|
+
const resultContent = toToolResultText(e.result);
|
|
621
|
+
const toolUseId = getToolUseId(e.result);
|
|
622
|
+
const fileToolDisplay = takeFileToolDisplay(agent.appState, toolUseId);
|
|
623
|
+
let toolLineId = toolUseId
|
|
624
|
+
? toolLineIdsRef.current.get(toolUseId)
|
|
625
|
+
: undefined;
|
|
626
|
+
if (toolLineId && toolUseId) {
|
|
627
|
+
toolLineIdsRef.current.delete(toolUseId);
|
|
557
628
|
}
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
phase: "done",
|
|
577
|
-
done: true,
|
|
578
|
-
});
|
|
579
|
-
}
|
|
580
|
-
break;
|
|
581
|
-
}
|
|
582
|
-
case "toolStreamUpdateEvent":
|
|
583
|
-
setStatus("running tool");
|
|
584
|
-
break;
|
|
585
|
-
case "modelStreamUpdateEvent": {
|
|
586
|
-
const modelEvent = e.event;
|
|
587
|
-
if (modelEvent?.type === "modelContentBlockDeltaEvent") {
|
|
588
|
-
const delta = modelEvent.delta;
|
|
589
|
-
if (delta?.type === "reasoningContentDelta" && delta.text) {
|
|
590
|
-
setStatus("thinking");
|
|
591
|
-
setLiveReasoning((prev) => `${prev}${delta.text}`);
|
|
629
|
+
toolLineId ??= pendingToolLineIdsRef.current.shift();
|
|
630
|
+
if (!toolLineId) {
|
|
631
|
+
const firstTrackedTool = toolLineIdsRef.current
|
|
632
|
+
.entries()
|
|
633
|
+
.next();
|
|
634
|
+
if (!firstTrackedTool.done) {
|
|
635
|
+
const [trackedToolUseId, trackedToolLineId] = firstTrackedTool.value;
|
|
636
|
+
toolLineIdsRef.current.delete(trackedToolUseId);
|
|
637
|
+
toolLineId = trackedToolLineId;
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
if (toolLineId) {
|
|
641
|
+
updateLine(toolLineId, {
|
|
642
|
+
phase: "done",
|
|
643
|
+
done: true,
|
|
644
|
+
resultContent,
|
|
645
|
+
fileToolDisplay,
|
|
646
|
+
});
|
|
592
647
|
}
|
|
593
|
-
else
|
|
594
|
-
|
|
648
|
+
else {
|
|
649
|
+
appendLine({
|
|
650
|
+
id: nowId(),
|
|
651
|
+
role: "tool",
|
|
652
|
+
title: "tool",
|
|
653
|
+
toolName: "unknown",
|
|
654
|
+
content: "",
|
|
655
|
+
resultContent,
|
|
656
|
+
fileToolDisplay,
|
|
657
|
+
phase: "done",
|
|
658
|
+
done: true,
|
|
659
|
+
});
|
|
595
660
|
}
|
|
661
|
+
break;
|
|
596
662
|
}
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
663
|
+
case "toolStreamUpdateEvent":
|
|
664
|
+
setStatus("running tool");
|
|
665
|
+
break;
|
|
666
|
+
case "modelStreamUpdateEvent": {
|
|
667
|
+
const modelEvent = e.event;
|
|
668
|
+
if (modelEvent?.type === "modelContentBlockDeltaEvent") {
|
|
669
|
+
const delta = modelEvent.delta;
|
|
670
|
+
if (delta?.type === "reasoningContentDelta" && delta.text) {
|
|
671
|
+
setStatus("thinking");
|
|
672
|
+
appendThoughtText(delta.text);
|
|
673
|
+
}
|
|
674
|
+
else if (delta?.type === "textDelta" && delta.text) {
|
|
675
|
+
finalizeThoughtLine();
|
|
676
|
+
setStatus("streaming");
|
|
677
|
+
ensureAssistantLine();
|
|
678
|
+
appendAssistantText(delta.text);
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
if (modelEvent?.type === "modelMetadataEvent") {
|
|
682
|
+
const u = (modelEvent.usage ?? {});
|
|
683
|
+
const delta = {
|
|
684
|
+
inputTokens: u.inputTokens ?? 0,
|
|
685
|
+
outputTokens: u.outputTokens ?? 0,
|
|
686
|
+
totalTokens: u.totalTokens ?? 0,
|
|
687
|
+
...(u.cacheReadInputTokens !== undefined && {
|
|
688
|
+
cacheReadInputTokens: u.cacheReadInputTokens,
|
|
621
689
|
}),
|
|
622
|
-
...(
|
|
623
|
-
cacheWriteInputTokens:
|
|
690
|
+
...(u.cacheWriteInputTokens !== undefined && {
|
|
691
|
+
cacheWriteInputTokens: u.cacheWriteInputTokens,
|
|
624
692
|
}),
|
|
625
693
|
};
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
694
|
+
const metricsData = (modelEvent.metrics ?? {});
|
|
695
|
+
const lat = metricsData.latencyMs ?? 0;
|
|
696
|
+
// Sum every `modelMetadataEvent` for this chat session (Strands meter semantics). Never reset on
|
|
697
|
+
// new prompts so the footer stays monotonic; note input totals sum per-request prompt sizes.
|
|
698
|
+
setUsage((prev) => {
|
|
699
|
+
const tokens = {
|
|
700
|
+
inputTokens: prev.inputTokens,
|
|
701
|
+
outputTokens: prev.outputTokens,
|
|
702
|
+
totalTokens: prev.totalTokens,
|
|
703
|
+
...(prev.cacheReadInputTokens !== undefined && {
|
|
704
|
+
cacheReadInputTokens: prev.cacheReadInputTokens,
|
|
705
|
+
}),
|
|
706
|
+
...(prev.cacheWriteInputTokens !== undefined && {
|
|
707
|
+
cacheWriteInputTokens: prev.cacheWriteInputTokens,
|
|
708
|
+
}),
|
|
709
|
+
};
|
|
710
|
+
accumulateUsage(tokens, delta);
|
|
711
|
+
return { ...tokens, latencyMs: prev.latencyMs + lat };
|
|
712
|
+
});
|
|
713
|
+
}
|
|
714
|
+
break;
|
|
629
715
|
}
|
|
630
|
-
|
|
716
|
+
default:
|
|
717
|
+
break;
|
|
631
718
|
}
|
|
632
|
-
default:
|
|
633
|
-
break;
|
|
634
719
|
}
|
|
635
|
-
}
|
|
720
|
+
});
|
|
636
721
|
}
|
|
637
722
|
catch (error) {
|
|
638
723
|
appendLine({
|
|
@@ -644,8 +729,8 @@ export function ChatApp({ agent, config, sessionId, manager, registry, prompt, o
|
|
|
644
729
|
});
|
|
645
730
|
}
|
|
646
731
|
finally {
|
|
647
|
-
|
|
648
|
-
|
|
732
|
+
finalizeThoughtLine();
|
|
733
|
+
finalizeAssistantLine();
|
|
649
734
|
for (const toolLineId of toolLineIdsRef.current.values()) {
|
|
650
735
|
updateLine(toolLineId, { phase: "done", done: true });
|
|
651
736
|
}
|
|
@@ -657,19 +742,21 @@ export function ChatApp({ agent, config, sessionId, manager, registry, prompt, o
|
|
|
657
742
|
runningRef.current = false;
|
|
658
743
|
setRunning(false);
|
|
659
744
|
setTurnStartedAt(null);
|
|
660
|
-
setLiveReasoning("");
|
|
661
745
|
setStatus("ready");
|
|
662
|
-
if (isExitRequested(
|
|
746
|
+
if (isExitRequested(agent)) {
|
|
663
747
|
onExit();
|
|
664
748
|
exit();
|
|
665
749
|
}
|
|
666
750
|
}
|
|
667
751
|
}, [
|
|
668
752
|
appendAssistantText,
|
|
753
|
+
appendThoughtText,
|
|
669
754
|
appendLine,
|
|
670
|
-
|
|
755
|
+
agent,
|
|
671
756
|
exit,
|
|
672
|
-
|
|
757
|
+
ensureAssistantLine,
|
|
758
|
+
finalizeAssistantLine,
|
|
759
|
+
finalizeThoughtLine,
|
|
673
760
|
onExit,
|
|
674
761
|
updateLine,
|
|
675
762
|
]);
|
|
@@ -680,6 +767,9 @@ export function ChatApp({ agent, config, sessionId, manager, registry, prompt, o
|
|
|
680
767
|
const queueRef = useRef(null);
|
|
681
768
|
if (!queueRef.current) {
|
|
682
769
|
queueRef.current = fastq.promise(async (item) => {
|
|
770
|
+
if (skippedQueueIdsRef.current.delete(item.id)) {
|
|
771
|
+
return;
|
|
772
|
+
}
|
|
683
773
|
if (mountedRef.current) {
|
|
684
774
|
setQueuedPrompts((prev) => prev.filter((entry) => entry.id !== item.id));
|
|
685
775
|
}
|
|
@@ -728,8 +818,37 @@ export function ChatApp({ agent, config, sessionId, manager, registry, prompt, o
|
|
|
728
818
|
if (pendingApproval) {
|
|
729
819
|
return;
|
|
730
820
|
}
|
|
821
|
+
const trimmed = value.text.trim();
|
|
822
|
+
if (runningRef.current &&
|
|
823
|
+
!trimmed &&
|
|
824
|
+
value.attachments.length === 0 &&
|
|
825
|
+
queuedPromptsRef.current.length > 0) {
|
|
826
|
+
const queued = queuedPromptsRef.current;
|
|
827
|
+
queuedPromptsRef.current = [];
|
|
828
|
+
for (const item of queued) {
|
|
829
|
+
skippedQueueIdsRef.current.add(item.id);
|
|
830
|
+
}
|
|
831
|
+
setQueuedPrompts([]);
|
|
832
|
+
if (steering.queue(queued.map((item) => item.prompt))) {
|
|
833
|
+
appendLine({
|
|
834
|
+
id: nowId(),
|
|
835
|
+
role: "system",
|
|
836
|
+
title: "steering",
|
|
837
|
+
content: `Steered the active turn with ${queued.length} queued prompt${queued.length === 1 ? "" : "s"}.`,
|
|
838
|
+
done: true,
|
|
839
|
+
});
|
|
840
|
+
}
|
|
841
|
+
setInput("");
|
|
842
|
+
return;
|
|
843
|
+
}
|
|
731
844
|
const command = parseChatCommand(value.text);
|
|
732
845
|
if (command && value.attachments.length === 0) {
|
|
846
|
+
if (command.name === "init") {
|
|
847
|
+
if (pushPrompt(INIT_AGENTS_PROMPT)) {
|
|
848
|
+
setInput("");
|
|
849
|
+
}
|
|
850
|
+
return;
|
|
851
|
+
}
|
|
733
852
|
if (command.name === "model") {
|
|
734
853
|
void handleModelCommand(command.args);
|
|
735
854
|
setInput("");
|
|
@@ -747,15 +866,16 @@ export function ChatApp({ agent, config, sessionId, manager, registry, prompt, o
|
|
|
747
866
|
}
|
|
748
867
|
}
|
|
749
868
|
if (pushPrompt(value)) {
|
|
750
|
-
setFollowRequest((value) => value + 1);
|
|
751
869
|
setInput("");
|
|
752
870
|
}
|
|
753
871
|
}, [
|
|
872
|
+
appendLine,
|
|
754
873
|
handleModelCommand,
|
|
755
874
|
handleModeCommand,
|
|
756
875
|
handleYoloCommand,
|
|
757
876
|
pendingApproval,
|
|
758
877
|
pushPrompt,
|
|
878
|
+
steering,
|
|
759
879
|
]);
|
|
760
880
|
useInput((inputKey, key) => {
|
|
761
881
|
if (isMouseInput(inputKey)) {
|
|
@@ -763,7 +883,7 @@ export function ChatApp({ agent, config, sessionId, manager, registry, prompt, o
|
|
|
763
883
|
}
|
|
764
884
|
if (key.ctrl && inputKey.toLowerCase() === "c") {
|
|
765
885
|
if (runningRef.current) {
|
|
766
|
-
|
|
886
|
+
agent.cancel();
|
|
767
887
|
setStatus("cancel requested");
|
|
768
888
|
return;
|
|
769
889
|
}
|
|
@@ -781,7 +901,7 @@ export function ChatApp({ agent, config, sessionId, manager, registry, prompt, o
|
|
|
781
901
|
return;
|
|
782
902
|
}
|
|
783
903
|
if (runningRef.current) {
|
|
784
|
-
|
|
904
|
+
agent.cancel();
|
|
785
905
|
setStatus("cancel requested");
|
|
786
906
|
return;
|
|
787
907
|
}
|
|
@@ -802,7 +922,17 @@ export function ChatApp({ agent, config, sessionId, manager, registry, prompt, o
|
|
|
802
922
|
const statusLabel = running && activeTodo
|
|
803
923
|
? activeTodo.activeForm.trim() || activeTodo.content
|
|
804
924
|
: status;
|
|
805
|
-
|
|
925
|
+
const inputHint = running && queuedPrompts.length > 0 ? INPUT_HINT_WITH_STEERING : INPUT_HINT;
|
|
926
|
+
const firstLiveLineIndex = useMemo(() => {
|
|
927
|
+
let index = 0;
|
|
928
|
+
while (index < lines.length && lines[index]?.done) {
|
|
929
|
+
index += 1;
|
|
930
|
+
}
|
|
931
|
+
return index;
|
|
932
|
+
}, [lines]);
|
|
933
|
+
const staticLines = useMemo(() => lines.slice(0, firstLiveLineIndex), [firstLiveLineIndex, lines]);
|
|
934
|
+
const liveLines = useMemo(() => lines.slice(firstLiveLineIndex), [firstLiveLineIndex, lines]);
|
|
935
|
+
return (_jsxs(Box, { flexDirection: "column", width: "100%", paddingX: 1, children: [staticLines.length > 0 ? (_jsx(Static, { items: staticLines, children: (line) => _jsx(TranscriptLine, { line: line }, line.id) })) : null, _jsxs(Box, { flexDirection: "column", flexShrink: 0, children: [lines.length === 0 || liveLines.length > 0 ? (_jsx(Transcript, { lines: liveLines, showEmptyBanner: lines.length === 0, marginTop: staticLines.length > 0 ? 0 : 1 })) : null, running && todoState.visible && todoState.todos.length > 0 ? (_jsx(TodoPanel, { todos: todoState.todos })) : null, _jsx(QueuedPrompts, { prompts: queuedPrompts }), pendingApproval ? (_jsx(ApprovalPrompt, { onDecision: (decision) => approvals.decide(decision) })) : null, !pendingApproval && picker === "model" ? (_jsx(SelectPicker, { title: "Choose model", items: config.llms.map((entry) => ({
|
|
806
936
|
label: `${entry.name} • ${entry.options.provider}/${entry.options.model}${entry.default ? " • current" : ""}`,
|
|
807
937
|
value: entry.name,
|
|
808
938
|
})), onSelect: (name) => {
|
|
@@ -810,34 +940,24 @@ export function ChatApp({ agent, config, sessionId, manager, registry, prompt, o
|
|
|
810
940
|
void handleModelCommand(name);
|
|
811
941
|
} })) : null, !pendingApproval && picker === "yolo" ? (_jsx(SelectPicker, { title: "Auto-approve tools (yolo)", items: [
|
|
812
942
|
{
|
|
813
|
-
label: `Off • confirm each tool${!isYoloEnabled(
|
|
943
|
+
label: `Off • confirm each tool${!isYoloEnabled(agent) ? " • current" : ""}`,
|
|
814
944
|
value: "off",
|
|
815
945
|
},
|
|
816
946
|
{
|
|
817
|
-
label: `On • run tools without prompts${isYoloEnabled(
|
|
947
|
+
label: `On • run tools without prompts${isYoloEnabled(agent) ? " • current" : ""}`,
|
|
818
948
|
value: "on",
|
|
819
949
|
},
|
|
820
950
|
], onSelect: (v) => {
|
|
821
951
|
setPicker(null);
|
|
822
952
|
void handleYoloCommand(v);
|
|
823
953
|
} })) : null, !pendingApproval && picker === "mode" ? (_jsx(SelectPicker, { title: "Session mode", items: [
|
|
824
|
-
{
|
|
825
|
-
label:
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
value: "default",
|
|
829
|
-
},
|
|
830
|
-
{
|
|
831
|
-
label: `Plan • read only tools + plan file${getModeState(currentAgent).mode === "plan" ? " • current" : ""}`,
|
|
832
|
-
value: "plan",
|
|
833
|
-
},
|
|
834
|
-
{
|
|
835
|
-
label: `Ask • read only tools, no plan workflow${getModeState(currentAgent).mode === "ask" ? " • current" : ""}`,
|
|
836
|
-
value: "ask",
|
|
837
|
-
},
|
|
954
|
+
...MODE_DEFINITIONS.map((entry) => ({
|
|
955
|
+
label: `${entry.name} • ${entry.description}${getModeState(agent).mode === entry.id ? " • current" : ""}`,
|
|
956
|
+
value: entry.id,
|
|
957
|
+
})),
|
|
838
958
|
], onSelect: (v) => {
|
|
839
959
|
setPicker(null);
|
|
840
960
|
void handleModeCommand(v);
|
|
841
|
-
} })) : null, !pendingApproval && !picker ? (_jsx(SlashCommands, { items: slashCommands, highlightIndex: slashHighlightIndex })) : null, !pendingApproval && !picker ? (_jsx(Composer, { input: input, running: running, disabled: Boolean(pendingApproval), hint:
|
|
961
|
+
} })) : null, !pendingApproval && !picker ? (_jsx(SlashCommands, { items: slashCommands, highlightIndex: slashHighlightIndex })) : null, !pendingApproval && !picker ? (_jsx(Composer, { input: input, running: running, disabled: Boolean(pendingApproval), hint: inputHint, onChange: setInput, onSubmit: onSubmit, slashMenu: slashMenu })) : null, _jsx(StatusBar, { running: running, status: status, statusLabel: statusLabel, sessionId: sessionId, currentModel: currentModelLabel(config), yoloOn: isYoloEnabled(agent), sessionMode: sessionModeLabel(getModeState(agent).mode), elapsedLabel: elapsedLabel, turnCount: turnCount, totalTools: totalTools, skillsFound: skillsFound, manager: manager, usage: usage })] })] }));
|
|
842
962
|
}
|
|
843
963
|
//# sourceMappingURL=app.js.map
|