@aragon-agent/cli 0.5.2 → 0.5.3
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/CHANGELOG.md +90 -0
- package/README.md +128 -1
- package/dist/agent/controller.d.ts +51 -1
- package/dist/agent/controller.js +177 -2
- package/dist/agent/headless.d.ts +12 -0
- package/dist/agent/headless.js +41 -1
- package/dist/agent/reducer.d.ts +48 -0
- package/dist/agent/reducer.js +91 -2
- package/dist/agent/system-prompt.d.ts +17 -0
- package/dist/agent/system-prompt.js +4 -0
- package/dist/cli.js +66 -2
- package/dist/commands/builtins.js +82 -0
- package/dist/config/app-paths.d.ts +17 -0
- package/dist/config/app-paths.js +21 -0
- package/dist/config/cli-commands.d.ts +26 -2
- package/dist/config/cli-commands.js +63 -4
- package/dist/config/env.d.ts +2 -2
- package/dist/config/env.js +28 -2
- package/dist/config/history-commands.d.ts +20 -0
- package/dist/config/history-commands.js +71 -0
- package/dist/config/load.d.ts +13 -0
- package/dist/config/load.js +65 -5
- package/dist/config/migrate-state-out-of-config.d.ts +32 -0
- package/dist/config/migrate-state-out-of-config.js +85 -0
- package/dist/config/prompt-history.d.ts +86 -0
- package/dist/config/prompt-history.js +332 -0
- package/dist/config/schema.d.ts +112 -16
- package/dist/config/schema.js +89 -6
- package/dist/config/store.js +13 -4
- package/dist/config/ui-state.d.ts +52 -0
- package/dist/config/ui-state.js +149 -0
- package/dist/logging/install.d.ts +85 -0
- package/dist/logging/install.js +94 -0
- package/dist/logging/logger.d.ts +1 -1
- package/dist/session/persist.d.ts +16 -0
- package/dist/session/persist.js +19 -1
- package/dist/team/activity.d.ts +67 -0
- package/dist/team/activity.js +130 -0
- package/dist/team/bus.d.ts +190 -0
- package/dist/team/bus.js +366 -0
- package/dist/team/comm-tools.d.ts +61 -0
- package/dist/team/comm-tools.js +221 -0
- package/dist/team/human-queue.d.ts +55 -0
- package/dist/team/human-queue.js +72 -0
- package/dist/team/limits.d.ts +123 -0
- package/dist/team/limits.js +128 -0
- package/dist/team/normalize.d.ts +39 -0
- package/dist/team/normalize.js +106 -0
- package/dist/team/panel-rows.d.ts +48 -0
- package/dist/team/panel-rows.js +75 -0
- package/dist/team/prompt.d.ts +49 -0
- package/dist/team/prompt.js +87 -0
- package/dist/team/report.d.ts +58 -0
- package/dist/team/report.js +205 -0
- package/dist/team/retry.d.ts +48 -0
- package/dist/team/retry.js +56 -0
- package/dist/team/runtime.d.ts +122 -0
- package/dist/team/runtime.js +406 -0
- package/dist/team/subagent.d.ts +90 -0
- package/dist/team/subagent.js +294 -0
- package/dist/team/task-tool.d.ts +47 -0
- package/dist/team/task-tool.js +118 -0
- package/dist/team/types.d.ts +172 -0
- package/dist/team/types.js +13 -0
- package/dist/tools/index.d.ts +48 -2
- package/dist/tools/index.js +26 -1
- package/dist/ui/App.js +97 -13
- package/dist/ui/StatusBar.d.ts +21 -0
- package/dist/ui/StatusBar.js +5 -2
- package/dist/ui/TeamPanel.d.ts +57 -0
- package/dist/ui/TeamPanel.js +134 -0
- package/dist/ui/Transcript.js +10 -0
- package/dist/ui/entries/TeamCard.d.ts +31 -0
- package/dist/ui/entries/TeamCard.js +39 -0
- package/dist/ui/glyphs.d.ts +10 -0
- package/dist/ui/glyphs.js +6 -0
- package/dist/ui/layout/AppShell.d.ts +11 -1
- package/dist/ui/layout/AppShell.js +3 -3
- package/dist/ui/overlays/HelpOverlay.js +12 -0
- package/dist/ui/transcript-text.js +20 -0
- package/dist/ui/use-startup-notices.d.ts +1 -1
- package/dist/ui/use-startup-notices.js +2 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,96 @@ were written.
|
|
|
9
9
|
|
|
10
10
|
### Added
|
|
11
11
|
|
|
12
|
+
- **Team subagents.** The agent can now hand independent parts of a job to up to
|
|
13
|
+
five short-lived subagents that run in parallel, then read one combined report
|
|
14
|
+
of what each of them found. It decides for itself whether to delegate, so a
|
|
15
|
+
session that never calls the new `task` tool is byte-for-byte the session that
|
|
16
|
+
existed before. On by default; `--no-team` or `team.enabled: false` turns it
|
|
17
|
+
off, and `aragon config set team.maxSubagents <n>` sets the width (1-10; the
|
|
18
|
+
10 is a hard ceiling no config file can raise).
|
|
19
|
+
|
|
20
|
+
A subagent is a full agent with the same tools and working directory but no
|
|
21
|
+
memory of your conversation, so its brief has to be self-contained. It cannot
|
|
22
|
+
delegate further and it cannot ask you anything. Plan mode and a skill's
|
|
23
|
+
`allowed-tools` ceiling both reach one level down, so delegating is never a
|
|
24
|
+
way around either; `--confirm` queues subagent confirmations one at a time and
|
|
25
|
+
labels each with the subagent that is asking.
|
|
26
|
+
|
|
27
|
+
Subagents can message each other with `team_send` / `team_wait`, delivered by
|
|
28
|
+
attaching the message to the recipient's next tool result rather than
|
|
29
|
+
interrupting it. The limits are deliberate — 6 messages each, one every 15
|
|
30
|
+
seconds, 24 per dispatch — and every refusal is a plain result naming the
|
|
31
|
+
limit rather than an error, because an error invites the retry the limits
|
|
32
|
+
exist to prevent.
|
|
33
|
+
|
|
34
|
+
While a dispatch runs, a roster sits between the transcript and the composer
|
|
35
|
+
and the status bar carries `agents 3/5`; both disappear when it finishes and
|
|
36
|
+
the transcript keeps a card you can expand with `Ctrl+O`. `Esc` aborts every
|
|
37
|
+
subagent and returns the partial report. Under `-p` the transitions go to
|
|
38
|
+
stderr and the subagents' tokens are folded into the `[usage]` footer, so the
|
|
39
|
+
cost readout cannot under-report what the team spent.
|
|
40
|
+
|
|
41
|
+
Full documentation, including the limits table and how team mode interacts
|
|
42
|
+
with plan mode, skills and `--confirm`, is in the README.
|
|
43
|
+
|
|
44
|
+
- **The subagent roster now shows what each subagent is doing, and shows the
|
|
45
|
+
ones that are working.** Where every row used to say `thinking` for minutes at
|
|
46
|
+
a time, it now says `bash: npm test -w cli`, `read: src/api/routes.ts`,
|
|
47
|
+
`waiting for a2`, or the tail of the sentence the subagent is currently
|
|
48
|
+
writing. On a narrow terminal the same row falls back to a file name and a
|
|
49
|
+
program name rather than wrapping, and the elapsed clock keeps its place at
|
|
50
|
+
every width.
|
|
51
|
+
|
|
52
|
+
The five visible rows are now the five that matter: whatever is running comes
|
|
53
|
+
first, then whatever is queued, then the most recent results. Above five
|
|
54
|
+
subagents the old panel showed the five that had finished first and hid
|
|
55
|
+
everything still working behind `+3 more`, which is the opposite of what the
|
|
56
|
+
roster is for. `+3 more` now says how many of the hidden ones are still going.
|
|
57
|
+
|
|
58
|
+
- **A subagent no longer waits two minutes for a message nobody can send.**
|
|
59
|
+
`team_wait` now checks whether anyone could actually answer before it blocks:
|
|
60
|
+
if the teammate it named has already finished, does not exist, or is itself
|
|
61
|
+
waiting in a way that cannot be released in time, it returns straight away and
|
|
62
|
+
says which. Nothing is refused that could still have been answered — including
|
|
63
|
+
by a third teammate further down the chain — and the subagent is told what to
|
|
64
|
+
do instead rather than handed an error.
|
|
65
|
+
|
|
66
|
+
- **A subagent whose very first request dies on a rate limit is retried once.**
|
|
67
|
+
Only a genuine cold start qualifies: no turn completed and no tool ran, so
|
|
68
|
+
there is nothing to undo. It restarts after two seconds, the roster says
|
|
69
|
+
`starting (retry)`, and the report notes `retried 1x`. Pressing `Esc`, a
|
|
70
|
+
timeout, or any subagent that had already begun work is never retried.
|
|
71
|
+
|
|
72
|
+
### Changed
|
|
73
|
+
|
|
74
|
+
- **`config.json` holds settings again.** The prompts you type are no longer
|
|
75
|
+
stored in it. They move to `~/.aragon-agent/prompt-history.jsonl` — one JSON
|
|
76
|
+
object per line, `0600` on POSIX — and the submit counter and the "notice
|
|
77
|
+
already shown" flag move to `~/.aragon-agent/state.json`. `↑` and `↓` behave
|
|
78
|
+
exactly as before.
|
|
79
|
+
|
|
80
|
+
Two things get better. Opening `config.json` to change your model no longer
|
|
81
|
+
means scrolling past a transcript of your own typing, and copying it to
|
|
82
|
+
another machine no longer carries your prompts along. And submitting a message
|
|
83
|
+
no longer rewrites the file that holds your API keys: `config.json` is written
|
|
84
|
+
when you change a setting, and at no other time.
|
|
85
|
+
|
|
86
|
+
**Your history and counters are migrated automatically, once, at the next
|
|
87
|
+
launch.** Nothing is printed, because nothing changes for you. The dead
|
|
88
|
+
`recentModels` key — which nothing has ever written — is dropped.
|
|
89
|
+
|
|
90
|
+
If you go back to 0.5.x after upgrading, that version does not know about the
|
|
91
|
+
new file and `↑` will look empty. Nothing has been lost: the entries are still
|
|
92
|
+
in `prompt-history.jsonl`, and upgrading again brings them back.
|
|
93
|
+
|
|
94
|
+
### Added
|
|
95
|
+
|
|
96
|
+
- **`aragon history`** — `path`, `list` (`-n`, `--json`) and `clear --yes` for
|
|
97
|
+
the prompt history, alongside the existing `aragon logs` commands. Entries are
|
|
98
|
+
stored verbatim, so `clear` is how you erase them; `aragon config set
|
|
99
|
+
historyEnabled false` stops new ones being recorded without deleting or hiding
|
|
100
|
+
what is already there.
|
|
101
|
+
|
|
12
102
|
- **The mouse wheel scrolls what is under the pointer.** In full-screen mode the
|
|
13
103
|
wheel now scrolls the transcript three rows per notch (a page with `Shift`),
|
|
14
104
|
scrolls an open overlay when the pointer is over one, and steps prompt history
|
package/README.md
CHANGED
|
@@ -72,6 +72,8 @@ aragon --help | -h Print help
|
|
|
72
72
|
| `--no-fullscreen` | Force the inline renderer (the 0.2.0 behavior) |
|
|
73
73
|
| `--no-exit-transcript` | Do not replay the session summary after exiting |
|
|
74
74
|
| `--plan` / `--no-plan` | Start the session in PLAN mode (read-only research + review) or force BUILD |
|
|
75
|
+
| `--team` / `--no-team` | Enable or disable team subagents. `--no-team` does not register the `task` tool at all |
|
|
76
|
+
| `--team-max <n>` | Max subagents per dispatch for this run, clamped to `[1, 10]` |
|
|
75
77
|
| `--no-skills` | Disable the skill system entirely (no catalog, no skill tools) |
|
|
76
78
|
| `--skill <name>` | Force-load a skill's full body for this run (repeatable) |
|
|
77
79
|
| `--skills-yes` | Approve skill installs for this run (CI / headless) |
|
|
@@ -96,6 +98,7 @@ Exit codes: `0` success · `1` agent/runtime error · `2` config/usage error ·
|
|
|
96
98
|
| `/save [file]` | Save the session to JSON |
|
|
97
99
|
| `/resume [file]` | Load a saved session |
|
|
98
100
|
| `/plan [on\|off\|status]` | Toggle plan mode - the keyboard-free equivalent of `Shift+Tab` |
|
|
101
|
+
| `/team [on\|off\|max <n>]` | Team subagents: status and the live roster, the on/off switch, the fan-out width |
|
|
99
102
|
| `/theme <auto\|warm\|cool\|light>` | Switch the color theme live (persisted) |
|
|
100
103
|
| `/expand [n]` | Expand / collapse the n-th-from-last (default last) tool card |
|
|
101
104
|
| `/copy` | Copy the last answer to the clipboard |
|
|
@@ -308,6 +311,82 @@ When skills are enabled, four more are added — the two read tools `skill` and
|
|
|
308
311
|
below). `--no-skills` removes them again. Updating a skill is deliberately not
|
|
309
312
|
among them; that is a `aragon skills update` decision for you, not the model.
|
|
310
313
|
|
|
314
|
+
With team mode on — which is the default — one more is added: `task`, the
|
|
315
|
+
delegation tool (see below). `--no-team` removes it again.
|
|
316
|
+
|
|
317
|
+
## Team subagents
|
|
318
|
+
|
|
319
|
+
The agent can hand parts of a job to short-lived **subagents** that run in
|
|
320
|
+
parallel, then read one combined report of what they each found. It decides for
|
|
321
|
+
itself whether to delegate; a session that never calls `task` is the session
|
|
322
|
+
that existed before this feature.
|
|
323
|
+
|
|
324
|
+
```
|
|
325
|
+
> read the auth middleware, map the route table, and check the migration
|
|
326
|
+
|
|
327
|
+
◆ team 2 running · 1 done · 84s ✉ 1
|
|
328
|
+
⠋ a1 read the auth middleware tool: grep 22.1s
|
|
329
|
+
⠙ a2 map the route table thinking 31.6s
|
|
330
|
+
✔ a3 check the migration done 4 turns 18.2s
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
**What a subagent is.** A full agent with its own message history, the same
|
|
334
|
+
tools and the same working directory — but no memory of your conversation, so
|
|
335
|
+
its brief has to be self-contained. It cannot delegate further (depth is capped
|
|
336
|
+
at one by construction) and it cannot ask you anything.
|
|
337
|
+
|
|
338
|
+
**Delegate wide, not deep.** Two to four subagents is the usual size. The
|
|
339
|
+
default cap is 5 per dispatch and 3 in flight at once; the hard maximum is 10
|
|
340
|
+
and no config file can raise it. `maxConcurrent` is separate from `maxSubagents`
|
|
341
|
+
on purpose: five simultaneous streams against one API key is a reliable way to
|
|
342
|
+
collect rate-limit errors, and each one would land in the report as a failed
|
|
343
|
+
subagent.
|
|
344
|
+
|
|
345
|
+
**The report.** One text result: a header with the ok/failed counts, aggregate
|
|
346
|
+
tokens and cost, then one section per subagent with its status, timing, the
|
|
347
|
+
files it wrote and its own final summary. A failed subagent never fails the
|
|
348
|
+
dispatch — partial results are the normal outcome of a fan-out. When two
|
|
349
|
+
subagents wrote the same file the header says so, phrased as a warning rather
|
|
350
|
+
than a fact: the file list is derived from `write_file` / `edit_file`, so a
|
|
351
|
+
write made through `bash` is invisible to it.
|
|
352
|
+
|
|
353
|
+
**Talking to each other.** Subagents get two extra tools, `team_send` and
|
|
354
|
+
`team_wait`. Messages are delivered by attaching them to the recipient's next
|
|
355
|
+
tool result, so nobody has to poll and nobody's work is interrupted. The limits
|
|
356
|
+
are the point rather than an afterthought: **6 messages per subagent, one every
|
|
357
|
+
15 seconds, 24 per dispatch**, a broadcast costing two. Every refusal is a plain
|
|
358
|
+
result naming the limit, never an error — an error reads as a malfunction and
|
|
359
|
+
invites a retry, which is the behaviour the limits exist to prevent.
|
|
360
|
+
|
|
361
|
+
**What you see.** While a dispatch runs, the roster above sits between the
|
|
362
|
+
transcript and the composer and the status bar carries `agents 3/5` (`[3]` under
|
|
363
|
+
100 columns). Both disappear when it finishes and the transcript keeps a card
|
|
364
|
+
with the per-agent results; `Ctrl+O` expands it to their summaries. Under `-p`
|
|
365
|
+
the same transitions go to stderr as `[team] a1 ok 22.1s 7 tools` lines, and the
|
|
366
|
+
children's tokens are folded into the `[usage]` footer.
|
|
367
|
+
|
|
368
|
+
**Interaction with the other subsystems.**
|
|
369
|
+
|
|
370
|
+
- **Plan mode reaches one level down.** In PLAN, every subagent is built with
|
|
371
|
+
the same read-only gate, so `write_file` / `edit_file` / `bash` are refused
|
|
372
|
+
inside them too. Parallel research is plan mode's best use, so `task` itself
|
|
373
|
+
is allowed. A single subagent can be pinned read-only with `readOnly: true`
|
|
374
|
+
even in a BUILD session — the field can only ever tighten.
|
|
375
|
+
- **A skill's `allowed-tools` ceiling reaches one level down too**, so
|
|
376
|
+
delegating is not a way around it. Subagents get `skill_find` but not `skill`:
|
|
377
|
+
loading a skill mutates a turn-scoped registry the lead owns, and three
|
|
378
|
+
subagents doing it at once would narrow what the lead may do next in a way
|
|
379
|
+
nothing would report. Always-on skills still reach them.
|
|
380
|
+
- **`--confirm`** queues subagent confirmations one at a time, labelled with the
|
|
381
|
+
subagent that is asking (`[a2] Write: src/routes.ts`).
|
|
382
|
+
- **Logs.** `dispatch_start` and `dispatch_end` are recorded at `info` with the
|
|
383
|
+
ok / failed / aborted counts and aggregate usage; phase transitions at
|
|
384
|
+
`debug`. A `team_send` subject is recorded, never its body; a subagent's brief
|
|
385
|
+
and summary only at `trace`.
|
|
386
|
+
|
|
387
|
+
**`Esc`** aborts the whole dispatch — every subagent within a couple of seconds
|
|
388
|
+
— and the report comes back marked `ABORTED` with whatever was finished.
|
|
389
|
+
|
|
311
390
|
## Skills
|
|
312
391
|
|
|
313
392
|
A skill is a reusable expert procedure stored on disk: a directory containing a
|
|
@@ -597,13 +676,16 @@ env / `.env` → CLI flags**.
|
|
|
597
676
|
`GOOGLE_API_KEY` / `GEMINI_API_KEY`, plus `ARAGON_PROVIDER`, `ARAGON_MODEL`,
|
|
598
677
|
`ARAGON_BASE_URL`, `ARAGON_THINKING`, `ARAGON_MAX_TOKENS`, `ARAGON_THEME`,
|
|
599
678
|
`ARAGON_FULLSCREEN`, `ARAGON_PLAN` (`1` starts in plan mode),
|
|
679
|
+
`ARAGON_TEAM` (`0` disables team subagents), `ARAGON_TEAM_MAX` (fan-out width),
|
|
600
680
|
`ARAGON_SKILLS` (`0` disables), `ARAGON_SKILLS_PATH`,
|
|
601
681
|
`ARAGON_SKILLS_DISABLED` (comma-separated names), `ARAGON_LOG_LEVEL`,
|
|
602
682
|
`ARAGON_LOG_FILE` (`0` disables), `ARAGON_LOG_DIR`.
|
|
603
683
|
`ARAGON_HOME` is the exception that **cannot** come from `.env`: it is read
|
|
604
684
|
before any `.env` is loaded. See [Files & logs](#files--logs).
|
|
605
685
|
- **User config file** (`aragon config path`): JSON, written `0600` on POSIX.
|
|
606
|
-
Holds provider/model/keys and
|
|
686
|
+
Holds provider / model / keys and your preferences, and nothing else — the
|
|
687
|
+
prompts you type and the counters behind one-time notices live in their own
|
|
688
|
+
files (see [Files & logs](#files--logs)). Keys are masked in the UI and never
|
|
607
689
|
logged. It lives in your home directory — see [Files & logs](#files--logs) —
|
|
608
690
|
and editing it by hand is supported: `aragon config edit` opens it, and an
|
|
609
691
|
invalid edit is reported rather than silently resetting every setting.
|
|
@@ -616,6 +698,13 @@ env / `.env` → CLI flags**.
|
|
|
616
698
|
| `planModeDefault` | `false` | Start every session in plan mode. `--no-plan` still overrides it for a single run. |
|
|
617
699
|
| `planModeMaxAskRounds` | `4` | `ask_user` rounds allowed per user message, clamped to `[1, 10]`. The counter resets on your next message; steering does **not** reset it. |
|
|
618
700
|
| `planModeHumanTimeoutMs` | `1800000` | Ceiling on a single question / plan wait, clamped to `[60000, 7200000]`. Thirty minutes is far outside "went to get coffee", but a ceiling has to exist so an unattended terminal cannot wedge a CI job forever. |
|
|
701
|
+
| `historyEnabled` | `true` | Record submitted prompts to `prompt-history.jsonl` for `↑` recall. Setting it to `false` stops new writes; it does not delete what is already stored (that is `aragon history clear --yes`) and does not stop reading. See [Prompt history](#prompt-history). |
|
|
702
|
+
| `team.enabled` | `true` | Master switch for team subagents. `false` means the `task` tool is never registered — `/team on` in such a session saves the setting for next launch and says so, rather than advertising a tool that is not there. |
|
|
703
|
+
| `team.maxSubagents` | `5` | Subagents per dispatch, clamped to `[1, 10]`. The 10 is the hard ceiling and is enforced twice — on the config value and again on what the model asks for — so hand-editing this file cannot raise it. |
|
|
704
|
+
| `team.maxConcurrent` | `3` | Subagents in flight at once, clamped to `[1, 10]` and capped at `maxSubagents`. A separate knob because provider rate limits are a different constraint from context economics. |
|
|
705
|
+
| `team.subagentTimeoutMs` | `300000` | One subagent's wall clock before it is aborted, clamped to `[30000, 1800000]`. A wedged subagent dies on its own ceiling without taking the dispatch with it. |
|
|
706
|
+
| `team.dispatchTimeoutMs` | `900000` | The whole dispatch's wall clock, clamped to `[60000, 3600000]`. |
|
|
707
|
+
| `team.maxTurnsPerSubagent` | `24` | Runaway-loop cap, clamped to `[4, 100]`. A subagent stopped here is reported as `stopped: turn cap reached`, with whatever it had produced. |
|
|
619
708
|
| `skills.enabled` | `true` | Master switch for the skill system. |
|
|
620
709
|
| `skills.requireApproval` | `true` | Require a human to approve `skill_install` / `skill_create`. |
|
|
621
710
|
| `skills.catalogMaxBytes` | `6000` | Level 1 catalog ceiling, in UTF-8 **bytes**, clamped to `[500, 40000]`. |
|
|
@@ -649,6 +738,8 @@ Everything AragonAgent keeps for you lives under one directory in your home:
|
|
|
649
738
|
~/.aragon-agent/ (Windows: C:\Users\<you>\.aragon-agent\)
|
|
650
739
|
├── config.json settings + API keys (0600 on POSIX)
|
|
651
740
|
├── config.json.bak written by `aragon config edit` before it opens
|
|
741
|
+
├── prompt-history.jsonl prompts you submitted, for ↑ recall (0600 on POSIX)
|
|
742
|
+
├── state.json UI bookkeeping: submit count, one-shot notices
|
|
652
743
|
├── logs/
|
|
653
744
|
│ ├── aragon-2026-07-27.log today, JSON Lines
|
|
654
745
|
│ └── aragon-2026-07-27.1.log rotated at log.maxFileBytes
|
|
@@ -657,6 +748,11 @@ Everything AragonAgent keeps for you lives under one directory in your home:
|
|
|
657
748
|
└── skill-usage.json
|
|
658
749
|
```
|
|
659
750
|
|
|
751
|
+
`config.json` holds **settings only**. What you typed and how often you have
|
|
752
|
+
typed it live in the two files next to it, so that editing your config means
|
|
753
|
+
scrolling past your own settings and nothing else, and so that submitting a
|
|
754
|
+
prompt no longer rewrites the file that holds your API keys.
|
|
755
|
+
|
|
660
756
|
`ARAGON_HOME` moves the whole tree. **It cannot come from a `.env` file** — the
|
|
661
757
|
path is resolved when the process starts, long before a `.env` is read — so set
|
|
662
758
|
it as a real environment variable. `aragon config home` always prints the
|
|
@@ -669,6 +765,33 @@ directories are **left in place** so that reinstalling an older build stays
|
|
|
669
765
|
lossless; `aragon config home` names them, and you can delete them once you are
|
|
670
766
|
satisfied.
|
|
671
767
|
|
|
768
|
+
### Prompt history
|
|
769
|
+
|
|
770
|
+
Every prompt you submit is appended to `~/.aragon-agent/prompt-history.jsonl`,
|
|
771
|
+
one JSON object per line, so that `↑` recalls it — in this session and in every
|
|
772
|
+
later one. It is written `0600` on POSIX, it never leaves the machine, and it is
|
|
773
|
+
**stored verbatim**: a redacted history would recall the wrong text, which is
|
|
774
|
+
worse than not recalling at all.
|
|
775
|
+
|
|
776
|
+
The last 100 distinct prompts are what `↑` walks. The file is rewritten down to
|
|
777
|
+
that many entries once it passes 400 lines, and a single submission longer than
|
|
778
|
+
16 KiB is not recorded at all rather than recorded truncated.
|
|
779
|
+
|
|
780
|
+
```bash
|
|
781
|
+
aragon history path # where it is, plus a reminder of what is in it
|
|
782
|
+
aragon history list -n 50 # the 50 most recent, newest first
|
|
783
|
+
aragon history list --json # raw entries with timestamps
|
|
784
|
+
aragon history clear --yes # delete the file
|
|
785
|
+
```
|
|
786
|
+
|
|
787
|
+
Set `historyEnabled` to `false` (`aragon config set historyEnabled false`) to
|
|
788
|
+
stop recording. Switching it off does **not** delete what is already stored —
|
|
789
|
+
`aragon history clear --yes` does that — and reading keeps working either way,
|
|
790
|
+
so you can look before you erase.
|
|
791
|
+
|
|
792
|
+
Upgrading from 0.5.x moves an existing `promptHistory` out of `config.json` into
|
|
793
|
+
this file once, automatically and silently.
|
|
794
|
+
|
|
672
795
|
### What gets logged
|
|
673
796
|
|
|
674
797
|
Logs are local files. Nothing is uploaded, ever — there is no network path out
|
|
@@ -705,6 +828,10 @@ aragon logs tail --level warn # only warn and above
|
|
|
705
828
|
aragon logs clear --yes # delete every log file
|
|
706
829
|
aragon logs open # open the directory in your file manager
|
|
707
830
|
|
|
831
|
+
aragon history path # where prompt history is kept
|
|
832
|
+
aragon history list -n 50 # the 50 most recent prompts, newest first
|
|
833
|
+
aragon history clear --yes # delete the prompt history
|
|
834
|
+
|
|
708
835
|
aragon config home # the user-state root (and whether ARAGON_HOME set it)
|
|
709
836
|
aragon config get log.level # one value; secrets always masked
|
|
710
837
|
aragon config list --json # everything; secrets always masked here too
|
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
* from the event stream by the reducer (TUI) and the headless writer.
|
|
10
10
|
*/
|
|
11
11
|
import { ModelRegistry, type AgentEvent, type AgentTool, type Message, type ModelInfo, type ProviderRegistry, type ThinkingLevel } from '@aragon-agent/core';
|
|
12
|
-
import type { CliConfig, ThemeName } from '../config/schema.js';
|
|
12
|
+
import type { CliConfig, TeamConfig, ThemeName } from '../config/schema.js';
|
|
13
13
|
import { type ConfirmRequest } from '../tools/index.js';
|
|
14
|
+
import type { TeamEvent, TeamSnapshot } from '../team/types.js';
|
|
14
15
|
import { type HumanInputGate } from '../tools/human-input.js';
|
|
15
16
|
import { SkillService, type ApprovalGate } from '../skills/service.js';
|
|
16
17
|
import type { AgentMode } from './agent-mode.js';
|
|
@@ -80,6 +81,9 @@ export declare class AgentController {
|
|
|
80
81
|
private askRounds;
|
|
81
82
|
/** Static: whether this session could ever render a question overlay. */
|
|
82
83
|
private readonly planInteractive;
|
|
84
|
+
private readonly teamRegistered;
|
|
85
|
+
private teamEnabled;
|
|
86
|
+
private readonly teamRuntime;
|
|
83
87
|
constructor(config: CliConfig, deps?: ControllerDeps);
|
|
84
88
|
private resolveKey;
|
|
85
89
|
/**
|
|
@@ -177,8 +181,54 @@ export declare class AgentController {
|
|
|
177
181
|
* path must not leave the watchdog disarmed for the rest of the run. Also used
|
|
178
182
|
* by the `--confirm` gate, which had exactly this bug — a user who took four
|
|
179
183
|
* minutes over `Proceed? (y/N)` had their run killed by the watchdog.
|
|
184
|
+
*
|
|
185
|
+
* RENAMED FROM `withHumanWait`, WITH THE OLD NAME KEPT AS AN ALIAS (D-12). The
|
|
186
|
+
* mechanism is not about humans any more — a `task` dispatch is a long wait
|
|
187
|
+
* with no human in it at all — but the plan tools and the `--confirm` gate read
|
|
188
|
+
* correctly with the old name at their call sites, and renaming those would be
|
|
189
|
+
* churn in files this change should barely touch.
|
|
190
|
+
*
|
|
191
|
+
* NOT RE-ENTRANT, and that matters here: `IdleWatchdog.pause()` sets a boolean
|
|
192
|
+
* rather than a counter, so a nested call's `finally` re-arms the watchdog
|
|
193
|
+
* while the outer wait is still going. That is why a child's `--confirm`
|
|
194
|
+
* dialog does NOT route through this (see the constructor's `humanQueue`).
|
|
180
195
|
*/
|
|
196
|
+
withPausedWatchdog<T>(fn: () => Promise<T>): Promise<T>;
|
|
197
|
+
/** @see withPausedWatchdog — the name the plan tools and `--confirm` use. */
|
|
181
198
|
withHumanWait<T>(fn: () => Promise<T>): Promise<T>;
|
|
199
|
+
/** Whether `task` is in `this.tools`. Fixed at construction; see the fields. */
|
|
200
|
+
isTeamRegistered(): boolean;
|
|
201
|
+
/** Whether `task` will actually dispatch. Flipped live by `/team on|off`. */
|
|
202
|
+
isTeamEnabled(): boolean;
|
|
203
|
+
/**
|
|
204
|
+
* Flip the live switch and re-render the prompt.
|
|
205
|
+
*
|
|
206
|
+
* Turning it ON in a session that started with `--no-team` deliberately does
|
|
207
|
+
* NOT register the tool (D-17): the array is immutable, and advertising an
|
|
208
|
+
* unregistered tool is the dead end P0-2 is about. `/team` reports that
|
|
209
|
+
* honestly by checking `isTeamRegistered()` first.
|
|
210
|
+
*/
|
|
211
|
+
setTeamEnabled(enabled: boolean): void;
|
|
212
|
+
getTeamConfig(): TeamConfig;
|
|
213
|
+
/**
|
|
214
|
+
* Adopt a new team config for this session and re-render the prompt (the block
|
|
215
|
+
* quotes the numbers). Clamped here as well as on the persist path, so a bad
|
|
216
|
+
* value can never reach the runtime.
|
|
217
|
+
*/
|
|
218
|
+
setTeamConfig(patch: Partial<TeamConfig>): TeamConfig;
|
|
219
|
+
/** Refused mid-dispatch by `/team`; half a dispatch under two ceilings is not
|
|
220
|
+
* a result anything can afterwards explain (the reasoning `/reload` uses). */
|
|
221
|
+
isTeamBusy(): boolean;
|
|
222
|
+
getTeamSnapshot(): TeamSnapshot | null;
|
|
223
|
+
/**
|
|
224
|
+
* Subscribe to the CLI-local team event stream.
|
|
225
|
+
*
|
|
226
|
+
* Returns a no-op unsubscribe when team mode was off at construction, so every
|
|
227
|
+
* caller can subscribe unconditionally.
|
|
228
|
+
*/
|
|
229
|
+
subscribeTeam(listener: (event: TeamEvent) => void): () => void;
|
|
230
|
+
/** Abort every child and clear timers. Idempotent; safe to call twice. */
|
|
231
|
+
dispose(): void;
|
|
182
232
|
setModel(provider: string, model: string, baseUrl?: string): void;
|
|
183
233
|
setThinkingLevel(level: ThinkingLevel): void;
|
|
184
234
|
setMaxTokens(value: number | undefined): void;
|
package/dist/agent/controller.js
CHANGED
|
@@ -9,10 +9,14 @@
|
|
|
9
9
|
* from the event stream by the reducer (TUI) and the headless writer.
|
|
10
10
|
*/
|
|
11
11
|
import { Agent, initProviders, ModelRegistry, } from '@aragon-agent/core';
|
|
12
|
-
import { isAdapterProvider } from '../config/schema.js';
|
|
12
|
+
import { clampTeamConfig, isAdapterProvider } from '../config/schema.js';
|
|
13
13
|
import { makeGetApiKey } from '../config/load.js';
|
|
14
14
|
import { updatePersistedConfig } from '../config/store.js';
|
|
15
15
|
import { createBuiltinTools } from '../tools/index.js';
|
|
16
|
+
import { TeamRuntime } from '../team/runtime.js';
|
|
17
|
+
import { TeamHumanQueue } from '../team/human-queue.js';
|
|
18
|
+
import { createTaskTool } from '../team/task-tool.js';
|
|
19
|
+
import { buildTeamBlock } from '../team/prompt.js';
|
|
16
20
|
import { createPlanTools } from '../tools/plan-tools.js';
|
|
17
21
|
import { DENY_ALL_HUMAN_INPUT } from '../tools/human-input.js';
|
|
18
22
|
import { createNodeSkillHost } from '../skills/node-host.js';
|
|
@@ -48,6 +52,25 @@ export class AgentController {
|
|
|
48
52
|
askRounds = 0;
|
|
49
53
|
/** Static: whether this session could ever render a question overlay. */
|
|
50
54
|
planInteractive;
|
|
55
|
+
// -----------------------------------------------------------------------
|
|
56
|
+
// Team mode (team-subagents §4.5) — TWO FLAGS, AND THEY ARE NOT THE SAME.
|
|
57
|
+
//
|
|
58
|
+
// `teamRegistered` is decided ONCE, at construction, and can never change:
|
|
59
|
+
// it is whether the `task` tool is in `this.tools` at all. The array is
|
|
60
|
+
// immutable for the life of the session (see the note in the constructor),
|
|
61
|
+
// so `/team on` in a session started with `--no-team` CANNOT add it.
|
|
62
|
+
//
|
|
63
|
+
// `teamEnabled` is live. `/team off` flips it, which makes `task` refuse
|
|
64
|
+
// through its own guard and drops `<team_mode>` from the next prompt rebuild
|
|
65
|
+
// — `rebuildSystemPrompt()` IS a live path, unlike the tool array.
|
|
66
|
+
//
|
|
67
|
+
// Conflating them is P0-2: the prompt would advertise a tool that was never
|
|
68
|
+
// registered, every call would come back "unknown tool", and the model would
|
|
69
|
+
// have no way to discover why (D-17 / R-18).
|
|
70
|
+
// -----------------------------------------------------------------------
|
|
71
|
+
teamRegistered;
|
|
72
|
+
teamEnabled;
|
|
73
|
+
teamRuntime;
|
|
51
74
|
constructor(config, deps = {}) {
|
|
52
75
|
this.config = config;
|
|
53
76
|
this.cwd = config.cwd;
|
|
@@ -81,6 +104,40 @@ export class AgentController {
|
|
|
81
104
|
this.skills.reportUnknownForcedSkills();
|
|
82
105
|
}
|
|
83
106
|
const confirm = deps.confirm;
|
|
107
|
+
// --- Team mode ---------------------------------------------------------
|
|
108
|
+
this.teamRegistered = config.team.enabled;
|
|
109
|
+
this.teamEnabled = config.team.enabled;
|
|
110
|
+
this.teamRuntime = this.teamRegistered
|
|
111
|
+
? new TeamRuntime({
|
|
112
|
+
getConfig: () => this.config,
|
|
113
|
+
providerRegistry: this.providerRegistry,
|
|
114
|
+
getCwd: () => this.cwd,
|
|
115
|
+
getMode: () => this.effectiveMode,
|
|
116
|
+
getApiKey: (id) => this.resolveKey(id),
|
|
117
|
+
// `skill_find` only, and the lead's always-on bodies. See the long
|
|
118
|
+
// note in `subagent.ts` for why `skill` itself is withheld (D-16).
|
|
119
|
+
...(this.skillsEnabled
|
|
120
|
+
? {
|
|
121
|
+
skillRegistry: this.skills.getRegistry(),
|
|
122
|
+
alwaysBlock: () => this.skills.alwaysBlock(),
|
|
123
|
+
toolPolicy: () => this.skills.toolPolicyDecision(() => this.toolNames()),
|
|
124
|
+
// Label-decorating, and it DOES NOT advance the lead's
|
|
125
|
+
// escalation counter (P1-3). That counter exists to tell ONE
|
|
126
|
+
// agent to stop retrying ONE tool; a child cannot retry the
|
|
127
|
+
// lead's turn, and letting children spend the lead's budget
|
|
128
|
+
// makes the escalation fire on the lead's next legitimate call.
|
|
129
|
+
onChildToolPolicyEvent: (e) => deps.notify?.('warn', `[${e.label}] ${e.verdict.message ?? `Blocked ${e.tool}`}`),
|
|
130
|
+
}
|
|
131
|
+
: {}),
|
|
132
|
+
// NOT routed through `withHumanWait` (I-3, and this one is subtle):
|
|
133
|
+
// the lead's watchdog is ALREADY paused for the whole dispatch, and
|
|
134
|
+
// `IdleWatchdog.pause()` is a boolean rather than a counter — so a
|
|
135
|
+
// nested resume when one child's dialog closed would re-arm the lead
|
|
136
|
+
// mid-dispatch and abort it at `idleTimeoutMs`. The queue pauses the
|
|
137
|
+
// CHILD's watchdog instead, which is the one that needs it (P0-4).
|
|
138
|
+
...(confirm ? { humanQueue: new TeamHumanQueue(confirm) } : {}),
|
|
139
|
+
})
|
|
140
|
+
: null;
|
|
84
141
|
this.tools = createBuiltinTools({
|
|
85
142
|
getCwd: () => this.cwd,
|
|
86
143
|
confirmTools: config.confirmTools,
|
|
@@ -110,6 +167,27 @@ export class AgentController {
|
|
|
110
167
|
withHumanWait: (fn) => this.withHumanWait(fn),
|
|
111
168
|
onPlanApproved: () => this.setAgentMode('build', { force: true }),
|
|
112
169
|
}),
|
|
170
|
+
// THROUGH THE FACTORY, NEVER APPENDED AFTERWARDS (D-15 / P0-1).
|
|
171
|
+
// `tools.test.ts::C7` asserts `HOST_TOOL_NAMES` equals what
|
|
172
|
+
// `createBuiltinTools` produces, so appending `task` here would turn that
|
|
173
|
+
// test red with a message about two lists of names.
|
|
174
|
+
//
|
|
175
|
+
// Empty when team mode was off at construction, which leaves the array
|
|
176
|
+
// byte-identical to the pre-team build (AC-11).
|
|
177
|
+
teamTools: this.teamRuntime
|
|
178
|
+
? [
|
|
179
|
+
createTaskTool({
|
|
180
|
+
runtime: this.teamRuntime,
|
|
181
|
+
// Read LIVE: `/team off` flips the flag, it cannot unregister.
|
|
182
|
+
isTeamEnabled: () => this.teamEnabled,
|
|
183
|
+
maxSubagents: () => this.config.team.maxSubagents,
|
|
184
|
+
hasApiKey: () => this.hasApiKey(),
|
|
185
|
+
activeProvider: () => this.config.provider,
|
|
186
|
+
modelCost: () => this.getModelInfo().cost,
|
|
187
|
+
withPausedWatchdog: (fn) => this.withPausedWatchdog(fn),
|
|
188
|
+
}),
|
|
189
|
+
]
|
|
190
|
+
: [],
|
|
113
191
|
// Read at CALL time, never cached: the mode flips mid-run when the user
|
|
114
192
|
// approves a plan, and a cached 'plan' would refuse the work they just
|
|
115
193
|
// authorized.
|
|
@@ -149,6 +227,11 @@ export class AgentController {
|
|
|
149
227
|
toolTimeoutOverrides: {
|
|
150
228
|
ask_user: config.planModeHumanTimeoutMs,
|
|
151
229
|
submit_plan: config.planModeHumanTimeoutMs,
|
|
230
|
+
// A fan-out is not a hung tool either. Like the two above, this
|
|
231
|
+
// number only bites BECAUSE `task` races `ctx.signal` — the
|
|
232
|
+
// executor's timeout is cooperative, so an override is inert for any
|
|
233
|
+
// tool that does not listen (I-2).
|
|
234
|
+
...(this.teamRegistered ? { task: config.team.dispatchTimeoutMs } : {}),
|
|
152
235
|
},
|
|
153
236
|
},
|
|
154
237
|
});
|
|
@@ -193,6 +276,16 @@ export class AgentController {
|
|
|
193
276
|
agentMode: this.effectiveMode,
|
|
194
277
|
planInteractive: this.planInteractive,
|
|
195
278
|
planMaxAskRounds: this.config.planModeMaxAskRounds,
|
|
279
|
+
// BOTH flags, and both are required (§4.5). `teamRegistered` false means
|
|
280
|
+
// there is no `task` tool to advertise; `teamEnabled` false means the user
|
|
281
|
+
// turned it off for this session. Advertising in either case would
|
|
282
|
+
// describe a capability the model does not have.
|
|
283
|
+
teamBlock: this.teamRegistered && this.teamEnabled
|
|
284
|
+
? buildTeamBlock({
|
|
285
|
+
maxSubagents: this.config.team.maxSubagents,
|
|
286
|
+
maxConcurrent: this.config.team.maxConcurrent,
|
|
287
|
+
})
|
|
288
|
+
: '',
|
|
196
289
|
});
|
|
197
290
|
}
|
|
198
291
|
rebuildSystemPrompt() {
|
|
@@ -293,6 +386,13 @@ export class AgentController {
|
|
|
293
386
|
}
|
|
294
387
|
abort() {
|
|
295
388
|
this.agent.abort();
|
|
389
|
+
// DELIBERATE REDUNDANCY (§3.8). Aborting the lead already aborts the
|
|
390
|
+
// in-flight `task` call's `ctx.signal`, which the runtime listens to — that
|
|
391
|
+
// path is correct today. Calling it directly as well makes "no child
|
|
392
|
+
// survives its dispatch" a property of THIS class rather than a consequence
|
|
393
|
+
// of signal plumbing three modules away, which is the same argument
|
|
394
|
+
// `App.tsx` records for `cancelPendingHuman()` on `agent_end`.
|
|
395
|
+
this.teamRuntime?.abortAll();
|
|
296
396
|
}
|
|
297
397
|
steer(text) {
|
|
298
398
|
// Mid-run interjection: promote the queue, keep what is already in force
|
|
@@ -393,8 +493,19 @@ export class AgentController {
|
|
|
393
493
|
* path must not leave the watchdog disarmed for the rest of the run. Also used
|
|
394
494
|
* by the `--confirm` gate, which had exactly this bug — a user who took four
|
|
395
495
|
* minutes over `Proceed? (y/N)` had their run killed by the watchdog.
|
|
496
|
+
*
|
|
497
|
+
* RENAMED FROM `withHumanWait`, WITH THE OLD NAME KEPT AS AN ALIAS (D-12). The
|
|
498
|
+
* mechanism is not about humans any more — a `task` dispatch is a long wait
|
|
499
|
+
* with no human in it at all — but the plan tools and the `--confirm` gate read
|
|
500
|
+
* correctly with the old name at their call sites, and renaming those would be
|
|
501
|
+
* churn in files this change should barely touch.
|
|
502
|
+
*
|
|
503
|
+
* NOT RE-ENTRANT, and that matters here: `IdleWatchdog.pause()` sets a boolean
|
|
504
|
+
* rather than a counter, so a nested call's `finally` re-arms the watchdog
|
|
505
|
+
* while the outer wait is still going. That is why a child's `--confirm`
|
|
506
|
+
* dialog does NOT route through this (see the constructor's `humanQueue`).
|
|
396
507
|
*/
|
|
397
|
-
async
|
|
508
|
+
async withPausedWatchdog(fn) {
|
|
398
509
|
this.agent.pauseIdleWatchdog();
|
|
399
510
|
try {
|
|
400
511
|
return await fn();
|
|
@@ -403,6 +514,70 @@ export class AgentController {
|
|
|
403
514
|
this.agent.resumeIdleWatchdog();
|
|
404
515
|
}
|
|
405
516
|
}
|
|
517
|
+
/** @see withPausedWatchdog — the name the plan tools and `--confirm` use. */
|
|
518
|
+
withHumanWait(fn) {
|
|
519
|
+
return this.withPausedWatchdog(fn);
|
|
520
|
+
}
|
|
521
|
+
// -----------------------------------------------------------------------
|
|
522
|
+
// Team mode (team-subagents §4.5)
|
|
523
|
+
// -----------------------------------------------------------------------
|
|
524
|
+
/** Whether `task` is in `this.tools`. Fixed at construction; see the fields. */
|
|
525
|
+
isTeamRegistered() {
|
|
526
|
+
return this.teamRegistered;
|
|
527
|
+
}
|
|
528
|
+
/** Whether `task` will actually dispatch. Flipped live by `/team on|off`. */
|
|
529
|
+
isTeamEnabled() {
|
|
530
|
+
return this.teamEnabled;
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* Flip the live switch and re-render the prompt.
|
|
534
|
+
*
|
|
535
|
+
* Turning it ON in a session that started with `--no-team` deliberately does
|
|
536
|
+
* NOT register the tool (D-17): the array is immutable, and advertising an
|
|
537
|
+
* unregistered tool is the dead end P0-2 is about. `/team` reports that
|
|
538
|
+
* honestly by checking `isTeamRegistered()` first.
|
|
539
|
+
*/
|
|
540
|
+
setTeamEnabled(enabled) {
|
|
541
|
+
this.teamEnabled = enabled;
|
|
542
|
+
this.rebuildSystemPrompt();
|
|
543
|
+
}
|
|
544
|
+
getTeamConfig() {
|
|
545
|
+
return this.config.team;
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* Adopt a new team config for this session and re-render the prompt (the block
|
|
549
|
+
* quotes the numbers). Clamped here as well as on the persist path, so a bad
|
|
550
|
+
* value can never reach the runtime.
|
|
551
|
+
*/
|
|
552
|
+
setTeamConfig(patch) {
|
|
553
|
+
const team = clampTeamConfig({ ...this.config.team, ...patch });
|
|
554
|
+
this.config = { ...this.config, team };
|
|
555
|
+
this.rebuildSystemPrompt();
|
|
556
|
+
return team;
|
|
557
|
+
}
|
|
558
|
+
/** Refused mid-dispatch by `/team`; half a dispatch under two ceilings is not
|
|
559
|
+
* a result anything can afterwards explain (the reasoning `/reload` uses). */
|
|
560
|
+
isTeamBusy() {
|
|
561
|
+
return this.teamRuntime?.isBusy() ?? false;
|
|
562
|
+
}
|
|
563
|
+
getTeamSnapshot() {
|
|
564
|
+
return this.teamRuntime?.snapshot() ?? null;
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* Subscribe to the CLI-local team event stream.
|
|
568
|
+
*
|
|
569
|
+
* Returns a no-op unsubscribe when team mode was off at construction, so every
|
|
570
|
+
* caller can subscribe unconditionally.
|
|
571
|
+
*/
|
|
572
|
+
subscribeTeam(listener) {
|
|
573
|
+
if (!this.teamRuntime)
|
|
574
|
+
return () => { };
|
|
575
|
+
return this.teamRuntime.subscribe(listener);
|
|
576
|
+
}
|
|
577
|
+
/** Abort every child and clear timers. Idempotent; safe to call twice. */
|
|
578
|
+
dispose() {
|
|
579
|
+
this.teamRuntime?.dispose();
|
|
580
|
+
}
|
|
406
581
|
// -----------------------------------------------------------------------
|
|
407
582
|
// Mutators
|
|
408
583
|
// -----------------------------------------------------------------------
|
package/dist/agent/headless.d.ts
CHANGED
|
@@ -6,12 +6,24 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import type { AgentEvent, ModelInfo } from '@aragon-agent/core';
|
|
8
8
|
import type { PreflightResult } from './controller.js';
|
|
9
|
+
import type { TeamEvent } from '../team/types.js';
|
|
9
10
|
/** The minimal controller surface headless mode needs (real or stubbed). */
|
|
10
11
|
export interface HeadlessController {
|
|
11
12
|
preflight(): PreflightResult;
|
|
12
13
|
subscribe(listener: (event: AgentEvent) => void): () => void;
|
|
13
14
|
prompt(text: string): Promise<void>;
|
|
14
15
|
getModelInfo(): ModelInfo;
|
|
16
|
+
/**
|
|
17
|
+
* The CLI-local team stream — OPTIONAL, deliberately (team-subagents §3.12 /
|
|
18
|
+
* P1-6).
|
|
19
|
+
*
|
|
20
|
+
* This interface is minimal so tests can satisfy it with an object literal.
|
|
21
|
+
* Making the member REQUIRED would break every existing stub for no benefit,
|
|
22
|
+
* and the subscription genuinely is optional: a controller with no team
|
|
23
|
+
* runtime has no team events. `runHeadless` calls it with `?.`, which keeps
|
|
24
|
+
* the `--no-team` headless path byte-identical to today's.
|
|
25
|
+
*/
|
|
26
|
+
subscribeTeam?(listener: (event: TeamEvent) => void): () => void;
|
|
15
27
|
}
|
|
16
28
|
export interface HeadlessOptions {
|
|
17
29
|
quiet?: boolean;
|