hoomanjs 1.29.2 → 1.31.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 +469 -234
- 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/BottomChrome.d.ts +52 -0
- package/dist/chat/components/BottomChrome.js +12 -0
- package/dist/chat/components/BottomChrome.js.map +1 -0
- package/dist/chat/components/ChatMessage.d.ts +2 -2
- package/dist/chat/components/ChatMessage.js +5 -6
- package/dist/chat/components/ChatMessage.js.map +1 -1
- package/dist/chat/components/ChromePicker.d.ts +17 -0
- package/dist/chat/components/ChromePicker.js +35 -0
- package/dist/chat/components/ChromePicker.js.map +1 -0
- package/dist/chat/components/EmptyChatBanner.js +2 -3
- package/dist/chat/components/EmptyChatBanner.js.map +1 -1
- package/dist/chat/components/StatusBar.d.ts +1 -2
- package/dist/chat/components/StatusBar.js +8 -5
- package/dist/chat/components/StatusBar.js.map +1 -1
- package/dist/chat/components/ThoughtEvent.d.ts +7 -0
- package/dist/chat/components/ThoughtEvent.js +30 -0
- package/dist/chat/components/ThoughtEvent.js.map +1 -0
- package/dist/chat/components/TodoPanel.js +52 -2
- package/dist/chat/components/TodoPanel.js.map +1 -1
- package/dist/chat/components/ToolEvent.js +1 -1
- package/dist/chat/components/ToolEvent.js.map +1 -1
- package/dist/chat/components/Transcript.d.ts +11 -2
- package/dist/chat/components/Transcript.js +78 -4
- 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 +21 -4
- 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 +26 -29
- 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/runtime.d.ts +10 -0
- package/dist/core/prompts/runtime.js +136 -0
- package/dist/core/prompts/runtime.js.map +1 -0
- 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/filesystem.md +2 -0
- 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 +12 -29
- 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/filesystem.d.ts +1 -0
- package/dist/core/tools/filesystem.js +38 -3
- package/dist/core/tools/filesystem.js.map +1 -1
- package/dist/core/tools/index.d.ts +1 -1
- package/dist/core/tools/index.js +1 -1
- package/dist/core/tools/index.js.map +1 -1
- 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
|
@@ -2,27 +2,22 @@ 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
4
|
import { Box, useApp, useInput, useWindowSize } from "ink";
|
|
5
|
-
import {
|
|
5
|
+
import { Message, TextBlock, ToolResultBlock, ToolUseBlock, } 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 { formatModeNames, isKnownSessionMode } from "../core/modes/index.js";
|
|
8
9
|
import { takeFileToolDisplay } from "../core/state/file-tool-display.js";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { Composer } from "./components/Composer.js";
|
|
12
|
-
import { SelectPicker } from "./components/SelectPicker.js";
|
|
13
|
-
import { QueuedPrompts } from "./components/QueuedPrompts.js";
|
|
14
|
-
import { SlashCommands } from "./components/SlashCommands.js";
|
|
15
|
-
import { StatusBar } from "./components/StatusBar.js";
|
|
16
|
-
import { TodoPanel } from "./components/TodoPanel.js";
|
|
17
|
-
import { TranscriptViewport } from "./components/TranscriptViewport.js";
|
|
10
|
+
import { BottomChrome } from "./components/BottomChrome.js";
|
|
11
|
+
import { Transcript } from "./components/Transcript.js";
|
|
18
12
|
import { getTodoViewState } from "../core/state/todos.js";
|
|
19
13
|
import { isExitRequested } from "../core/state/exit-request.js";
|
|
20
|
-
import { copyAgentAppState } from "../core/state/agent-app-state.js";
|
|
21
14
|
import { getModeState, setSessionMode, } from "../core/state/session-mode.js";
|
|
22
15
|
import { isYoloEnabled, setYoloEnabled } from "../core/state/yolo.js";
|
|
23
16
|
import { applySessionMode } from "../core/agent/sync-tool-registry-mode.js";
|
|
24
17
|
import { attachmentPathsToPromptBlocks } from "../core/utils/attachments.js";
|
|
25
18
|
import { isMouseInput } from "./mouse.js";
|
|
19
|
+
import { readBundledPrompt } from "../core/prompts/bundled.js";
|
|
20
|
+
import { runWithAgentMemoryScope } from "../core/memory/index.js";
|
|
26
21
|
function emptyTurnUsage() {
|
|
27
22
|
return { ...createEmptyUsage(), latencyMs: 0 };
|
|
28
23
|
}
|
|
@@ -37,7 +32,9 @@ function normalizePromptSubmission(value) {
|
|
|
37
32
|
],
|
|
38
33
|
};
|
|
39
34
|
}
|
|
40
|
-
const INPUT_HINT = "shift/meta+enter or \\+enter: newline | esc/ctrl+c: cancel or exit";
|
|
35
|
+
const INPUT_HINT = "pgup/pgdn: scroll | shift/meta+enter or \\+enter: newline | esc/ctrl+c: cancel or exit";
|
|
36
|
+
const INPUT_HINT_WITH_STEERING = "enter on empty input: steer active turn with queued prompts | pgup/pgdn: scroll | shift/meta+enter or \\+enter: newline | esc/ctrl+c: cancel or exit";
|
|
37
|
+
const INIT_AGENTS_PROMPT = readBundledPrompt("static", "init.md");
|
|
41
38
|
function nowId() {
|
|
42
39
|
return `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
43
40
|
}
|
|
@@ -49,6 +46,17 @@ function stringifyUnknown(value) {
|
|
|
49
46
|
return String(value);
|
|
50
47
|
}
|
|
51
48
|
}
|
|
49
|
+
function blockToFallbackText(block) {
|
|
50
|
+
if (block.type === "textBlock") {
|
|
51
|
+
return block.text;
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
return JSON.stringify(block.toJSON?.() ?? block, null, 2);
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return String(block);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
52
60
|
function toToolResultText(result) {
|
|
53
61
|
const data = result;
|
|
54
62
|
const pieces = (data.content ?? []).map((item) => {
|
|
@@ -76,6 +84,83 @@ function getToolUseId(value) {
|
|
|
76
84
|
}
|
|
77
85
|
return null;
|
|
78
86
|
}
|
|
87
|
+
function estimateReasoningTokens(text) {
|
|
88
|
+
const trimmed = text.trim();
|
|
89
|
+
if (!trimmed) {
|
|
90
|
+
return 0;
|
|
91
|
+
}
|
|
92
|
+
return Math.max(1, Math.round(trimmed.length / 4));
|
|
93
|
+
}
|
|
94
|
+
function buildInitialTranscript(messages) {
|
|
95
|
+
const lines = [];
|
|
96
|
+
const toolResults = new Map();
|
|
97
|
+
for (const message of messages) {
|
|
98
|
+
for (const block of message.content) {
|
|
99
|
+
if (block instanceof ToolResultBlock) {
|
|
100
|
+
toolResults.set(block.toolUseId, block);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
for (const message of messages) {
|
|
105
|
+
if (message.role === "user") {
|
|
106
|
+
const parts = message.content
|
|
107
|
+
.filter((block) => !(block instanceof ToolResultBlock))
|
|
108
|
+
.map((block) => blockToFallbackText(block)?.trimEnd() ?? "")
|
|
109
|
+
.filter(Boolean);
|
|
110
|
+
if (parts.length > 0) {
|
|
111
|
+
lines.push({
|
|
112
|
+
id: nowId(),
|
|
113
|
+
role: "user",
|
|
114
|
+
content: parts.join("\n\n"),
|
|
115
|
+
done: true,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
if (message.role !== "assistant") {
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
for (const block of message.content) {
|
|
124
|
+
if (block instanceof ToolUseBlock) {
|
|
125
|
+
const result = toolResults.get(block.toolUseId);
|
|
126
|
+
lines.push({
|
|
127
|
+
id: nowId(),
|
|
128
|
+
role: "tool",
|
|
129
|
+
title: "tool",
|
|
130
|
+
toolName: block.name,
|
|
131
|
+
content: stringifyUnknown(block.input ?? {}),
|
|
132
|
+
resultContent: result ? toToolResultText(result) : undefined,
|
|
133
|
+
phase: result ? "done" : "running",
|
|
134
|
+
done: Boolean(result),
|
|
135
|
+
});
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
if (block.type === "reasoningBlock") {
|
|
139
|
+
const text = blockToFallbackText(block)?.trim();
|
|
140
|
+
if (text) {
|
|
141
|
+
lines.push({
|
|
142
|
+
id: nowId(),
|
|
143
|
+
role: "thought",
|
|
144
|
+
content: text,
|
|
145
|
+
done: true,
|
|
146
|
+
estimatedTokens: estimateReasoningTokens(text),
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
const text = blockToFallbackText(block)?.trimEnd();
|
|
152
|
+
if (text) {
|
|
153
|
+
lines.push({
|
|
154
|
+
id: nowId(),
|
|
155
|
+
role: "assistant",
|
|
156
|
+
content: text,
|
|
157
|
+
done: true,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return lines;
|
|
163
|
+
}
|
|
79
164
|
function currentModelName(config) {
|
|
80
165
|
return (config.llms.find((m) => m.default)?.name ??
|
|
81
166
|
config.llms[0]?.name ??
|
|
@@ -129,7 +214,7 @@ function parseYoloToggleArg(raw) {
|
|
|
129
214
|
}
|
|
130
215
|
function parseSessionModeArg(raw) {
|
|
131
216
|
const t = raw.trim().toLowerCase();
|
|
132
|
-
if (t
|
|
217
|
+
if (isKnownSessionMode(t)) {
|
|
133
218
|
return t;
|
|
134
219
|
}
|
|
135
220
|
return undefined;
|
|
@@ -138,7 +223,11 @@ function listModelsText(config) {
|
|
|
138
223
|
const current = currentModelName(config);
|
|
139
224
|
const options = config.llms.map((entry) => {
|
|
140
225
|
const marker = entry.name === current ? "*" : "-";
|
|
141
|
-
|
|
226
|
+
const resolved = config.resolveLlm(entry.name);
|
|
227
|
+
if (!resolved) {
|
|
228
|
+
return `${marker} ${entry.name} (${entry.options.provider}/${entry.options.model})`;
|
|
229
|
+
}
|
|
230
|
+
return `${marker} ${entry.name} (${entry.options.provider} -> ${resolved.options.provider}/${resolved.options.model})`;
|
|
142
231
|
});
|
|
143
232
|
return [
|
|
144
233
|
`Current model: ${current}`,
|
|
@@ -148,9 +237,13 @@ function listModelsText(config) {
|
|
|
148
237
|
].join("\n");
|
|
149
238
|
}
|
|
150
239
|
const SLASH_COMMANDS = [
|
|
240
|
+
{
|
|
241
|
+
name: "init",
|
|
242
|
+
description: "Generate or refresh AGENTS.md for this project.",
|
|
243
|
+
},
|
|
151
244
|
{
|
|
152
245
|
name: "mode",
|
|
153
|
-
description:
|
|
246
|
+
description: `Session mode: ${formatModeNames()}.`,
|
|
154
247
|
},
|
|
155
248
|
{
|
|
156
249
|
name: "model",
|
|
@@ -175,15 +268,42 @@ function matchingSlashCommands(input) {
|
|
|
175
268
|
}
|
|
176
269
|
return SLASH_COMMANDS.filter((item) => item.name.startsWith(query));
|
|
177
270
|
}
|
|
178
|
-
|
|
271
|
+
function estimateChromeRows(params) {
|
|
272
|
+
let rows = 8;
|
|
273
|
+
if (params.running && params.todoCount > 0) {
|
|
274
|
+
rows += 2 + params.todoCount;
|
|
275
|
+
}
|
|
276
|
+
if (params.queueCount > 0) {
|
|
277
|
+
rows += 2 + params.queueCount;
|
|
278
|
+
}
|
|
279
|
+
if (params.pendingApproval) {
|
|
280
|
+
rows += 4;
|
|
281
|
+
return rows;
|
|
282
|
+
}
|
|
283
|
+
if (params.picker === "model") {
|
|
284
|
+
rows += 2 + 4;
|
|
285
|
+
return rows;
|
|
286
|
+
}
|
|
287
|
+
if (params.picker === "yolo") {
|
|
288
|
+
rows += 2 + 2;
|
|
289
|
+
return rows;
|
|
290
|
+
}
|
|
291
|
+
if (params.picker === "mode") {
|
|
292
|
+
rows += 2 + 3;
|
|
293
|
+
return rows;
|
|
294
|
+
}
|
|
295
|
+
if (params.slashCommandCount > 0) {
|
|
296
|
+
rows += params.slashCommandCount + 1;
|
|
297
|
+
}
|
|
298
|
+
return rows;
|
|
299
|
+
}
|
|
300
|
+
export function ChatApp({ agent, config, sessionId, manager, registry, approvals, steering, prompt, onExit, }) {
|
|
179
301
|
const { exit } = useApp();
|
|
180
|
-
const
|
|
181
|
-
const [currentAgent, setCurrentAgent] = useState(agent);
|
|
182
|
-
const [currentManager, setCurrentManager] = useState(manager);
|
|
302
|
+
const windowSize = useWindowSize();
|
|
183
303
|
const [input, setInput] = useState("");
|
|
184
304
|
const [running, setRunning] = useState(false);
|
|
185
305
|
const [status, setStatus] = useState("ready");
|
|
186
|
-
const [lines, setLines] = useState(
|
|
306
|
+
const [lines, setLines] = useState(() => buildInitialTranscript(agent.messages));
|
|
187
307
|
const [turnCount, setTurnCount] = useState(0);
|
|
188
308
|
const [skillsFound, setSkillsFound] = useState(0);
|
|
189
309
|
const [turnStartedAt, setTurnStartedAt] = useState(null);
|
|
@@ -198,16 +318,24 @@ export function ChatApp({ agent, config, sessionId, manager, registry, prompt, o
|
|
|
198
318
|
}, []);
|
|
199
319
|
const [slashHighlightIndex, setSlashHighlightIndex] = useState(0);
|
|
200
320
|
const [queuedPrompts, setQueuedPrompts] = useState([]);
|
|
201
|
-
const [
|
|
202
|
-
const [followRequest, setFollowRequest] = useState(0);
|
|
321
|
+
const [transcriptScrollOffset, setTranscriptScrollOffset] = useState(0);
|
|
203
322
|
const [todoState, setTodoState] = useState(() => getTodoViewState(agent));
|
|
204
|
-
const controllerRef = useRef(new ChatApprovalController());
|
|
205
323
|
const mountedRef = useRef(true);
|
|
206
324
|
const runningRef = useRef(false);
|
|
207
325
|
const assistantLineIdRef = useRef(null);
|
|
326
|
+
const assistantCommittedTextRef = useRef("");
|
|
327
|
+
const streamedAssistantBlockRef = useRef(null);
|
|
328
|
+
const thoughtLineIdRef = useRef(null);
|
|
329
|
+
const thoughtTextRef = useRef("");
|
|
330
|
+
const thoughtStartedAtRef = useRef(null);
|
|
208
331
|
const toolLineIdsRef = useRef(new Map());
|
|
209
332
|
const pendingToolLineIdsRef = useRef([]);
|
|
210
333
|
const initialRanRef = useRef(false);
|
|
334
|
+
const queuedPromptsRef = useRef([]);
|
|
335
|
+
const skippedQueueIdsRef = useRef(new Set());
|
|
336
|
+
useEffect(() => {
|
|
337
|
+
queuedPromptsRef.current = queuedPrompts;
|
|
338
|
+
}, [queuedPrompts]);
|
|
211
339
|
useEffect(() => {
|
|
212
340
|
let cancelled = false;
|
|
213
341
|
void registry
|
|
@@ -240,23 +368,20 @@ export function ChatApp({ agent, config, sessionId, manager, registry, prompt, o
|
|
|
240
368
|
};
|
|
241
369
|
}, [running, turnStartedAt]);
|
|
242
370
|
useEffect(() => {
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
-
setPendingApproval(controller.pending);
|
|
371
|
+
const cleanupListener = approvals.subscribe(() => {
|
|
372
|
+
setPendingApproval(approvals.pending);
|
|
246
373
|
});
|
|
247
|
-
const cleanupHook = currentAgent.addHook(BeforeToolCallEvent, createChatApprovalHandler(controller));
|
|
248
374
|
return () => {
|
|
249
375
|
cleanupListener();
|
|
250
|
-
cleanupHook();
|
|
251
376
|
};
|
|
252
|
-
}, [
|
|
377
|
+
}, [approvals]);
|
|
253
378
|
useEffect(() => {
|
|
254
379
|
let active = true;
|
|
255
380
|
const refresh = () => {
|
|
256
381
|
if (!active) {
|
|
257
382
|
return;
|
|
258
383
|
}
|
|
259
|
-
setTodoState(getTodoViewState(
|
|
384
|
+
setTodoState(getTodoViewState(agent));
|
|
260
385
|
};
|
|
261
386
|
refresh();
|
|
262
387
|
const timer = setInterval(refresh, running ? 200 : 800);
|
|
@@ -264,8 +389,8 @@ export function ChatApp({ agent, config, sessionId, manager, registry, prompt, o
|
|
|
264
389
|
active = false;
|
|
265
390
|
clearInterval(timer);
|
|
266
391
|
};
|
|
267
|
-
}, [
|
|
268
|
-
const totalTools =
|
|
392
|
+
}, [agent, running]);
|
|
393
|
+
const totalTools = agent.tools?.length ?? 0;
|
|
269
394
|
const slashCommands = useMemo(() => matchingSlashCommands(input), [input]);
|
|
270
395
|
useEffect(() => {
|
|
271
396
|
setSlashHighlightIndex((i) => {
|
|
@@ -317,26 +442,91 @@ export function ChatApp({ agent, config, sessionId, manager, registry, prompt, o
|
|
|
317
442
|
return next;
|
|
318
443
|
});
|
|
319
444
|
}, []);
|
|
320
|
-
const
|
|
445
|
+
const replaceAssistantText = useCallback((text) => {
|
|
321
446
|
const id = assistantLineIdRef.current;
|
|
322
447
|
if (!id) {
|
|
323
448
|
return;
|
|
324
449
|
}
|
|
325
|
-
setLines((prev) => prev.map((line) => line.id === id ? { ...line, content:
|
|
450
|
+
setLines((prev) => prev.map((line) => (line.id === id ? { ...line, content: text } : line)));
|
|
326
451
|
}, []);
|
|
327
|
-
const
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
452
|
+
const appendAssistantText = useCallback((text) => {
|
|
453
|
+
streamedAssistantBlockRef.current = `${streamedAssistantBlockRef.current ?? ""}${text}`;
|
|
454
|
+
replaceAssistantText(`${assistantCommittedTextRef.current}${streamedAssistantBlockRef.current}`);
|
|
455
|
+
}, [replaceAssistantText]);
|
|
456
|
+
const commitAssistantBlock = useCallback((text) => {
|
|
457
|
+
assistantCommittedTextRef.current = `${assistantCommittedTextRef.current}${text}`;
|
|
458
|
+
streamedAssistantBlockRef.current = null;
|
|
459
|
+
replaceAssistantText(assistantCommittedTextRef.current);
|
|
460
|
+
}, [replaceAssistantText]);
|
|
461
|
+
const finalizeAssistantLine = useCallback(() => {
|
|
462
|
+
const id = assistantLineIdRef.current;
|
|
463
|
+
if (!id) {
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
updateLine(id, { done: true });
|
|
467
|
+
assistantLineIdRef.current = null;
|
|
468
|
+
assistantCommittedTextRef.current = "";
|
|
469
|
+
streamedAssistantBlockRef.current = null;
|
|
470
|
+
}, [updateLine]);
|
|
471
|
+
const ensureAssistantLine = useCallback(() => {
|
|
472
|
+
const existing = assistantLineIdRef.current;
|
|
473
|
+
if (existing) {
|
|
474
|
+
return existing;
|
|
475
|
+
}
|
|
476
|
+
const id = nowId();
|
|
477
|
+
assistantLineIdRef.current = id;
|
|
478
|
+
assistantCommittedTextRef.current = "";
|
|
479
|
+
streamedAssistantBlockRef.current = null;
|
|
480
|
+
appendLine({
|
|
481
|
+
id,
|
|
482
|
+
role: "assistant",
|
|
483
|
+
content: "",
|
|
484
|
+
done: false,
|
|
485
|
+
});
|
|
486
|
+
return id;
|
|
487
|
+
}, [appendLine]);
|
|
488
|
+
const finalizeThoughtLine = useCallback(() => {
|
|
489
|
+
const id = thoughtLineIdRef.current;
|
|
490
|
+
if (!id) {
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
const finishedAt = Date.now();
|
|
494
|
+
updateLine(id, {
|
|
495
|
+
done: true,
|
|
496
|
+
finishedAt,
|
|
497
|
+
estimatedTokens: estimateReasoningTokens(thoughtTextRef.current),
|
|
498
|
+
});
|
|
499
|
+
thoughtLineIdRef.current = null;
|
|
500
|
+
thoughtTextRef.current = "";
|
|
501
|
+
thoughtStartedAtRef.current = null;
|
|
502
|
+
}, [updateLine]);
|
|
503
|
+
const ensureThoughtLine = useCallback(() => {
|
|
504
|
+
const existing = thoughtLineIdRef.current;
|
|
505
|
+
if (existing) {
|
|
506
|
+
return existing;
|
|
507
|
+
}
|
|
508
|
+
finalizeAssistantLine();
|
|
509
|
+
const startedAt = Date.now();
|
|
510
|
+
const id = nowId();
|
|
511
|
+
thoughtLineIdRef.current = id;
|
|
512
|
+
thoughtTextRef.current = "";
|
|
513
|
+
thoughtStartedAtRef.current = startedAt;
|
|
514
|
+
appendLine({
|
|
515
|
+
id,
|
|
516
|
+
role: "thought",
|
|
517
|
+
content: "",
|
|
518
|
+
done: false,
|
|
519
|
+
startedAt,
|
|
520
|
+
});
|
|
521
|
+
return id;
|
|
522
|
+
}, [appendLine, finalizeAssistantLine]);
|
|
523
|
+
const appendThoughtText = useCallback((text) => {
|
|
524
|
+
const id = ensureThoughtLine();
|
|
525
|
+
thoughtTextRef.current = `${thoughtTextRef.current}${text}`;
|
|
526
|
+
setLines((prev) => prev.map((line) => line.id === id
|
|
527
|
+
? { ...line, content: `${line.content}${text}` }
|
|
528
|
+
: line));
|
|
529
|
+
}, [ensureThoughtLine]);
|
|
340
530
|
const handleModelCommand = useCallback(async (args) => {
|
|
341
531
|
if (runningRef.current) {
|
|
342
532
|
appendLine({
|
|
@@ -374,7 +564,8 @@ export function ChatApp({ agent, config, sessionId, manager, registry, prompt, o
|
|
|
374
564
|
})),
|
|
375
565
|
});
|
|
376
566
|
try {
|
|
377
|
-
await
|
|
567
|
+
const provider = await modelProviders[config.llm.provider]();
|
|
568
|
+
agent.model = provider.create(config.llm.model, config.llm.params);
|
|
378
569
|
}
|
|
379
570
|
catch (error) {
|
|
380
571
|
config.update({
|
|
@@ -391,7 +582,7 @@ export function ChatApp({ agent, config, sessionId, manager, registry, prompt, o
|
|
|
391
582
|
done: true,
|
|
392
583
|
});
|
|
393
584
|
}
|
|
394
|
-
}, [appendLine, config
|
|
585
|
+
}, [agent, appendLine, config]);
|
|
395
586
|
const handleYoloCommand = useCallback(async (args) => {
|
|
396
587
|
if (runningRef.current) {
|
|
397
588
|
appendLine({
|
|
@@ -419,13 +610,13 @@ export function ChatApp({ agent, config, sessionId, manager, registry, prompt, o
|
|
|
419
610
|
});
|
|
420
611
|
return;
|
|
421
612
|
}
|
|
422
|
-
const prev = isYoloEnabled(
|
|
613
|
+
const prev = isYoloEnabled(agent);
|
|
423
614
|
if (prev === enabled) {
|
|
424
615
|
return;
|
|
425
616
|
}
|
|
426
|
-
setYoloEnabled(
|
|
617
|
+
setYoloEnabled(agent, enabled);
|
|
427
618
|
bumpSessionChrome();
|
|
428
|
-
}, [appendLine, bumpSessionChrome
|
|
619
|
+
}, [agent, appendLine, bumpSessionChrome]);
|
|
429
620
|
const handleModeCommand = useCallback(async (args) => {
|
|
430
621
|
if (runningRef.current) {
|
|
431
622
|
appendLine({
|
|
@@ -448,19 +639,19 @@ export function ChatApp({ agent, config, sessionId, manager, registry, prompt, o
|
|
|
448
639
|
id: nowId(),
|
|
449
640
|
role: "system",
|
|
450
641
|
title: "mode",
|
|
451
|
-
content: `Unknown mode "${trimmed}". Use
|
|
642
|
+
content: `Unknown mode "${trimmed}". Use agent, ask, or plan, or open the picker with /mode.`,
|
|
452
643
|
done: true,
|
|
453
644
|
});
|
|
454
645
|
return;
|
|
455
646
|
}
|
|
456
|
-
const prev = getModeState(
|
|
647
|
+
const prev = getModeState(agent).mode;
|
|
457
648
|
if (prev === mode) {
|
|
458
649
|
return;
|
|
459
650
|
}
|
|
460
|
-
setSessionMode(
|
|
461
|
-
applySessionMode(
|
|
651
|
+
setSessionMode(agent, mode);
|
|
652
|
+
applySessionMode(agent);
|
|
462
653
|
bumpSessionChrome();
|
|
463
|
-
}, [appendLine, bumpSessionChrome
|
|
654
|
+
}, [agent, appendLine, bumpSessionChrome]);
|
|
464
655
|
const runTurn = useCallback(async (prompt) => {
|
|
465
656
|
const trimmed = prompt.text.trim();
|
|
466
657
|
if (!trimmed && prompt.attachments.length === 0) {
|
|
@@ -471,7 +662,6 @@ export function ChatApp({ agent, config, sessionId, manager, registry, prompt, o
|
|
|
471
662
|
setRunning(true);
|
|
472
663
|
setStatus("thinking");
|
|
473
664
|
setTurnStartedAt(Date.now());
|
|
474
|
-
setLiveReasoning("");
|
|
475
665
|
setTurnCount((value) => value + 1);
|
|
476
666
|
appendLine({
|
|
477
667
|
id: nowId(),
|
|
@@ -483,14 +673,6 @@ export function ChatApp({ agent, config, sessionId, manager, registry, prompt, o
|
|
|
483
673
|
: trimmed,
|
|
484
674
|
done: true,
|
|
485
675
|
});
|
|
486
|
-
const assistantId = nowId();
|
|
487
|
-
assistantLineIdRef.current = assistantId;
|
|
488
|
-
appendLine({
|
|
489
|
-
id: assistantId,
|
|
490
|
-
role: "assistant",
|
|
491
|
-
content: "",
|
|
492
|
-
done: false,
|
|
493
|
-
});
|
|
494
676
|
try {
|
|
495
677
|
const streamInput = attachmentBlocks.length > 0
|
|
496
678
|
? [
|
|
@@ -503,136 +685,142 @@ export function ChatApp({ agent, config, sessionId, manager, registry, prompt, o
|
|
|
503
685
|
}),
|
|
504
686
|
]
|
|
505
687
|
: 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);
|
|
688
|
+
await runWithAgentMemoryScope(agent, async () => {
|
|
689
|
+
for await (const event of agent.stream(streamInput)) {
|
|
690
|
+
const e = event;
|
|
691
|
+
switch (e.type) {
|
|
692
|
+
case "contentBlockEvent": {
|
|
693
|
+
const block = e.contentBlock;
|
|
694
|
+
if (block.type === "textBlock") {
|
|
695
|
+
finalizeThoughtLine();
|
|
696
|
+
ensureAssistantLine();
|
|
697
|
+
commitAssistantBlock(block.text ?? "");
|
|
519
698
|
}
|
|
520
|
-
else {
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
699
|
+
else if (block.type === "toolUseBlock") {
|
|
700
|
+
finalizeThoughtLine();
|
|
701
|
+
finalizeAssistantLine();
|
|
702
|
+
const toolId = nowId();
|
|
703
|
+
const toolUseId = getToolUseId(block);
|
|
704
|
+
if (toolUseId) {
|
|
705
|
+
toolLineIdsRef.current.set(toolUseId, toolId);
|
|
706
|
+
}
|
|
707
|
+
else {
|
|
708
|
+
pendingToolLineIdsRef.current.push(toolId);
|
|
709
|
+
}
|
|
710
|
+
appendLine({
|
|
711
|
+
id: toolId,
|
|
712
|
+
role: "tool",
|
|
713
|
+
title: "tool",
|
|
714
|
+
toolName: block.name ?? "unknown",
|
|
715
|
+
content: stringifyUnknown(block.input ?? {}),
|
|
716
|
+
phase: "running",
|
|
717
|
+
done: false,
|
|
718
|
+
});
|
|
534
719
|
}
|
|
720
|
+
break;
|
|
535
721
|
}
|
|
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;
|
|
722
|
+
case "toolResultEvent": {
|
|
723
|
+
const resultContent = toToolResultText(e.result);
|
|
724
|
+
const toolUseId = getToolUseId(e.result);
|
|
725
|
+
const fileToolDisplay = takeFileToolDisplay(agent.appState, toolUseId);
|
|
726
|
+
let toolLineId = toolUseId
|
|
727
|
+
? toolLineIdsRef.current.get(toolUseId)
|
|
728
|
+
: undefined;
|
|
729
|
+
if (toolLineId && toolUseId) {
|
|
730
|
+
toolLineIdsRef.current.delete(toolUseId);
|
|
557
731
|
}
|
|
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}`);
|
|
732
|
+
toolLineId ??= pendingToolLineIdsRef.current.shift();
|
|
733
|
+
if (!toolLineId) {
|
|
734
|
+
const firstTrackedTool = toolLineIdsRef.current
|
|
735
|
+
.entries()
|
|
736
|
+
.next();
|
|
737
|
+
if (!firstTrackedTool.done) {
|
|
738
|
+
const [trackedToolUseId, trackedToolLineId] = firstTrackedTool.value;
|
|
739
|
+
toolLineIdsRef.current.delete(trackedToolUseId);
|
|
740
|
+
toolLineId = trackedToolLineId;
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
if (toolLineId) {
|
|
744
|
+
updateLine(toolLineId, {
|
|
745
|
+
phase: "done",
|
|
746
|
+
done: true,
|
|
747
|
+
resultContent,
|
|
748
|
+
fileToolDisplay,
|
|
749
|
+
});
|
|
592
750
|
}
|
|
593
|
-
else
|
|
594
|
-
|
|
751
|
+
else {
|
|
752
|
+
appendLine({
|
|
753
|
+
id: nowId(),
|
|
754
|
+
role: "tool",
|
|
755
|
+
title: "tool",
|
|
756
|
+
toolName: "unknown",
|
|
757
|
+
content: "",
|
|
758
|
+
resultContent,
|
|
759
|
+
fileToolDisplay,
|
|
760
|
+
phase: "done",
|
|
761
|
+
done: true,
|
|
762
|
+
});
|
|
595
763
|
}
|
|
764
|
+
break;
|
|
596
765
|
}
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
766
|
+
case "toolStreamUpdateEvent":
|
|
767
|
+
setStatus("running tool");
|
|
768
|
+
break;
|
|
769
|
+
case "modelStreamUpdateEvent": {
|
|
770
|
+
const modelEvent = e.event;
|
|
771
|
+
if (modelEvent?.type === "modelContentBlockDeltaEvent") {
|
|
772
|
+
const delta = modelEvent.delta;
|
|
773
|
+
if (delta?.type === "reasoningContentDelta" && delta.text) {
|
|
774
|
+
setStatus("thinking");
|
|
775
|
+
appendThoughtText(delta.text);
|
|
776
|
+
}
|
|
777
|
+
else if (delta?.type === "textDelta" && delta.text) {
|
|
778
|
+
finalizeThoughtLine();
|
|
779
|
+
setStatus("streaming");
|
|
780
|
+
ensureAssistantLine();
|
|
781
|
+
appendAssistantText(delta.text);
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
if (modelEvent?.type === "modelMetadataEvent") {
|
|
785
|
+
const u = (modelEvent.usage ?? {});
|
|
786
|
+
const delta = {
|
|
787
|
+
inputTokens: u.inputTokens ?? 0,
|
|
788
|
+
outputTokens: u.outputTokens ?? 0,
|
|
789
|
+
totalTokens: u.totalTokens ?? 0,
|
|
790
|
+
...(u.cacheReadInputTokens !== undefined && {
|
|
791
|
+
cacheReadInputTokens: u.cacheReadInputTokens,
|
|
621
792
|
}),
|
|
622
|
-
...(
|
|
623
|
-
cacheWriteInputTokens:
|
|
793
|
+
...(u.cacheWriteInputTokens !== undefined && {
|
|
794
|
+
cacheWriteInputTokens: u.cacheWriteInputTokens,
|
|
624
795
|
}),
|
|
625
796
|
};
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
797
|
+
const metricsData = (modelEvent.metrics ?? {});
|
|
798
|
+
const lat = metricsData.latencyMs ?? 0;
|
|
799
|
+
// Sum every `modelMetadataEvent` for this chat session (Strands meter semantics). Never reset on
|
|
800
|
+
// new prompts so the footer stays monotonic; note input totals sum per-request prompt sizes.
|
|
801
|
+
setUsage((prev) => {
|
|
802
|
+
const tokens = {
|
|
803
|
+
inputTokens: prev.inputTokens,
|
|
804
|
+
outputTokens: prev.outputTokens,
|
|
805
|
+
totalTokens: prev.totalTokens,
|
|
806
|
+
...(prev.cacheReadInputTokens !== undefined && {
|
|
807
|
+
cacheReadInputTokens: prev.cacheReadInputTokens,
|
|
808
|
+
}),
|
|
809
|
+
...(prev.cacheWriteInputTokens !== undefined && {
|
|
810
|
+
cacheWriteInputTokens: prev.cacheWriteInputTokens,
|
|
811
|
+
}),
|
|
812
|
+
};
|
|
813
|
+
accumulateUsage(tokens, delta);
|
|
814
|
+
return { ...tokens, latencyMs: prev.latencyMs + lat };
|
|
815
|
+
});
|
|
816
|
+
}
|
|
817
|
+
break;
|
|
629
818
|
}
|
|
630
|
-
|
|
819
|
+
default:
|
|
820
|
+
break;
|
|
631
821
|
}
|
|
632
|
-
default:
|
|
633
|
-
break;
|
|
634
822
|
}
|
|
635
|
-
}
|
|
823
|
+
});
|
|
636
824
|
}
|
|
637
825
|
catch (error) {
|
|
638
826
|
appendLine({
|
|
@@ -644,8 +832,8 @@ export function ChatApp({ agent, config, sessionId, manager, registry, prompt, o
|
|
|
644
832
|
});
|
|
645
833
|
}
|
|
646
834
|
finally {
|
|
647
|
-
|
|
648
|
-
|
|
835
|
+
finalizeThoughtLine();
|
|
836
|
+
finalizeAssistantLine();
|
|
649
837
|
for (const toolLineId of toolLineIdsRef.current.values()) {
|
|
650
838
|
updateLine(toolLineId, { phase: "done", done: true });
|
|
651
839
|
}
|
|
@@ -657,19 +845,21 @@ export function ChatApp({ agent, config, sessionId, manager, registry, prompt, o
|
|
|
657
845
|
runningRef.current = false;
|
|
658
846
|
setRunning(false);
|
|
659
847
|
setTurnStartedAt(null);
|
|
660
|
-
setLiveReasoning("");
|
|
661
848
|
setStatus("ready");
|
|
662
|
-
if (isExitRequested(
|
|
849
|
+
if (isExitRequested(agent)) {
|
|
663
850
|
onExit();
|
|
664
851
|
exit();
|
|
665
852
|
}
|
|
666
853
|
}
|
|
667
854
|
}, [
|
|
668
855
|
appendAssistantText,
|
|
856
|
+
appendThoughtText,
|
|
669
857
|
appendLine,
|
|
670
|
-
|
|
858
|
+
agent,
|
|
671
859
|
exit,
|
|
672
|
-
|
|
860
|
+
ensureAssistantLine,
|
|
861
|
+
finalizeAssistantLine,
|
|
862
|
+
finalizeThoughtLine,
|
|
673
863
|
onExit,
|
|
674
864
|
updateLine,
|
|
675
865
|
]);
|
|
@@ -680,6 +870,9 @@ export function ChatApp({ agent, config, sessionId, manager, registry, prompt, o
|
|
|
680
870
|
const queueRef = useRef(null);
|
|
681
871
|
if (!queueRef.current) {
|
|
682
872
|
queueRef.current = fastq.promise(async (item) => {
|
|
873
|
+
if (skippedQueueIdsRef.current.delete(item.id)) {
|
|
874
|
+
return;
|
|
875
|
+
}
|
|
683
876
|
if (mountedRef.current) {
|
|
684
877
|
setQueuedPrompts((prev) => prev.filter((entry) => entry.id !== item.id));
|
|
685
878
|
}
|
|
@@ -702,6 +895,7 @@ export function ChatApp({ agent, config, sessionId, manager, registry, prompt, o
|
|
|
702
895
|
id: nowId(),
|
|
703
896
|
prompt: { ...normalized, text: trimmed },
|
|
704
897
|
};
|
|
898
|
+
setTranscriptScrollOffset(0);
|
|
705
899
|
setQueuedPrompts((prev) => [...prev, item]);
|
|
706
900
|
void queueRef.current?.push(item).catch((error) => {
|
|
707
901
|
if (!mountedRef.current) {
|
|
@@ -728,8 +922,37 @@ export function ChatApp({ agent, config, sessionId, manager, registry, prompt, o
|
|
|
728
922
|
if (pendingApproval) {
|
|
729
923
|
return;
|
|
730
924
|
}
|
|
925
|
+
const trimmed = value.text.trim();
|
|
926
|
+
if (runningRef.current &&
|
|
927
|
+
!trimmed &&
|
|
928
|
+
value.attachments.length === 0 &&
|
|
929
|
+
queuedPromptsRef.current.length > 0) {
|
|
930
|
+
const queued = queuedPromptsRef.current;
|
|
931
|
+
queuedPromptsRef.current = [];
|
|
932
|
+
for (const item of queued) {
|
|
933
|
+
skippedQueueIdsRef.current.add(item.id);
|
|
934
|
+
}
|
|
935
|
+
setQueuedPrompts([]);
|
|
936
|
+
if (steering.queue(queued.map((item) => item.prompt))) {
|
|
937
|
+
appendLine({
|
|
938
|
+
id: nowId(),
|
|
939
|
+
role: "system",
|
|
940
|
+
title: "steering",
|
|
941
|
+
content: `Steered the active turn with ${queued.length} queued prompt${queued.length === 1 ? "" : "s"}.`,
|
|
942
|
+
done: true,
|
|
943
|
+
});
|
|
944
|
+
}
|
|
945
|
+
setInput("");
|
|
946
|
+
return;
|
|
947
|
+
}
|
|
731
948
|
const command = parseChatCommand(value.text);
|
|
732
949
|
if (command && value.attachments.length === 0) {
|
|
950
|
+
if (command.name === "init") {
|
|
951
|
+
if (pushPrompt(INIT_AGENTS_PROMPT)) {
|
|
952
|
+
setInput("");
|
|
953
|
+
}
|
|
954
|
+
return;
|
|
955
|
+
}
|
|
733
956
|
if (command.name === "model") {
|
|
734
957
|
void handleModelCommand(command.args);
|
|
735
958
|
setInput("");
|
|
@@ -747,23 +970,42 @@ export function ChatApp({ agent, config, sessionId, manager, registry, prompt, o
|
|
|
747
970
|
}
|
|
748
971
|
}
|
|
749
972
|
if (pushPrompt(value)) {
|
|
750
|
-
setFollowRequest((value) => value + 1);
|
|
751
973
|
setInput("");
|
|
752
974
|
}
|
|
753
975
|
}, [
|
|
976
|
+
appendLine,
|
|
754
977
|
handleModelCommand,
|
|
755
978
|
handleModeCommand,
|
|
756
979
|
handleYoloCommand,
|
|
757
980
|
pendingApproval,
|
|
758
981
|
pushPrompt,
|
|
982
|
+
steering,
|
|
759
983
|
]);
|
|
760
984
|
useInput((inputKey, key) => {
|
|
761
985
|
if (isMouseInput(inputKey)) {
|
|
762
986
|
return;
|
|
763
987
|
}
|
|
988
|
+
if (!key.ctrl && !key.meta && !key.super) {
|
|
989
|
+
if (key.pageUp) {
|
|
990
|
+
setTranscriptScrollOffset((offset) => Math.min(Math.max(0, lines.length - 1), offset + transcriptScrollStep));
|
|
991
|
+
return;
|
|
992
|
+
}
|
|
993
|
+
if (key.pageDown) {
|
|
994
|
+
setTranscriptScrollOffset((offset) => Math.max(0, offset - transcriptScrollStep));
|
|
995
|
+
return;
|
|
996
|
+
}
|
|
997
|
+
if (key.home) {
|
|
998
|
+
setTranscriptScrollOffset(Math.max(0, lines.length - 1));
|
|
999
|
+
return;
|
|
1000
|
+
}
|
|
1001
|
+
if (key.end) {
|
|
1002
|
+
setTranscriptScrollOffset(0);
|
|
1003
|
+
return;
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
764
1006
|
if (key.ctrl && inputKey.toLowerCase() === "c") {
|
|
765
1007
|
if (runningRef.current) {
|
|
766
|
-
|
|
1008
|
+
agent.cancel();
|
|
767
1009
|
setStatus("cancel requested");
|
|
768
1010
|
return;
|
|
769
1011
|
}
|
|
@@ -781,7 +1023,7 @@ export function ChatApp({ agent, config, sessionId, manager, registry, prompt, o
|
|
|
781
1023
|
return;
|
|
782
1024
|
}
|
|
783
1025
|
if (runningRef.current) {
|
|
784
|
-
|
|
1026
|
+
agent.cancel();
|
|
785
1027
|
setStatus("cancel requested");
|
|
786
1028
|
return;
|
|
787
1029
|
}
|
|
@@ -798,46 +1040,39 @@ export function ChatApp({ agent, config, sessionId, manager, registry, prompt, o
|
|
|
798
1040
|
const sec = seconds % 60;
|
|
799
1041
|
return `${String(min).padStart(2, "0")}:${String(sec).padStart(2, "0")}`;
|
|
800
1042
|
}, [turnElapsedMs]);
|
|
801
|
-
const
|
|
802
|
-
const
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
label: `Ask • read only tools, no plan workflow${getModeState(currentAgent).mode === "ask" ? " • current" : ""}`,
|
|
836
|
-
value: "ask",
|
|
837
|
-
},
|
|
838
|
-
], onSelect: (v) => {
|
|
839
|
-
setPicker(null);
|
|
840
|
-
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: INPUT_HINT, onChange: setInput, onSubmit: onSubmit, slashMenu: slashMenu })) : null, _jsx(StatusBar, { running: running, status: status, statusLabel: statusLabel, sessionId: sessionId, currentModel: currentModelLabel(config), yoloOn: isYoloEnabled(currentAgent), sessionMode: getModeState(currentAgent).mode, elapsedLabel: elapsedLabel, turnCount: turnCount, totalTools: totalTools, skillsFound: skillsFound, manager: currentManager, usage: usage })] })] }));
|
|
1043
|
+
const inputHint = running && queuedPrompts.length > 0 ? INPUT_HINT_WITH_STEERING : INPUT_HINT;
|
|
1044
|
+
const transcriptRows = useMemo(() => Math.max(6, windowSize.rows -
|
|
1045
|
+
estimateChromeRows({
|
|
1046
|
+
running,
|
|
1047
|
+
todoCount: todoState.visible ? todoState.todos.length : 0,
|
|
1048
|
+
queueCount: queuedPrompts.length,
|
|
1049
|
+
pendingApproval: Boolean(pendingApproval),
|
|
1050
|
+
picker,
|
|
1051
|
+
slashCommandCount: !pendingApproval && !picker ? slashCommands.length : 0,
|
|
1052
|
+
}) -
|
|
1053
|
+
2), [
|
|
1054
|
+
pendingApproval,
|
|
1055
|
+
picker,
|
|
1056
|
+
queuedPrompts.length,
|
|
1057
|
+
running,
|
|
1058
|
+
slashCommands.length,
|
|
1059
|
+
todoState.todos.length,
|
|
1060
|
+
todoState.visible,
|
|
1061
|
+
windowSize.rows,
|
|
1062
|
+
]);
|
|
1063
|
+
const transcriptScrollStep = useMemo(() => Math.max(1, Math.floor(transcriptRows / 3)), [transcriptRows]);
|
|
1064
|
+
useEffect(() => {
|
|
1065
|
+
setTranscriptScrollOffset((offset) => Math.min(offset, lines.length - 1));
|
|
1066
|
+
}, [lines.length]);
|
|
1067
|
+
return (_jsxs(Box, { flexDirection: "column", width: "100%", paddingX: 1, height: Math.max(1, windowSize.rows - 1), children: [_jsx(Transcript, { lines: lines, assistantName: config.name, showEmptyBanner: lines.length === 0, marginTop: 1, maxRows: transcriptRows, scrollOffset: transcriptScrollOffset }), _jsx(BottomChrome, { config: config, running: running, status: status, sessionId: sessionId, currentModel: currentModelLabel(config), yoloOn: isYoloEnabled(agent), sessionMode: getModeState(agent).mode, elapsedLabel: elapsedLabel, turnCount: turnCount, totalTools: totalTools, skillsFound: skillsFound, manager: manager, usage: usage, todoState: todoState, queuedPrompts: queuedPrompts, pendingApproval: Boolean(pendingApproval), picker: picker, slashCommands: slashCommands, slashHighlightIndex: slashHighlightIndex, input: input, inputHint: inputHint, slashMenu: slashMenu, onApprovalDecision: (decision) => approvals.decide(decision), onModelSelect: (name) => {
|
|
1068
|
+
setPicker(null);
|
|
1069
|
+
void handleModelCommand(name);
|
|
1070
|
+
}, onYoloSelect: (value) => {
|
|
1071
|
+
setPicker(null);
|
|
1072
|
+
void handleYoloCommand(value);
|
|
1073
|
+
}, onModeSelect: (value) => {
|
|
1074
|
+
setPicker(null);
|
|
1075
|
+
void handleModeCommand(value);
|
|
1076
|
+
}, onInputChange: setInput, onSubmit: onSubmit })] }));
|
|
842
1077
|
}
|
|
843
1078
|
//# sourceMappingURL=app.js.map
|