Commit 1df0b68
committed
Agent mode phase 2: persistent, interactive terminals
Agent mode's only process-management tool (start_background_command) spawns
with stdio: ["ignore", ...] — there's no way to send input to a running
process, so answering an interactive prompt or driving a REPL was
impossible; output was poll-only, never streamed.
- New app/src/terminal-manager.ts, backed by node-pty (real pseudo-terminal,
not a plain pipe): create/write/resize/close/list, workspace-scoped
cleanup wired into the same lifecycle hooks phase 0 built for background
tasks (agent:closeWorkspace, window-all-closed, before-quit). Reuses phase
1's command-sandbox.ts for filesystem confinement where the platform
supports it, defaulting to network allowed (unlike run_command's per-call
default) since this is an interactive session a human can see and type
into directly, not a one-shot command the model composed unsupervised.
- Two separate paths reach it, deliberately: a human opening the terminal
panel goes through a dedicated terminal:create IPC channel with live
push-streamed output (mirrors the existing chat:chunk streaming pattern)
and never touches tool approval, since the human is driving their own
keystrokes. The model gets four new agent tools — create_terminal,
write_to_terminal, read_terminal_output, close_terminal — that poll
instead of stream, going through the normal approval-card pipeline like
every other tool. Kept start_background_command's existing four tools
unchanged rather than folding them into this, so no schema break for
prompts/evals that already know them.
- New frontend/src/components/terminal-panel.tsx (xterm.js + fit addon):
one mounted terminal instance, tab-switching replays each session's
buffered output rather than keeping N instances alive at once.
- Extracted resolveSafePath out of agent-tools.ts into workspace-path.ts so
terminal-manager.ts could reuse the same workspace-containment logic
without agent-tools.ts <-> terminal-manager.ts becoming a circular import
(agent-tools.ts's own new create_terminal/write_to_terminal/etc tool
cases need to import terminal-manager.ts, which already needed
resolveSafePath).
New dependencies: node-pty (main, native — added to asarUnpack alongside
the other native deps; electron-builder rebuilds it for Electron's ABI
automatically, same as the existing node-llama-cpp dependency already
relies on), @xterm/xterm + @xterm/addon-fit (renderer).
17 new tests across terminal-manager.test.ts and 3 new agent-tools.test.ts
cases for the tool-call dispatch path, all exercising a real spawned pty
rather than mocking node-pty.1 parent 948bbe0 commit 1df0b68
16 files changed
Lines changed: 754 additions & 40 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
33 | 33 | | |
34 | 34 | | |
35 | 35 | | |
36 | | - | |
| 36 | + | |
| 37 | + | |
37 | 38 | | |
38 | 39 | | |
39 | 40 | | |
| |||
91 | 92 | | |
92 | 93 | | |
93 | 94 | | |
| 95 | + | |
94 | 96 | | |
95 | 97 | | |
96 | 98 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
| 6 | + | |
6 | 7 | | |
7 | 8 | | |
8 | 9 | | |
| |||
393 | 394 | | |
394 | 395 | | |
395 | 396 | | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
| 410 | + | |
| 411 | + | |
| 412 | + | |
| 413 | + | |
| 414 | + | |
| 415 | + | |
| 416 | + | |
| 417 | + | |
| 418 | + | |
| 419 | + | |
| 420 | + | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
| 427 | + | |
| 428 | + | |
| 429 | + | |
| 430 | + | |
| 431 | + | |
| 432 | + | |
| 433 | + | |
| 434 | + | |
| 435 | + | |
| 436 | + | |
| 437 | + | |
| 438 | + | |
396 | 439 | | |
397 | 440 | | |
398 | 441 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
11 | 11 | | |
12 | 12 | | |
13 | 13 | | |
| 14 | + | |
| 15 | + | |
14 | 16 | | |
15 | 17 | | |
16 | 18 | | |
| |||
202 | 204 | | |
203 | 205 | | |
204 | 206 | | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
205 | 255 | | |
206 | 256 | | |
207 | 257 | | |
| |||
415 | 465 | | |
416 | 466 | | |
417 | 467 | | |
418 | | - | |
419 | | - | |
420 | | - | |
421 | | - | |
422 | | - | |
423 | | - | |
424 | | - | |
425 | | - | |
426 | | - | |
427 | | - | |
428 | | - | |
429 | | - | |
430 | | - | |
431 | | - | |
432 | | - | |
433 | | - | |
434 | | - | |
435 | | - | |
436 | | - | |
437 | | - | |
438 | | - | |
439 | | - | |
440 | | - | |
441 | | - | |
442 | | - | |
443 | | - | |
444 | | - | |
445 | | - | |
446 | | - | |
447 | | - | |
448 | | - | |
449 | | - | |
450 | 468 | | |
451 | 469 | | |
452 | 470 | | |
| |||
1467 | 1485 | | |
1468 | 1486 | | |
1469 | 1487 | | |
| 1488 | + | |
| 1489 | + | |
| 1490 | + | |
| 1491 | + | |
| 1492 | + | |
| 1493 | + | |
| 1494 | + | |
| 1495 | + | |
| 1496 | + | |
| 1497 | + | |
| 1498 | + | |
| 1499 | + | |
| 1500 | + | |
| 1501 | + | |
| 1502 | + | |
| 1503 | + | |
| 1504 | + | |
| 1505 | + | |
| 1506 | + | |
| 1507 | + | |
1470 | 1508 | | |
1471 | 1509 | | |
1472 | 1510 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
24 | 24 | | |
25 | 25 | | |
26 | 26 | | |
27 | | - | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
28 | 51 | | |
29 | 52 | | |
30 | 53 | | |
31 | | - | |
| 54 | + | |
32 | 55 | | |
33 | 56 | | |
34 | 57 | | |
| |||
65 | 88 | | |
66 | 89 | | |
67 | 90 | | |
68 | | - | |
| 91 | + | |
69 | 92 | | |
70 | 93 | | |
71 | 94 | | |
| |||
144 | 167 | | |
145 | 168 | | |
146 | 169 | | |
147 | | - | |
| 170 | + | |
148 | 171 | | |
149 | 172 | | |
150 | 173 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
15 | 15 | | |
16 | 16 | | |
17 | 17 | | |
| 18 | + | |
18 | 19 | | |
19 | 20 | | |
20 | 21 | | |
| |||
763 | 764 | | |
764 | 765 | | |
765 | 766 | | |
766 | | - | |
| 767 | + | |
| 768 | + | |
767 | 769 | | |
768 | 770 | | |
769 | 771 | | |
770 | 772 | | |
| 773 | + | |
| 774 | + | |
| 775 | + | |
| 776 | + | |
| 777 | + | |
| 778 | + | |
| 779 | + | |
| 780 | + | |
| 781 | + | |
| 782 | + | |
| 783 | + | |
| 784 | + | |
| 785 | + | |
| 786 | + | |
| 787 | + | |
| 788 | + | |
| 789 | + | |
| 790 | + | |
| 791 | + | |
| 792 | + | |
| 793 | + | |
| 794 | + | |
| 795 | + | |
| 796 | + | |
| 797 | + | |
| 798 | + | |
| 799 | + | |
| 800 | + | |
| 801 | + | |
| 802 | + | |
| 803 | + | |
| 804 | + | |
| 805 | + | |
| 806 | + | |
| 807 | + | |
| 808 | + | |
| 809 | + | |
| 810 | + | |
771 | 811 | | |
772 | 812 | | |
773 | 813 | | |
| |||
824 | 864 | | |
825 | 865 | | |
826 | 866 | | |
| 867 | + | |
827 | 868 | | |
828 | 869 | | |
829 | 870 | | |
| |||
832 | 873 | | |
833 | 874 | | |
834 | 875 | | |
| 876 | + | |
835 | 877 | | |
836 | 878 | | |
0 commit comments