@markusylisiurunen/tau 0.1.54 → 0.1.56
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 +18 -0
- package/dist/app.js +19 -240
- package/dist/app.js.map +1 -1
- package/dist/config.js +1 -0
- package/dist/config.js.map +1 -1
- package/dist/content_loader.js +70 -41
- package/dist/content_loader.js.map +1 -1
- package/dist/debug.js +22 -7
- package/dist/debug.js.map +1 -1
- package/dist/main.js +19 -8
- package/dist/main.js.map +1 -1
- package/dist/session/session_engine.js +8 -6
- package/dist/session/session_engine.js.map +1 -1
- package/dist/subagents/subagent_engine.js +6 -1
- package/dist/subagents/subagent_engine.js.map +1 -1
- package/dist/tool_ui_router.js +274 -0
- package/dist/tool_ui_router.js.map +1 -0
- package/dist/tools/bash.js +32 -104
- package/dist/tools/bash.js.map +1 -1
- package/dist/tools/grep.js +20 -72
- package/dist/tools/grep.js.map +1 -1
- package/dist/ui/file_execution.js +12 -45
- package/dist/ui/file_execution.js.map +1 -1
- package/dist/ui/restricted_execution.js +16 -66
- package/dist/ui/restricted_execution.js.map +1 -1
- package/dist/ui/tool_output_helpers.js +30 -0
- package/dist/ui/tool_output_helpers.js.map +1 -0
- package/dist/utils/agents_files.js +156 -0
- package/dist/utils/agents_files.js.map +1 -0
- package/dist/utils/context.js +2 -275
- package/dist/utils/context.js.map +1 -1
- package/dist/utils/context_builder.js +123 -0
- package/dist/utils/context_builder.js.map +1 -0
- package/dist/utils/flex_retry.js +12 -0
- package/dist/utils/flex_retry.js.map +1 -0
- package/dist/utils/project_files.js +11 -153
- package/dist/utils/project_files.js.map +1 -1
- package/dist/utils/spawn_capture.js +135 -0
- package/dist/utils/spawn_capture.js.map +1 -0
- package/dist/utils/truncate.js +131 -101
- package/dist/utils/truncate.js.map +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -224,6 +224,7 @@ store settings in `~/.config/tau/config.json`:
|
|
|
224
224
|
"defaultPersona": "gpt-5.2-chat",
|
|
225
225
|
"defaultRisk": "read-write",
|
|
226
226
|
"toolDisplayMode": "compact",
|
|
227
|
+
"disableBuiltinPersonas": false,
|
|
227
228
|
"userPreferences": "prefer concise responses. use TypeScript for examples."
|
|
228
229
|
}
|
|
229
230
|
```
|
|
@@ -236,6 +237,8 @@ the `userPreferences` field lets you set guidance that applies to every conversa
|
|
|
236
237
|
|
|
237
238
|
`toolDisplayMode` controls how tool calls appear: `"compact"` (default) shows one-line summaries, `"full"` shows detailed blocks.
|
|
238
239
|
|
|
240
|
+
if `disableBuiltinPersonas` is set to `true`, tau will not load any built-in personas. only personas from `~/.config/tau/personas/` and `.tau/personas/` will be available.
|
|
241
|
+
|
|
239
242
|
### project bash commands
|
|
240
243
|
|
|
241
244
|
define shortcuts for common shell commands in `.tau/config.json` at your project root (or `~/.tau/config.json` globally). tau resolves the project root via git, so you can run tau from subdirectories and it will still pick up `.tau/config.json`:
|
|
@@ -280,6 +283,7 @@ the frontmatter defines the persona's id, provider, and model. the markdown body
|
|
|
280
283
|
|
|
281
284
|
you can also set model parameters via optional frontmatter fields:
|
|
282
285
|
|
|
286
|
+
- `extends`: inherit settings from a built-in persona id (for example `gpt-5.2-coder`). only optional fields are inherited; `provider` and `model` are still required on the extending persona. if the markdown body is empty, the base persona's system prompt is used.
|
|
283
287
|
- `reasoning`: one of `none`, `minimal`, `low`, `medium`, `high`, `xhigh`
|
|
284
288
|
- `allowedReasoningLevels`: list of reasoning levels shown in the ui
|
|
285
289
|
- `skills`: list of enabled skill names (matched by `name` in skill frontmatter), or `"*"` to enable all discovered skills
|
|
@@ -295,6 +299,20 @@ you can also set model parameters via optional frontmatter fields:
|
|
|
295
299
|
|
|
296
300
|
use it with `--persona my-assistant` or `/persona:my-assistant`. if a project persona id conflicts with a user or built-in persona, the project persona wins.
|
|
297
301
|
|
|
302
|
+
to clone a built-in persona but swap the provider/model, use `extends`:
|
|
303
|
+
|
|
304
|
+
```markdown
|
|
305
|
+
---
|
|
306
|
+
id: my-haiku-coder
|
|
307
|
+
extends: gpt-5.2-coder
|
|
308
|
+
provider: anthropic
|
|
309
|
+
model: claude-haiku-4-5
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
by default, user-level personas can’t use built-in persona ids. if you set `disableBuiltinPersonas: true`, those ids become available for custom personas.
|
|
315
|
+
|
|
298
316
|
### custom prompts
|
|
299
317
|
|
|
300
318
|
save reusable prompt templates in `~/.config/tau/prompts/` (user-level) or `.tau/prompts/` (project-level). project-level `.tau/` directories are discovered by walking up from the current working directory to the git repo root:
|
package/dist/app.js
CHANGED
|
@@ -13,6 +13,7 @@ import { renderExport } from "./export/index.js";
|
|
|
13
13
|
import { SessionEngine } from "./session/session_engine.js";
|
|
14
14
|
import { formatSubagentsForPrompt } from "./subagents/registry.js";
|
|
15
15
|
import { createAppTerminal } from "./terminal.js";
|
|
16
|
+
import { ToolUiRouter } from "./tool_ui_router.js";
|
|
16
17
|
import { BASH_USER_MAX_STDERR_LINES, BASH_USER_MAX_STDERR_TOKENS, BASH_USER_MAX_STDOUT_LINES, BASH_USER_MAX_STDOUT_TOKENS, createBashToolDefinition, executeBashTool, formatBashUserMessageText, prepareBashOutput, } from "./tools/bash.js";
|
|
17
18
|
import { createEditToolDefinition } from "./tools/edit.js";
|
|
18
19
|
import { createForkToolDefinition } from "./tools/fork.js";
|
|
@@ -23,15 +24,12 @@ import { ToolRegistry } from "./tools/registry.js";
|
|
|
23
24
|
import { createTaskToolDefinition } from "./tools/task.js";
|
|
24
25
|
import { createWriteToolDefinition } from "./tools/write.js";
|
|
25
26
|
import { REASONING_LEVELS, } from "./types.js";
|
|
26
|
-
import {
|
|
27
|
+
import { buildBashExecutionView } from "./ui/bash_execution.js";
|
|
27
28
|
import { ChatContainerComponent } from "./ui/chat_container.js";
|
|
28
29
|
import { CustomEditor } from "./ui/custom_editor.js";
|
|
29
|
-
import { buildEditBlockedView, buildEditSuccessView, buildWriteBlockedView, buildWriteSuccessView, } from "./ui/file_execution.js";
|
|
30
30
|
import { FooterComponent } from "./ui/footer.js";
|
|
31
31
|
import { QueuedMessagesComponent } from "./ui/queued_messages.js";
|
|
32
|
-
import { buildGrepBlockedView, buildGrepFinishedView, buildGrepRunningView, buildListBlockedView, buildListSuccessView, buildReadBlockedView, buildReadSuccessView, } from "./ui/restricted_execution.js";
|
|
33
32
|
import { getFileAutocompleteToken, SlashAutocompleteProvider } from "./ui/slash_autocomplete.js";
|
|
34
|
-
import { buildTaskBlockedView, buildTaskFinishedView, buildTaskRunningView, } from "./ui/task_execution.js";
|
|
35
33
|
import { createUiTheme } from "./ui/theme.js";
|
|
36
34
|
import { buildThemePreviewMessages } from "./ui/theme_preview.js";
|
|
37
35
|
import { buildBaseSystemPrompt, buildEnvironmentTag, buildProjectContextBlock, buildSkillsIndexBlock, findAgentsFilesInScopeDetailed, formatRiskLevelChangeNotice, } from "./utils/context.js";
|
|
@@ -40,7 +38,7 @@ import { formatAdaptiveNumber, formatCwd, formatTokenWindow } from "./utils/form
|
|
|
40
38
|
import { getGitRoot } from "./utils/git.js";
|
|
41
39
|
import { extractAllFencedCodeBlocks, extractAssistantText } from "./utils/messages.js";
|
|
42
40
|
import { streamModel } from "./utils/model_stream.js";
|
|
43
|
-
import {
|
|
41
|
+
import { listProjectFilesAsync } from "./utils/project_files.js";
|
|
44
42
|
import { APP_VERSION } from "./version.js";
|
|
45
43
|
export class ChatApp {
|
|
46
44
|
ui;
|
|
@@ -49,6 +47,7 @@ export class ChatApp {
|
|
|
49
47
|
queuedMessages;
|
|
50
48
|
editor;
|
|
51
49
|
uiTheme;
|
|
50
|
+
toolUiRouter;
|
|
52
51
|
personas;
|
|
53
52
|
currentPersona;
|
|
54
53
|
prompts;
|
|
@@ -58,10 +57,6 @@ export class ChatApp {
|
|
|
58
57
|
initialUserMessage;
|
|
59
58
|
config;
|
|
60
59
|
engine;
|
|
61
|
-
runningBashComponents = new Map();
|
|
62
|
-
runningTaskComponents = new Map();
|
|
63
|
-
taskEvents = new Map(); // toolCallId -> accumulated events
|
|
64
|
-
subagentCostTotal = 0;
|
|
65
60
|
isStreaming = false;
|
|
66
61
|
queuedUserMessages = [];
|
|
67
62
|
isDrainingQueuedUserMessages = false;
|
|
@@ -119,7 +114,8 @@ export class ChatApp {
|
|
|
119
114
|
agentsFiles: this.agentsFiles,
|
|
120
115
|
})
|
|
121
116
|
: undefined;
|
|
122
|
-
this.projectFiles =
|
|
117
|
+
this.projectFiles = [];
|
|
118
|
+
this.refreshProjectFilesInBackground();
|
|
123
119
|
this.currentPersona =
|
|
124
120
|
(options.initialPersonaId &&
|
|
125
121
|
this.personas.find((p) => p.id.toLowerCase() === options.initialPersonaId.toLowerCase())) ||
|
|
@@ -170,6 +166,12 @@ export class ChatApp {
|
|
|
170
166
|
this.footer = new FooterComponent(this.uiTheme, this.ui);
|
|
171
167
|
this.queuedMessages = new QueuedMessagesComponent(this.uiTheme, this.queuedUserMessages);
|
|
172
168
|
this.editor = new CustomEditor(this.uiTheme);
|
|
169
|
+
this.toolUiRouter = new ToolUiRouter({
|
|
170
|
+
theme: this.uiTheme,
|
|
171
|
+
chatContainer: this.chatContainer,
|
|
172
|
+
requestRender: () => this.ui.requestRender(),
|
|
173
|
+
onCostUpdated: () => this.updateFooter(),
|
|
174
|
+
});
|
|
173
175
|
this.setupUI();
|
|
174
176
|
this.setupEditor();
|
|
175
177
|
}
|
|
@@ -262,6 +264,7 @@ export class ChatApp {
|
|
|
262
264
|
void listProjectFilesAsync(process.cwd())
|
|
263
265
|
.then((files) => {
|
|
264
266
|
this.projectFiles = files;
|
|
267
|
+
this.ui.requestRender();
|
|
265
268
|
})
|
|
266
269
|
.catch(() => {
|
|
267
270
|
// Ignore refresh errors; autocomplete will keep using the existing cache.
|
|
@@ -398,7 +401,7 @@ export class ChatApp {
|
|
|
398
401
|
total += m.usage?.cost?.total ?? 0;
|
|
399
402
|
}
|
|
400
403
|
}
|
|
401
|
-
return `$${formatAdaptiveNumber(total + this.
|
|
404
|
+
return `$${formatAdaptiveNumber(total + this.toolUiRouter.getSubagentCostTotal(), 2, 5)}`;
|
|
402
405
|
}
|
|
403
406
|
getTurnDurationString() {
|
|
404
407
|
const now = Date.now();
|
|
@@ -896,10 +899,7 @@ export class ChatApp {
|
|
|
896
899
|
}
|
|
897
900
|
clearSession() {
|
|
898
901
|
this.engine.reset();
|
|
899
|
-
this.
|
|
900
|
-
this.runningTaskComponents.clear();
|
|
901
|
-
this.taskEvents.clear();
|
|
902
|
-
this.subagentCostTotal = 0;
|
|
902
|
+
this.toolUiRouter.resetSession();
|
|
903
903
|
this.expandedFilesInCurrentPrompt.clear();
|
|
904
904
|
this.expandedSkillsInCurrentPrompt.clear();
|
|
905
905
|
this.chatContainer.addMessage({ type: "session_divider", label: "new session" });
|
|
@@ -1032,10 +1032,7 @@ Write plain prose, no formatting. Be thorough enough that the reader can resume
|
|
|
1032
1032
|
this.previousSessionSummary = previousSessionContext;
|
|
1033
1033
|
// Reset the session state but preserve history with divider and summary
|
|
1034
1034
|
this.engine.reset();
|
|
1035
|
-
this.
|
|
1036
|
-
this.runningTaskComponents.clear();
|
|
1037
|
-
this.taskEvents.clear();
|
|
1038
|
-
this.subagentCostTotal = 0;
|
|
1035
|
+
this.toolUiRouter.resetSession();
|
|
1039
1036
|
this.expandedFilesInCurrentPrompt.clear();
|
|
1040
1037
|
this.expandedSkillsInCurrentPrompt.clear();
|
|
1041
1038
|
this.chatContainer.addMessage({ type: "session_divider", label: "new session" });
|
|
@@ -1339,211 +1336,7 @@ Write plain prose, no formatting. Be thorough enough that the reader can resume
|
|
|
1339
1336
|
break;
|
|
1340
1337
|
}
|
|
1341
1338
|
case "tool_ui": {
|
|
1342
|
-
|
|
1343
|
-
if (uiEvent.type === "bash_started") {
|
|
1344
|
-
this.chatContainer.addMessage({
|
|
1345
|
-
type: "tool",
|
|
1346
|
-
view: buildBashRunningView(this.uiTheme, uiEvent.command),
|
|
1347
|
-
}, uiEvent.toolCallId);
|
|
1348
|
-
this.runningBashComponents.set(uiEvent.toolCallId, {
|
|
1349
|
-
command: uiEvent.command,
|
|
1350
|
-
});
|
|
1351
|
-
this.ui.requestRender();
|
|
1352
|
-
}
|
|
1353
|
-
else if (uiEvent.type === "bash_execution") {
|
|
1354
|
-
const running = this.runningBashComponents.get(uiEvent.toolCallId);
|
|
1355
|
-
this.chatContainer.replaceMessage(uiEvent.toolCallId, {
|
|
1356
|
-
type: "tool",
|
|
1357
|
-
view: buildBashExecutionView(this.uiTheme, uiEvent.command, uiEvent.exitCode, uiEvent.truncationInfo, uiEvent.durationMs),
|
|
1358
|
-
});
|
|
1359
|
-
if (running) {
|
|
1360
|
-
this.runningBashComponents.delete(uiEvent.toolCallId);
|
|
1361
|
-
}
|
|
1362
|
-
this.ui.requestRender();
|
|
1363
|
-
}
|
|
1364
|
-
else if (uiEvent.type === "bash_blocked") {
|
|
1365
|
-
if (uiEvent.toolCallId) {
|
|
1366
|
-
const running = this.runningBashComponents.get(uiEvent.toolCallId);
|
|
1367
|
-
this.chatContainer.replaceMessage(uiEvent.toolCallId, {
|
|
1368
|
-
type: "tool",
|
|
1369
|
-
view: buildBashBlockedView(this.uiTheme, uiEvent.command, uiEvent.reason),
|
|
1370
|
-
});
|
|
1371
|
-
if (running) {
|
|
1372
|
-
this.runningBashComponents.delete(uiEvent.toolCallId);
|
|
1373
|
-
}
|
|
1374
|
-
}
|
|
1375
|
-
else {
|
|
1376
|
-
this.chatContainer.addMessage({
|
|
1377
|
-
type: "tool",
|
|
1378
|
-
view: buildBashBlockedView(this.uiTheme, uiEvent.command, uiEvent.reason),
|
|
1379
|
-
});
|
|
1380
|
-
}
|
|
1381
|
-
this.ui.requestRender();
|
|
1382
|
-
}
|
|
1383
|
-
else if (uiEvent.type === "task_started") {
|
|
1384
|
-
if (!this.taskEvents.has(uiEvent.toolCallId)) {
|
|
1385
|
-
this.taskEvents.set(uiEvent.toolCallId, []);
|
|
1386
|
-
}
|
|
1387
|
-
const kind = uiEvent.kind ?? "task";
|
|
1388
|
-
const subagentName = uiEvent.name.trim() || undefined;
|
|
1389
|
-
this.chatContainer.addMessage({
|
|
1390
|
-
type: "tool",
|
|
1391
|
-
view: buildTaskRunningView(this.uiTheme, uiEvent.title, [], 0, 0, 0, {
|
|
1392
|
-
kind,
|
|
1393
|
-
subagentName,
|
|
1394
|
-
}),
|
|
1395
|
-
}, uiEvent.toolCallId);
|
|
1396
|
-
this.runningTaskComponents.set(uiEvent.toolCallId, {
|
|
1397
|
-
kind,
|
|
1398
|
-
name: subagentName,
|
|
1399
|
-
title: uiEvent.title,
|
|
1400
|
-
costTotal: 0,
|
|
1401
|
-
turns: 0,
|
|
1402
|
-
toolCalls: 0,
|
|
1403
|
-
});
|
|
1404
|
-
this.ui.requestRender();
|
|
1405
|
-
}
|
|
1406
|
-
else if (uiEvent.type === "task_progress") {
|
|
1407
|
-
let events = this.taskEvents.get(uiEvent.toolCallId);
|
|
1408
|
-
if (!events) {
|
|
1409
|
-
events = [];
|
|
1410
|
-
this.taskEvents.set(uiEvent.toolCallId, events);
|
|
1411
|
-
}
|
|
1412
|
-
events.push(uiEvent.event);
|
|
1413
|
-
const running = this.runningTaskComponents.get(uiEvent.toolCallId);
|
|
1414
|
-
const kind = uiEvent.kind ?? running?.kind ?? "task";
|
|
1415
|
-
const subagentName = uiEvent.name.trim() || undefined;
|
|
1416
|
-
if (running) {
|
|
1417
|
-
running.kind = kind;
|
|
1418
|
-
running.name = subagentName;
|
|
1419
|
-
running.title = uiEvent.title;
|
|
1420
|
-
running.costTotal = uiEvent.costTotal;
|
|
1421
|
-
running.turns = uiEvent.turns;
|
|
1422
|
-
running.toolCalls = uiEvent.toolCalls;
|
|
1423
|
-
}
|
|
1424
|
-
this.chatContainer.replaceMessage(uiEvent.toolCallId, {
|
|
1425
|
-
type: "tool",
|
|
1426
|
-
view: buildTaskRunningView(this.uiTheme, uiEvent.title, events, uiEvent.costTotal, uiEvent.turns, uiEvent.toolCalls, { kind, subagentName }),
|
|
1427
|
-
});
|
|
1428
|
-
this.ui.requestRender();
|
|
1429
|
-
}
|
|
1430
|
-
else if (uiEvent.type === "task_finished") {
|
|
1431
|
-
const running = this.runningTaskComponents.get(uiEvent.toolCallId);
|
|
1432
|
-
const kind = uiEvent.kind ?? running?.kind ?? "task";
|
|
1433
|
-
const subagentName = uiEvent.name.trim() || undefined;
|
|
1434
|
-
this.chatContainer.replaceMessage(uiEvent.toolCallId, {
|
|
1435
|
-
type: "tool",
|
|
1436
|
-
view: buildTaskFinishedView(this.uiTheme, uiEvent.title, uiEvent.costTotal, uiEvent.turns, uiEvent.toolCalls, uiEvent.status, uiEvent.finalOutput, { kind, subagentName }),
|
|
1437
|
-
});
|
|
1438
|
-
this.runningTaskComponents.delete(uiEvent.toolCallId);
|
|
1439
|
-
this.taskEvents.delete(uiEvent.toolCallId);
|
|
1440
|
-
this.subagentCostTotal += uiEvent.costTotal;
|
|
1441
|
-
this.updateFooter();
|
|
1442
|
-
this.ui.requestRender();
|
|
1443
|
-
}
|
|
1444
|
-
else if (uiEvent.type === "task_blocked") {
|
|
1445
|
-
const running = this.runningTaskComponents.get(uiEvent.toolCallId);
|
|
1446
|
-
const kind = uiEvent.kind ?? running?.kind ?? "task";
|
|
1447
|
-
const subagentName = uiEvent.name?.trim() || undefined;
|
|
1448
|
-
if (running) {
|
|
1449
|
-
this.chatContainer.replaceMessage(uiEvent.toolCallId, {
|
|
1450
|
-
type: "tool",
|
|
1451
|
-
view: buildTaskBlockedView(this.uiTheme, uiEvent.title, uiEvent.reason, {
|
|
1452
|
-
kind,
|
|
1453
|
-
subagentName,
|
|
1454
|
-
}),
|
|
1455
|
-
});
|
|
1456
|
-
}
|
|
1457
|
-
else {
|
|
1458
|
-
this.chatContainer.addMessage({
|
|
1459
|
-
type: "tool",
|
|
1460
|
-
view: buildTaskBlockedView(this.uiTheme, uiEvent.title, uiEvent.reason, {
|
|
1461
|
-
kind,
|
|
1462
|
-
subagentName,
|
|
1463
|
-
}),
|
|
1464
|
-
}, uiEvent.toolCallId);
|
|
1465
|
-
}
|
|
1466
|
-
this.runningTaskComponents.delete(uiEvent.toolCallId);
|
|
1467
|
-
this.taskEvents.delete(uiEvent.toolCallId);
|
|
1468
|
-
this.ui.requestRender();
|
|
1469
|
-
}
|
|
1470
|
-
else if (uiEvent.type === "write_success") {
|
|
1471
|
-
this.chatContainer.addMessage({
|
|
1472
|
-
type: "tool",
|
|
1473
|
-
view: buildWriteSuccessView(this.uiTheme, uiEvent.path, uiEvent.bytes, uiEvent.lines, uiEvent.content),
|
|
1474
|
-
});
|
|
1475
|
-
this.ui.requestRender();
|
|
1476
|
-
}
|
|
1477
|
-
else if (uiEvent.type === "write_blocked") {
|
|
1478
|
-
this.chatContainer.addMessage({
|
|
1479
|
-
type: "tool",
|
|
1480
|
-
view: buildWriteBlockedView(this.uiTheme, uiEvent.path, uiEvent.reason),
|
|
1481
|
-
});
|
|
1482
|
-
this.ui.requestRender();
|
|
1483
|
-
}
|
|
1484
|
-
else if (uiEvent.type === "edit_success") {
|
|
1485
|
-
this.chatContainer.addMessage({
|
|
1486
|
-
type: "tool",
|
|
1487
|
-
view: buildEditSuccessView(this.uiTheme, uiEvent.path, uiEvent.oldLength, uiEvent.newLength, uiEvent.oldText, uiEvent.newText),
|
|
1488
|
-
});
|
|
1489
|
-
this.ui.requestRender();
|
|
1490
|
-
}
|
|
1491
|
-
else if (uiEvent.type === "edit_blocked") {
|
|
1492
|
-
this.chatContainer.addMessage({
|
|
1493
|
-
type: "tool",
|
|
1494
|
-
view: buildEditBlockedView(this.uiTheme, uiEvent.path, uiEvent.reason),
|
|
1495
|
-
});
|
|
1496
|
-
this.ui.requestRender();
|
|
1497
|
-
}
|
|
1498
|
-
else if (uiEvent.type === "read_success") {
|
|
1499
|
-
this.chatContainer.addMessage({
|
|
1500
|
-
type: "tool",
|
|
1501
|
-
view: buildReadSuccessView(this.uiTheme, uiEvent.path, uiEvent.startLine, uiEvent.endLine, uiEvent.content, uiEvent.modelTruncation),
|
|
1502
|
-
});
|
|
1503
|
-
this.ui.requestRender();
|
|
1504
|
-
}
|
|
1505
|
-
else if (uiEvent.type === "read_blocked") {
|
|
1506
|
-
this.chatContainer.addMessage({
|
|
1507
|
-
type: "tool",
|
|
1508
|
-
view: buildReadBlockedView(this.uiTheme, uiEvent.path, uiEvent.reason),
|
|
1509
|
-
});
|
|
1510
|
-
this.ui.requestRender();
|
|
1511
|
-
}
|
|
1512
|
-
else if (uiEvent.type === "list_success") {
|
|
1513
|
-
this.chatContainer.addMessage({
|
|
1514
|
-
type: "tool",
|
|
1515
|
-
view: buildListSuccessView(this.uiTheme, uiEvent.path, uiEvent.offset, uiEvent.limit, uiEvent.total, uiEvent.returned, uiEvent.entries),
|
|
1516
|
-
});
|
|
1517
|
-
this.ui.requestRender();
|
|
1518
|
-
}
|
|
1519
|
-
else if (uiEvent.type === "list_blocked") {
|
|
1520
|
-
this.chatContainer.addMessage({
|
|
1521
|
-
type: "tool",
|
|
1522
|
-
view: buildListBlockedView(this.uiTheme, uiEvent.path, uiEvent.reason),
|
|
1523
|
-
});
|
|
1524
|
-
this.ui.requestRender();
|
|
1525
|
-
}
|
|
1526
|
-
else if (uiEvent.type === "grep_started") {
|
|
1527
|
-
this.chatContainer.addMessage({
|
|
1528
|
-
type: "tool",
|
|
1529
|
-
view: buildGrepRunningView(this.uiTheme, uiEvent.pattern),
|
|
1530
|
-
}, uiEvent.toolCallId);
|
|
1531
|
-
this.ui.requestRender();
|
|
1532
|
-
}
|
|
1533
|
-
else if (uiEvent.type === "grep_finished") {
|
|
1534
|
-
this.chatContainer.replaceMessage(uiEvent.toolCallId, {
|
|
1535
|
-
type: "tool",
|
|
1536
|
-
view: buildGrepFinishedView(this.uiTheme, uiEvent.pattern, uiEvent.status, uiEvent.exitCode, uiEvent.stdout, uiEvent.stderr, uiEvent.captureTruncated),
|
|
1537
|
-
});
|
|
1538
|
-
this.ui.requestRender();
|
|
1539
|
-
}
|
|
1540
|
-
else if (uiEvent.type === "grep_blocked") {
|
|
1541
|
-
this.chatContainer.addMessage({
|
|
1542
|
-
type: "tool",
|
|
1543
|
-
view: buildGrepBlockedView(this.uiTheme, uiEvent.pattern, uiEvent.reason),
|
|
1544
|
-
}, uiEvent.toolCallId);
|
|
1545
|
-
this.ui.requestRender();
|
|
1546
|
-
}
|
|
1339
|
+
this.toolUiRouter.handle(event.uiEvent);
|
|
1547
1340
|
break;
|
|
1548
1341
|
}
|
|
1549
1342
|
case "notice": {
|
|
@@ -1563,26 +1356,12 @@ Write plain prose, no formatting. Be thorough enough that the reader can resume
|
|
|
1563
1356
|
finally {
|
|
1564
1357
|
const wasAborted = this.currentTurnAbort?.signal.aborted ?? false;
|
|
1565
1358
|
const reason = wasAborted ? "aborted" : "interrupted";
|
|
1566
|
-
|
|
1567
|
-
this.chatContainer.replaceMessage(id, {
|
|
1568
|
-
type: "tool",
|
|
1569
|
-
view: buildBashAbortedView(this.uiTheme, running.command, reason),
|
|
1570
|
-
});
|
|
1571
|
-
}
|
|
1572
|
-
const taskStatus = wasAborted ? "aborted" : "error";
|
|
1573
|
-
for (const [id, running] of this.runningTaskComponents.entries()) {
|
|
1574
|
-
this.chatContainer.replaceMessage(id, {
|
|
1575
|
-
type: "tool",
|
|
1576
|
-
view: buildTaskFinishedView(this.uiTheme, running.title, running.costTotal, running.turns, running.toolCalls, taskStatus, reason, { kind: running.kind, subagentName: running.name }),
|
|
1577
|
-
});
|
|
1578
|
-
}
|
|
1359
|
+
this.toolUiRouter.finalizePending(reason);
|
|
1579
1360
|
this.footer.stop();
|
|
1580
1361
|
this.stopTurnTimer();
|
|
1581
1362
|
this.isStreaming = false;
|
|
1582
1363
|
this.currentTurnAbort = undefined;
|
|
1583
|
-
this.
|
|
1584
|
-
this.runningTaskComponents.clear();
|
|
1585
|
-
this.taskEvents.clear();
|
|
1364
|
+
this.toolUiRouter.clearTransientState();
|
|
1586
1365
|
this.pendingIdleNotification = true;
|
|
1587
1366
|
this.ui.requestRender();
|
|
1588
1367
|
void this.drainQueuedUserMessages();
|