@aragon-agent/cli 0.6.2 → 0.6.4
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 +321 -0
- package/README.md +297 -2
- package/dist/agent/controller.d.ts +193 -1
- package/dist/agent/controller.js +475 -2
- package/dist/agent/headless.d.ts +8 -0
- package/dist/agent/headless.js +47 -0
- package/dist/agent/reducer.d.ts +189 -0
- package/dist/agent/reducer.js +301 -2
- package/dist/agent/system-prompt.d.ts +14 -0
- package/dist/agent/system-prompt.js +2 -0
- package/dist/cli.js +297 -16
- package/dist/commands/builtins.js +165 -24
- package/dist/commands/registry.d.ts +27 -0
- package/dist/compaction/archive.d.ts +175 -0
- package/dist/compaction/archive.js +267 -0
- package/dist/compaction/child.d.ts +97 -0
- package/dist/compaction/child.js +118 -0
- package/dist/compaction/command.d.ts +41 -0
- package/dist/compaction/command.js +355 -0
- package/dist/compaction/compactor.d.ts +302 -0
- package/dist/compaction/compactor.js +810 -0
- package/dist/compaction/digest.d.ts +62 -0
- package/dist/compaction/digest.js +164 -0
- package/dist/compaction/limits.d.ts +165 -0
- package/dist/compaction/limits.js +172 -0
- package/dist/compaction/pressure.d.ts +135 -0
- package/dist/compaction/pressure.js +167 -0
- package/dist/compaction/summarize-call.d.ts +70 -0
- package/dist/compaction/summarize-call.js +86 -0
- package/dist/compaction/summary-prompt.d.ts +85 -0
- package/dist/compaction/summary-prompt.js +197 -0
- package/dist/compaction/tail-budget.d.ts +52 -0
- package/dist/compaction/tail-budget.js +67 -0
- package/dist/compaction/types.d.ts +215 -0
- package/dist/compaction/types.js +22 -0
- package/dist/compaction/wiring.d.ts +264 -0
- package/dist/compaction/wiring.js +577 -0
- package/dist/config/app-paths.d.ts +14 -0
- package/dist/config/app-paths.js +16 -0
- package/dist/config/cli-commands.d.ts +41 -0
- package/dist/config/cli-commands.js +77 -1
- package/dist/config/env.d.ts +5 -2
- package/dist/config/env.js +140 -3
- package/dist/config/load.d.ts +42 -0
- package/dist/config/load.js +101 -1
- package/dist/config/schema.d.ts +244 -0
- package/dist/config/schema.js +170 -0
- package/dist/config/store.js +37 -1
- package/dist/config/ui-state.d.ts +28 -1
- package/dist/config/ui-state.js +9 -0
- package/dist/exec/events.d.ts +50 -1
- package/dist/exec/runner.js +42 -0
- package/dist/input/limits.d.ts +72 -0
- package/dist/input/limits.js +63 -0
- package/dist/input/mouse-events.d.ts +31 -5
- package/dist/input/mouse-events.js +86 -27
- package/dist/input/paste-parse.d.ts +71 -0
- package/dist/input/paste-parse.js +95 -0
- package/dist/input/stdin-filter.d.ts +81 -0
- package/dist/input/stdin-filter.js +379 -0
- package/dist/logging/install.d.ts +53 -1
- package/dist/logging/install.js +81 -1
- package/dist/logging/logger.d.ts +1 -1
- package/dist/proc/classify.d.ts +52 -0
- package/dist/proc/classify.js +143 -0
- package/dist/proc/kill-tree.d.ts +42 -0
- package/dist/proc/kill-tree.js +119 -0
- package/dist/proc/limits.d.ts +84 -0
- package/dist/proc/limits.js +84 -0
- package/dist/proc/log-ring.d.ts +68 -0
- package/dist/proc/log-ring.js +102 -0
- package/dist/proc/prompt.d.ts +24 -0
- package/dist/proc/prompt.js +49 -0
- package/dist/proc/readiness.d.ts +102 -0
- package/dist/proc/readiness.js +219 -0
- package/dist/proc/supervisor.d.ts +103 -0
- package/dist/proc/supervisor.js +465 -0
- package/dist/proc/types.d.ts +175 -0
- package/dist/proc/types.js +15 -0
- package/dist/session/persist.js +55 -1
- package/dist/team/report.js +7 -1
- package/dist/team/runtime.d.ts +10 -0
- package/dist/team/runtime.js +7 -0
- package/dist/team/subagent.d.ts +31 -1
- package/dist/team/subagent.js +42 -15
- package/dist/team/types.d.ts +8 -0
- package/dist/tools/bash-tool.d.ts +51 -2
- package/dist/tools/bash-tool.js +321 -51
- package/dist/tools/fs-tools.d.ts +17 -0
- package/dist/tools/index.d.ts +55 -2
- package/dist/tools/index.js +39 -1
- package/dist/tools/proc-tools.d.ts +25 -0
- package/dist/tools/proc-tools.js +102 -0
- package/dist/ui/ActivityLine.d.ts +19 -1
- package/dist/ui/ActivityLine.js +10 -2
- package/dist/ui/App.d.ts +62 -2
- package/dist/ui/App.js +546 -16
- package/dist/ui/Composer.d.ts +66 -1
- package/dist/ui/Composer.js +50 -6
- package/dist/ui/PromptInput.d.ts +82 -3
- package/dist/ui/PromptInput.js +232 -49
- package/dist/ui/StatusBar.d.ts +59 -0
- package/dist/ui/StatusBar.js +16 -4
- package/dist/ui/TeamPanel.js +7 -1
- package/dist/ui/Transcript.d.ts +21 -1
- package/dist/ui/Transcript.js +61 -3
- package/dist/ui/clipboard.d.ts +52 -0
- package/dist/ui/clipboard.js +91 -0
- package/dist/ui/composer-limits.d.ts +31 -0
- package/dist/ui/composer-limits.js +50 -0
- package/dist/ui/composer-rows.d.ts +73 -0
- package/dist/ui/composer-rows.js +201 -0
- package/dist/ui/editor-reducer.d.ts +37 -0
- package/dist/ui/editor-reducer.js +88 -12
- package/dist/ui/entries/CompactionCard.d.ts +75 -0
- package/dist/ui/entries/CompactionCard.js +158 -0
- package/dist/ui/entries/ServiceCard.d.ts +66 -0
- package/dist/ui/entries/ServiceCard.js +116 -0
- package/dist/ui/entries/UserEntry.d.ts +17 -3
- package/dist/ui/entries/UserEntry.js +34 -5
- package/dist/ui/frame-differ.d.ts +46 -0
- package/dist/ui/frame-differ.js +94 -10
- package/dist/ui/gauge.d.ts +16 -1
- package/dist/ui/gauge.js +25 -6
- package/dist/ui/glyphs.d.ts +11 -0
- package/dist/ui/glyphs.js +2 -0
- package/dist/ui/layout/ScrollViewport.d.ts +43 -6
- package/dist/ui/layout/ScrollViewport.js +128 -21
- package/dist/ui/layout/budget.d.ts +44 -9
- package/dist/ui/layout/budget.js +42 -10
- package/dist/ui/layout/follow-state.d.ts +137 -0
- package/dist/ui/layout/follow-state.js +150 -0
- package/dist/ui/layout/virtual-window.d.ts +11 -0
- package/dist/ui/layout/virtual-window.js +85 -1
- package/dist/ui/overlays/HelpOverlay.js +9 -1
- package/dist/ui/overlays/PlanReviewOverlay.js +10 -2
- package/dist/ui/overlays/QuestionOverlay.js +5 -1
- package/dist/ui/overlays/SettingsScreen.d.ts +47 -1
- package/dist/ui/overlays/SettingsScreen.js +74 -2
- package/dist/ui/palettes.d.ts +16 -0
- package/dist/ui/palettes.js +6 -0
- package/dist/ui/paste-frames.d.ts +87 -0
- package/dist/ui/paste-frames.js +112 -0
- package/dist/ui/paste-tokens.d.ts +90 -0
- package/dist/ui/paste-tokens.js +147 -0
- package/dist/ui/screen.d.ts +38 -0
- package/dist/ui/screen.js +113 -8
- package/dist/ui/selection/highlight.d.ts +39 -0
- package/dist/ui/selection/highlight.js +64 -0
- package/dist/ui/selection/screen-mirror.d.ts +24 -0
- package/dist/ui/selection/screen-mirror.js +35 -0
- package/dist/ui/selection/selection-controller.d.ts +88 -0
- package/dist/ui/selection/selection-controller.js +282 -0
- package/dist/ui/selection/selection.d.ts +90 -0
- package/dist/ui/selection/selection.js +223 -0
- package/dist/ui/stdout-frame-writer.d.ts +33 -0
- package/dist/ui/stdout-frame-writer.js +15 -0
- package/dist/ui/theme.d.ts +11 -0
- package/dist/ui/theme.js +2 -0
- package/dist/ui/transcript-text.js +72 -0
- package/dist/ui/use-startup-notices.d.ts +27 -1
- package/dist/ui/use-startup-notices.js +43 -11
- package/dist/ui/use-wheel-routing.d.ts +1 -1
- package/dist/ui/use-wheel-routing.js +8 -0
- package/package.json +4 -2
- package/dist/input/stdin-mouse-filter.d.ts +0 -42
- package/dist/input/stdin-mouse-filter.js +0 -153
package/README.md
CHANGED
|
@@ -377,6 +377,8 @@ below works there too, in either position — `aragon --model m exec "…"` and
|
|
|
377
377
|
| `--fast-model <id>` | The fast model id. Implies nothing about `--fast` on its own |
|
|
378
378
|
| `--fast-provider <id>` | Provider for the fast model. Absent inherits the main provider |
|
|
379
379
|
| `--fast-review <n\|off>` | Turns between automatic fast reviews, or `off` |
|
|
380
|
+
| `--compaction` / `--no-compaction` | Compact the conversation when the context window fills, or never. **On** by default — see **Context compaction** |
|
|
381
|
+
| `--compaction-threshold <n>` | Occupancy that triggers compaction for this run: `0.9` or `90%`, clamped to `[0.5, 0.95]` |
|
|
380
382
|
| `--no-skills` | Disable the skill system entirely (no catalog, no skill tools) |
|
|
381
383
|
| `--skill <name>` | Force-load a skill's full body for this run (repeatable) |
|
|
382
384
|
| `--skills-yes` | Approve skill installs for this run (CI / headless) |
|
|
@@ -410,6 +412,8 @@ signal ends the run (`130` SIGINT, `143` SIGTERM, `129` SIGHUP).
|
|
|
410
412
|
| `/todo [on\|off\|panel on\|off\|follow <mode>\|clear\|continue]` | Todo planning: status, the on/off switch, the rail, follow-through, and picking an unfinished plan back up |
|
|
411
413
|
| `/retry [show\|on\|off\|max <n>]` | API retry: the effective ladder, the on/off switch, the retry count. Takes effect **in the running session**, children included |
|
|
412
414
|
| `/fast [on\|off\|model <id>\|provider <id>\|same\|review <n\|off>\|delegate on\|off]` | Fast model tier: status and this session's totals, the on/off switch, which model, the review cadence |
|
|
415
|
+
| `/compact [status\|on\|off\|threshold <n>\|keep <n>\|history\|show <n>\|<instructions>]` | Context compaction: occupancy and this session's totals, the on/off switch, when it fires, how much it keeps. With free text, compacts now and tells the summarizer what to pay attention to |
|
|
416
|
+
| `/bg [list\|logs <id> [n]\|stop <id\|all>\|status]` | Background services: what is running, its log tail, and how to stop it. `list` is the default |
|
|
413
417
|
| `/update [status\|now\|skip\|off]` | Auto-update: what is running, what is available, where it came from, when it looks again. `now` forces a check past the throttle; `skip` declines the offered version until a newer one appears |
|
|
414
418
|
| `/theme <auto\|warm\|cool\|light>` | Switch the color theme live (persisted) |
|
|
415
419
|
| `/expand [n]` | Expand / collapse the n-th-from-last (default last) tool card |
|
|
@@ -434,10 +438,12 @@ completes, `Up` / `Down` moves the selection, `Esc` closes it.
|
|
|
434
438
|
| `Shift+Tab` | Toggle **plan mode** (`BUILD` <-> `PLAN`). Equivalent: `/plan`. On Windows this needs a console flag Node < 22.17 does not set; aragon sets it at startup — see [Requirements](#requirements) |
|
|
435
439
|
| `Ctrl+P` | The same toggle, over a channel no Windows console can swallow. Use it if `Shift+Tab` does nothing |
|
|
436
440
|
| `Esc` | Abort the run / close an overlay / close a popup |
|
|
437
|
-
| `
|
|
441
|
+
| `Esc` ×2 | **Force-stop** a run that did not abort: kills the shell command it is blocked on and returns the view to `idle`. The second press only does anything while the run is *still* running, so in a healthy run it is a no-op |
|
|
442
|
+
| `Ctrl+C` | Stop the background **services** the agent started, when there are any. It does not arm exit |
|
|
443
|
+
| `Ctrl+C` ×2 | Exit (first press warns), once no services are running |
|
|
438
444
|
| `Ctrl+L` | Redraw the frame (clear the screen in inline mode) |
|
|
439
445
|
| `Ctrl+T` | Show / hide thinking (**off by default**). In inline mode it applies to the live entry and everything drawn after it — settled entries are already in your terminal's scrollback and cannot be repainted |
|
|
440
|
-
| `Ctrl+O` | Expand / collapse the most recent tool card — including
|
|
446
|
+
| `Ctrl+O` | Expand / collapse the most recent tool, team, compaction or **service** card — including a diff or a service's log tail |
|
|
441
447
|
| `PgUp` / `PgDn` | Scroll the transcript a page (full-screen mode) |
|
|
442
448
|
| `Shift+↑` / `Shift+↓` | Scroll the transcript a line (full-screen mode) |
|
|
443
449
|
| Mouse wheel | Scroll the transcript (or the open overlay). On Windows needs Node ≥ 22.17 — see [Requirements](#requirements) |
|
|
@@ -447,6 +453,7 @@ completes, `Up` / `Down` moves the selection, `Esc` closes it.
|
|
|
447
453
|
| `Ctrl+W`, `Alt+Backspace` | Delete the previous word |
|
|
448
454
|
| `Ctrl+U` / `Ctrl+K` | Kill to line start / end |
|
|
449
455
|
| `Up` / `Down` | Move between draft lines; recall prompt history at the edges |
|
|
456
|
+
| Paste | Inserted as-is up to 6 lines / 400 chars; larger collapses to `[Pasted text #1 +15 lines]`, which deletes as one unit and expands in full when you send. `--no-paste` restores the pre-0.6.3 behaviour |
|
|
450
457
|
| `?` | Open help (empty input) |
|
|
451
458
|
|
|
452
459
|
In **full-screen mode** the transcript is scrolled by the app itself: `PgUp` /
|
|
@@ -905,6 +912,94 @@ delegation tool (see below). `--no-team` removes it again.
|
|
|
905
912
|
With todo planning on — also the default — one more is added: `todo_write`, the
|
|
906
913
|
planning tool (see above). `--no-todo` removes it again.
|
|
907
914
|
|
|
915
|
+
With background services on — also the default — two more are added:
|
|
916
|
+
`bash_output` and `bash_kill` (see below), and `bash` itself gains a `background`
|
|
917
|
+
parameter. `bash.background: false` removes all three again.
|
|
918
|
+
|
|
919
|
+
## Background services
|
|
920
|
+
|
|
921
|
+
The agent can write a web app; it also has to be able to **run** one. A command
|
|
922
|
+
that never exits on its own — `npm run dev`, `uvicorn main:app`, `vite`,
|
|
923
|
+
`docker compose up`, `tsc --watch` — is not a hung tool, it is a server, and
|
|
924
|
+
running it in the foreground stalls the turn until the tool timeout kills it
|
|
925
|
+
three minutes later.
|
|
926
|
+
|
|
927
|
+
So those commands are **supervised** instead. `bash` gains one optional
|
|
928
|
+
parameter:
|
|
929
|
+
|
|
930
|
+
```jsonc
|
|
931
|
+
{ "command": "npm run dev", "background": true }
|
|
932
|
+
```
|
|
933
|
+
|
|
934
|
+
`true` supervises it, `false` never does, and **omitting it lets the runtime
|
|
935
|
+
decide** from the command itself — a closed allowlist over the leading token and
|
|
936
|
+
the script name (`npm|pnpm|yarn|bun run dev|start|serve|watch|preview`,
|
|
937
|
+
`next dev`, `vite`, `nuxt dev`, `ng serve`, `nodemon`, `tsc --watch`, `uvicorn`,
|
|
938
|
+
`gunicorn`, `flask run`, `manage.py runserver`, `rails server`, `php -S`,
|
|
939
|
+
`cargo watch`, `docker compose up` without `-d`, `tail -f`, `watch `). It never
|
|
940
|
+
fires on a chained command, because a chain's tail is what you actually wanted
|
|
941
|
+
the result of, and `npm run build` and `npm test` are deliberately not on it.
|
|
942
|
+
|
|
943
|
+
A supervised launch returns as soon as there is something true to say — the
|
|
944
|
+
**first** of ready, exited, or four seconds — so a server that crashes on boot is
|
|
945
|
+
reported in 400 ms with the stack in the result rather than after a three-minute
|
|
946
|
+
stall:
|
|
947
|
+
|
|
948
|
+
```
|
|
949
|
+
$ npm run dev
|
|
950
|
+
[background] service s1 started (pid 24188)
|
|
951
|
+
[ready] http://localhost:3000 (detected from output after 1.4s)
|
|
952
|
+
[log tail]
|
|
953
|
+
> next dev
|
|
954
|
+
- Local: http://localhost:3000
|
|
955
|
+
Read more with bash_output({ service: "s1" }); stop it with bash_kill({ service: "s1" }).
|
|
956
|
+
```
|
|
957
|
+
|
|
958
|
+
Readiness is a URL the server printed, or one TCP connect to a port the command
|
|
959
|
+
named — and if that port was **already answering before the launch**, the probe
|
|
960
|
+
is switched off and the card says so, rather than calling somebody else's server
|
|
961
|
+
yours. A process that stays up without listening on anything (`tsc --watch`) is
|
|
962
|
+
reported as `running`, which is the honest third answer.
|
|
963
|
+
|
|
964
|
+
Each service gets a transcript card and a `svc N` chip in the status bar. Two
|
|
965
|
+
tools read and stop them:
|
|
966
|
+
|
|
967
|
+
- `bash_output({ service, since? })` — the log tail and the current status.
|
|
968
|
+
`since` is the cursor the previous call returned, so a watcher can be read
|
|
969
|
+
incrementally. The tail is a bounded in-memory ring of 200 rows; there are no
|
|
970
|
+
log files on disk.
|
|
971
|
+
- `bash_kill({ service })` — stop one, or `"all"`.
|
|
972
|
+
|
|
973
|
+
**Services do not survive the CLI.** Quitting, `Ctrl+C`, `SIGTERM` and a crash
|
|
974
|
+
all reap the tree on a best-effort basis; there is no daemon, no PID file and no
|
|
975
|
+
reattach across launches. A `SIGKILL` of aragon itself is unrecoverable by
|
|
976
|
+
construction, and if a stop cannot confirm the process is gone it says
|
|
977
|
+
`may have left a detached child` rather than claiming success.
|
|
978
|
+
|
|
979
|
+
From your side there are two keys and one command: `Ctrl+C` stops every live
|
|
980
|
+
service (and does *not* arm exit), `/bg` lists them, and `/bg logs s1` prints a
|
|
981
|
+
tail without going through the model.
|
|
982
|
+
|
|
983
|
+
### Turning it off
|
|
984
|
+
|
|
985
|
+
```jsonc
|
|
986
|
+
// ~/.aragon/config.json
|
|
987
|
+
{ "bash": { "background": false } }
|
|
988
|
+
```
|
|
989
|
+
|
|
990
|
+
`ARAGON_BASH_BACKGROUND=0` does the same for one run;
|
|
991
|
+
`ARAGON_BASH_AUTO_BACKGROUND=0` keeps the tools but stops the classifier firing
|
|
992
|
+
on a command that did not ask. With `background: false` the build behaves exactly
|
|
993
|
+
as it did before this feature existed — no `background` parameter, no extra
|
|
994
|
+
tools, no prompt block, no chip.
|
|
995
|
+
|
|
996
|
+
Two things are **not** governed by that switch, because they are fixes rather
|
|
997
|
+
than features. `bash` now always settles: it returns when the process exits
|
|
998
|
+
rather than when its output stream closes, so a command that detaches a
|
|
999
|
+
grandchild can no longer leave the turn pending forever, and it is handed a
|
|
1000
|
+
closed stdin so a command that prompts fails instead of blocking on a read
|
|
1001
|
+
nobody will answer. And `Esc` twice always force-stops, whatever the flag says.
|
|
1002
|
+
|
|
908
1003
|
## Team subagents
|
|
909
1004
|
|
|
910
1005
|
The agent can hand parts of a job to short-lived **subagents** that run in
|
|
@@ -1116,6 +1211,205 @@ it for a background advisory is how an unrequested call ends up competing with
|
|
|
1116
1211
|
you for a rate-limited provider's quota. The review's own wall-clock bound is
|
|
1117
1212
|
20 s.
|
|
1118
1213
|
|
|
1214
|
+
## Context compaction
|
|
1215
|
+
|
|
1216
|
+
A long agentic run fills the model's context window. Before this existed, the
|
|
1217
|
+
only ending available to it at that point was an HTTP 400 and a banner telling
|
|
1218
|
+
you to start over — which threw away everything the run had done.
|
|
1219
|
+
|
|
1220
|
+
Now the CLI **compacts** instead. When the conversation occupies **90 %** of the
|
|
1221
|
+
window, the run pauses at a turn boundary, hands the older part of the history to
|
|
1222
|
+
a summarizer, and swaps it for a structured record. Your original task stays
|
|
1223
|
+
**verbatim**, the most recent turns stay **verbatim**, and the run continues in
|
|
1224
|
+
the same loop with the same tools, the same todo list and the same working
|
|
1225
|
+
directory. Nothing about the session restarts.
|
|
1226
|
+
|
|
1227
|
+
**It is on by default**, unlike every other optional subsystem here, and that is
|
|
1228
|
+
deliberate: the fast tier and team mode *add* behaviour you did not ask for,
|
|
1229
|
+
while this one *removes* a failure you did not ask for. `--no-compaction` or
|
|
1230
|
+
`compaction.enabled: false` restores the old behaviour exactly — no manager is
|
|
1231
|
+
constructed, nothing is subscribed, and a full window ends the run as it did
|
|
1232
|
+
before.
|
|
1233
|
+
|
|
1234
|
+
### What actually happens
|
|
1235
|
+
|
|
1236
|
+
1. **Proactively**, when measured occupancy crosses the threshold. This is the
|
|
1237
|
+
case that fires almost every time.
|
|
1238
|
+
2. **Reactively**, when the provider returns `context_overflow` anyway — because
|
|
1239
|
+
the model's context window is not in the static table, or you are pointed at a
|
|
1240
|
+
proxy in front of a smaller model. One compaction, one re-send, run continues.
|
|
1241
|
+
The engine allows exactly one of these per turn.
|
|
1242
|
+
3. **Manually**, with `/compact`. While the agent is idle it runs immediately;
|
|
1243
|
+
while it is running it queues and fires at the next turn boundary.
|
|
1244
|
+
|
|
1245
|
+
The trigger has **two** terms, and the second one is not belt-and-braces: 90 % of
|
|
1246
|
+
a 200 k window leaves 20 k, which is plenty, but 90 % of a 32 k window leaves
|
|
1247
|
+
3.2 k — less than a single `max_tokens` of 8192, so the request is already
|
|
1248
|
+
impossible. Compaction therefore also fires whenever the remaining headroom drops
|
|
1249
|
+
below one full response.
|
|
1250
|
+
|
|
1251
|
+
### Which model summarizes, and what it costs
|
|
1252
|
+
|
|
1253
|
+
**By default, your own model.** `compaction.useFastTier` is `true`, but it
|
|
1254
|
+
describes a *preference*: the fast tier only resolves when you have configured
|
|
1255
|
+
it, and it is off by default. So out of the box the first compaction is a
|
|
1256
|
+
~30 k-token call **on the session's own model** — real money on a frontier model,
|
|
1257
|
+
spent by a feature that is on by default.
|
|
1258
|
+
|
|
1259
|
+
Three things make that the right trade rather than a hidden cost. It happens at
|
|
1260
|
+
most 5 times per run. The alternative is losing the entire run. And the spend is
|
|
1261
|
+
visible: it goes into the session total, it is priced with the *summarizer's* own
|
|
1262
|
+
table, and `/compact status` reports `pricing unknown` rather than `$0.00` when
|
|
1263
|
+
the model is not in that table.
|
|
1264
|
+
|
|
1265
|
+
To make it cheap, configure the fast tier (`/fast on`, `/fast model <cheap-id>`).
|
|
1266
|
+
The transcript card then names the cheap model.
|
|
1267
|
+
|
|
1268
|
+
### When it cannot summarize
|
|
1269
|
+
|
|
1270
|
+
Summarization is a network call and it will sometimes fail. The ladder is: one
|
|
1271
|
+
retry — on your **main** model if the first attempt used the fast tier, because
|
|
1272
|
+
"a fast model that cannot summarize" is the likeliest single failure — and then,
|
|
1273
|
+
by default, a **truncation**: the same cut, the same verbatim task, and a block
|
|
1274
|
+
that says plainly that the dropped messages were not summarized. That is
|
|
1275
|
+
announced on the card, in the transcript, on the JSON event stream and inside the
|
|
1276
|
+
block the model itself reads.
|
|
1277
|
+
|
|
1278
|
+
Truncation loses information, and it is still the default, because an unattended
|
|
1279
|
+
`aragon exec` that wedges on an unrecoverable 400 loses the whole run.
|
|
1280
|
+
`compaction.onFailure: "stop"` makes the other trade: the history is left alone,
|
|
1281
|
+
an error names your exits, and the next request will probably fail — which is
|
|
1282
|
+
what you asked for by setting it.
|
|
1283
|
+
|
|
1284
|
+
### It will not loop on your money
|
|
1285
|
+
|
|
1286
|
+
Four independent guards: never two compactions on consecutive turns, never more
|
|
1287
|
+
than 5 per run, a splice that does not project a real reclaim does not count as
|
|
1288
|
+
progress, and two consecutive no-progress compactions **switch the proactive
|
|
1289
|
+
trigger off for the session** with a notice naming the cause and the fix.
|
|
1290
|
+
|
|
1291
|
+
The guards are trigger-aware. A *pressure* compaction that reclaims little has
|
|
1292
|
+
spent money to buy two turns and should stop. An *overflow* compaction that
|
|
1293
|
+
reclaims little is the difference between a live run and a dead one, because the
|
|
1294
|
+
provider has already refused the request — so the reactive path stays armed even
|
|
1295
|
+
after a self-disable, and an overflow attempt may halve `keepRecentTurns` for
|
|
1296
|
+
itself, which is the one lever that can make a too-large tail fit.
|
|
1297
|
+
|
|
1298
|
+
### What you see
|
|
1299
|
+
|
|
1300
|
+
Three surfaces, each answering something the others cannot:
|
|
1301
|
+
|
|
1302
|
+
- **While it runs** — the activity row reads `Compacting context…`. It outranks
|
|
1303
|
+
the tool name and the rotating phrase, because compaction happens between
|
|
1304
|
+
turns and the phrase would otherwise claim the model is thinking. The
|
|
1305
|
+
transcript card counts the seconds and tells you `esc to cancel`, which has
|
|
1306
|
+
always been true and was never said.
|
|
1307
|
+
- **As state** — a `compacting` chip in the status bar, and the context gauge's
|
|
1308
|
+
colours aligned to your own thresholds. The gauge **falls immediately** after a
|
|
1309
|
+
compaction rather than waiting for the next turn, with a `~` while the value is
|
|
1310
|
+
derived rather than measured.
|
|
1311
|
+
- **As a record** — a transcript card with the before/after message and token
|
|
1312
|
+
counts, the summarizer, the duration, and the summary itself. `Ctrl+O` expands
|
|
1313
|
+
it.
|
|
1314
|
+
|
|
1315
|
+
**What a red gauge means:** the trigger is `>= threshold` while the red band is
|
|
1316
|
+
`> threshold`, so any occupancy that would paint red has already triggered
|
|
1317
|
+
compaction and the bar repaints downward in the same frame. Red is therefore only
|
|
1318
|
+
ever visible when compaction did **not** or **could not** run — it is off, it
|
|
1319
|
+
self-disabled, or the ladder ran out.
|
|
1320
|
+
|
|
1321
|
+
`/compact status` is the guaranteed surface: the chip drops on a narrow terminal
|
|
1322
|
+
and the card scrolls away, but the command answers at any width, in any mode,
|
|
1323
|
+
after the fact.
|
|
1324
|
+
|
|
1325
|
+
### When the RECENT turns are what does not fit
|
|
1326
|
+
|
|
1327
|
+
Every rung above operates on the **head** of the conversation. When the retained
|
|
1328
|
+
tail is the problem — a few turns each carrying several 100 KB tool results —
|
|
1329
|
+
each of those rungs reports success or "nothing to drop" while the history stays
|
|
1330
|
+
un-sendable.
|
|
1331
|
+
|
|
1332
|
+
The last rung clips oversized `tool_result` bodies **inside the retained turns**,
|
|
1333
|
+
oldest first, stopping the moment the request fits. Nothing is removed: no
|
|
1334
|
+
message, no tool-call id, no role — so a history that was structurally valid
|
|
1335
|
+
before is still valid after. Every clip is announced **in the text the model
|
|
1336
|
+
reads**, at the exact place the data went:
|
|
1337
|
+
|
|
1338
|
+
```
|
|
1339
|
+
[... 214003 characters removed by context compaction ...]
|
|
1340
|
+
```
|
|
1341
|
+
|
|
1342
|
+
A model that sees that knows the output is partial and can re-run the tool. It is
|
|
1343
|
+
also stated on the transcript card, in `/compact status`, on the JSON event
|
|
1344
|
+
stream and in the archive. When clipping is the **only** thing that happened, the
|
|
1345
|
+
card says so and names no model, because none was called.
|
|
1346
|
+
|
|
1347
|
+
### Sub-agents get the same protection
|
|
1348
|
+
|
|
1349
|
+
A `task` child is bounded by `team.maxTurnsPerSubagent` (24) and
|
|
1350
|
+
`team.dispatchTimeoutMs` (15 minutes) — the same profile as a lead run that fills
|
|
1351
|
+
a window. When a child overflowed, its history was discarded and the whole
|
|
1352
|
+
dispatch reached you as one partial sentence.
|
|
1353
|
+
|
|
1354
|
+
Children now compact their own history, under tighter bounds: **two** retained
|
|
1355
|
+
turns instead of four, at most **two** compactions per child instead of five, the
|
|
1356
|
+
fast tier preferred whenever it resolves, and `onFailure` forced to `truncate`
|
|
1357
|
+
because nobody is watching a background worker. There is no transcript card for a
|
|
1358
|
+
child — the lead's transcript describes the lead's context. Turn it off with
|
|
1359
|
+
`compaction.subagents: false`.
|
|
1360
|
+
|
|
1361
|
+
### A compaction is no longer irreversible
|
|
1362
|
+
|
|
1363
|
+
Before a splice is adopted, the dropped messages are written verbatim to
|
|
1364
|
+
`~/.aragon/compaction/` — metadata, the summary, and the messages themselves.
|
|
1365
|
+
|
|
1366
|
+
`/compact history` lists **this run's** archives, newest first, with the path of
|
|
1367
|
+
each. `/compact show <n>` prints one archive's metadata and its stored summary;
|
|
1368
|
+
it never prints message bodies, because a single archive can be megabytes and the
|
|
1369
|
+
transcript is not a pager. The directory is shared by every `aragon` on the
|
|
1370
|
+
machine, so files carry a per-process run id: another terminal's compactions are
|
|
1371
|
+
counted in one trailing line rather than listed as yours.
|
|
1372
|
+
|
|
1373
|
+
Retention is two-tier and bounded: the newest 20 files **of this run**, plus a
|
|
1374
|
+
seven-day sweep across all runs. Writing is best-effort — a failure is logged and
|
|
1375
|
+
never affects the compaction. `compaction.archive: false` turns it off and writes
|
|
1376
|
+
nothing.
|
|
1377
|
+
|
|
1378
|
+
This is **not undo**: restoring an over-full history restores the condition that
|
|
1379
|
+
triggered the compaction, and the next request fails. It is fidelity on disk, so
|
|
1380
|
+
"the summary was wrong and the agent proceeded on a false record" is something
|
|
1381
|
+
you can check rather than something you have to accept.
|
|
1382
|
+
|
|
1383
|
+
### Configuration
|
|
1384
|
+
|
|
1385
|
+
```jsonc
|
|
1386
|
+
{
|
|
1387
|
+
"compaction": {
|
|
1388
|
+
"enabled": true, // false restores the pre-feature behaviour exactly
|
|
1389
|
+
"threshold": 0.9, // [0.5, 0.95]
|
|
1390
|
+
"warnThreshold": 0.75, // [0.4, threshold - 0.05]; where the gauge turns amber
|
|
1391
|
+
"keepRecentTurns": 4, // [1, 20] complete turns kept verbatim
|
|
1392
|
+
"useFastTier": true, // summarize with the fast tier WHEN it resolves
|
|
1393
|
+
"onFailure": "truncate", // or "stop"
|
|
1394
|
+
"subagents": true, // give `task` children their own compaction
|
|
1395
|
+
"archive": true // write the dropped messages to ~/.aragon/compaction
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
```
|
|
1399
|
+
|
|
1400
|
+
Environment: `ARAGON_COMPACTION=0|1`, `ARAGON_COMPACTION_THRESHOLD`,
|
|
1401
|
+
`ARAGON_COMPACTION_KEEP_TURNS`, `ARAGON_COMPACTION_SUBAGENTS`,
|
|
1402
|
+
`ARAGON_COMPACTION_ARCHIVE`.
|
|
1403
|
+
|
|
1404
|
+
### The part that cannot be fixed
|
|
1405
|
+
|
|
1406
|
+
A summarizer that is 90 % faithful will, eventually, drop something the run
|
|
1407
|
+
needed. No amount of prompt engineering closes that. What this design does is
|
|
1408
|
+
bound it: your task is verbatim, the recent turns are verbatim, the block tells
|
|
1409
|
+
the model the record is partial, and three surfaces make it visible so you can
|
|
1410
|
+
step in. That is the same trade Claude Code and Codex make, and it is preferable
|
|
1411
|
+
by a wide margin to the alternative, which is losing the entire run.
|
|
1412
|
+
|
|
1119
1413
|
## Skills
|
|
1120
1414
|
|
|
1121
1415
|
A skill is a reusable expert procedure stored on disk: a directory containing a
|
|
@@ -1445,6 +1739,7 @@ env / `.env` → CLI flags**.
|
|
|
1445
1739
|
| `planModeDefault` | `false` | Start every session in plan mode. `--no-plan` still overrides it for a single run. |
|
|
1446
1740
|
| `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. |
|
|
1447
1741
|
| `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. |
|
|
1742
|
+
| `paste` | `true` | Recognise pasted text before Ink's key parser sees it: line breaks become buffer newlines instead of fifteen separate messages, control bytes are stripped instead of overwriting the row they land on, and a paste above 6 lines or 400 characters collapses to a one-line placeholder that expands when you send. `false` treats pasted bytes as keystrokes, which is what 0.6.2 did. |
|
|
1448
1743
|
| `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). |
|
|
1449
1744
|
| `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. |
|
|
1450
1745
|
| `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. |
|
|
@@ -9,14 +9,17 @@
|
|
|
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 ModelRef, type ProviderRegistry, type ThinkingLevel } from '@aragon-agent/core';
|
|
12
|
-
import type { CliConfig, FastConfig, RetryConfig, TeamConfig, ThemeName, TodoConfig } from '../config/schema.js';
|
|
12
|
+
import type { CliConfig, CompactionConfig, FastConfig, RetryConfig, TeamConfig, ThemeName, TodoConfig } from '../config/schema.js';
|
|
13
13
|
import { type ConfirmRequest } from '../tools/index.js';
|
|
14
14
|
import type { ToolPermission } from '../exec/permission.js';
|
|
15
15
|
import { type ToolOutputListener } from '../tools/tool-output-store.js';
|
|
16
16
|
import type { FilePatch } from '../tools/patch.js';
|
|
17
17
|
import type { TeamEvent, TeamSnapshot } from '../team/types.js';
|
|
18
|
+
import { ProcSupervisor } from '../proc/supervisor.js';
|
|
19
|
+
import type { ProcEventListener, ServiceSnapshot } from '../proc/types.js';
|
|
18
20
|
import { type FastStatus } from '../fast/wiring.js';
|
|
19
21
|
import type { FastEventListener } from '../fast/types.js';
|
|
22
|
+
import type { CompactionEventListener, CompactionSnapshot } from '../compaction/types.js';
|
|
20
23
|
import type { TodoEventListener, TodoSnapshot } from '../todo/types.js';
|
|
21
24
|
import { type HumanInputGate } from '../tools/human-input.js';
|
|
22
25
|
import { SkillService, type ApprovalGate } from '../skills/service.js';
|
|
@@ -174,6 +177,34 @@ export declare class AgentController {
|
|
|
174
177
|
private readonly toolOutputs;
|
|
175
178
|
private readonly outputListeners;
|
|
176
179
|
private readonly fast;
|
|
180
|
+
private readonly compaction;
|
|
181
|
+
private readonly procs;
|
|
182
|
+
/**
|
|
183
|
+
* The host's notice channel, kept so `prompt()`'s totality has somewhere to
|
|
184
|
+
* report to (I-8). Every other consumer reads `deps.notify` through a closure
|
|
185
|
+
* built in the constructor; this one is called from a method, which is why it
|
|
186
|
+
* needs a field.
|
|
187
|
+
*/
|
|
188
|
+
private readonly notifyHostFn;
|
|
189
|
+
/** Whether the SERVICE half is on: tools, prompt block, `background` param. */
|
|
190
|
+
private readonly bashBackgroundRegistered;
|
|
191
|
+
/** Release the exit reaper. Called by `dispose()`. */
|
|
192
|
+
private readonly releaseSignalHook;
|
|
193
|
+
/**
|
|
194
|
+
* Bumped by `forceStop()`; captured by `App` when it subscribes to a run.
|
|
195
|
+
*
|
|
196
|
+
* THE VIEW AND THE ENGINE DELIBERATELY DISAGREE AFTER A FORCE-STOP (D-10 /
|
|
197
|
+
* I-7). Rung two dispatches `runEnd` locally so the composer is usable
|
|
198
|
+
* immediately, but the engine keeps unwinding and keeps EMITTING -
|
|
199
|
+
* `turn_start`, `tool_call_start`, `turn_end`, `agent_end` - and
|
|
200
|
+
* `runStart`/`turnStart` would set `status: 'running'` again, bouncing the
|
|
201
|
+
* view straight back out of the `idle` the user was just given and appending
|
|
202
|
+
* entries to a transcript they believe is finished. `App` drops every event
|
|
203
|
+
* whose generation is stale, which is the same shape as `abortRequested`
|
|
204
|
+
* above and exists for the same reason: the loop legitimately emits after an
|
|
205
|
+
* abort lands.
|
|
206
|
+
*/
|
|
207
|
+
private runGen;
|
|
177
208
|
/**
|
|
178
209
|
* Set SYNCHRONOUSLY by `abort()` before `agent.abort()` (§3.5.4a guard 1).
|
|
179
210
|
* Cleared at the next `agent_start`.
|
|
@@ -232,7 +263,97 @@ export declare class AgentController {
|
|
|
232
263
|
* never rejects, so callers must not treat resolution as success.
|
|
233
264
|
*/
|
|
234
265
|
prompt(text: string): Promise<void>;
|
|
266
|
+
/**
|
|
267
|
+
* Wait for the engine to unwind, bounded.
|
|
268
|
+
*
|
|
269
|
+
* BOUNDED BECAUSE THE UNBOUNDED CASE IS THE ONE THIS FEATURE IS ABOUT: a tool
|
|
270
|
+
* that never settles is exactly why rung two exists, and `Agent.waitForIdle()`
|
|
271
|
+
* alone would hang here for as long as it hangs there. The budget is the two
|
|
272
|
+
* graces a wedged `bash` can legitimately spend, plus the executor's own.
|
|
273
|
+
*/
|
|
274
|
+
private waitForEngineIdle;
|
|
275
|
+
/** The pre-round body of `prompt`, unchanged apart from being private. */
|
|
276
|
+
private startPrompt;
|
|
235
277
|
abort(): void;
|
|
278
|
+
/**
|
|
279
|
+
* Rung two of the Esc ladder: stop the AGENT, whatever it is blocked on
|
|
280
|
+
* (§3.6 / G3).
|
|
281
|
+
*
|
|
282
|
+
* FOUR STEPS, AND THE FOURTH IS AN ABSENCE.
|
|
283
|
+
*
|
|
284
|
+
* 1. `abort()` - everything it does today, unchanged.
|
|
285
|
+
* 2. `killForeground('force')` - hard-kill every tracked foreground `bash`
|
|
286
|
+
* child. THIS is what actually unblocks a wedged `await tool.execute`;
|
|
287
|
+
* an abort signal a tool ignores is advisory, and rung two exists for
|
|
288
|
+
* precisely the tools that ignore it.
|
|
289
|
+
* 3. `runGen += 1` - so `App` can drop the events the engine will keep
|
|
290
|
+
* emitting while it unwinds (I-7). Without it the view bounces straight
|
|
291
|
+
* back out of the `idle` the user was just given.
|
|
292
|
+
* 4. IT DOES NOT TOUCH BACKGROUND SERVICES. `Esc` interrupts the AGENT;
|
|
293
|
+
* `Ctrl+C` stops the SERVICES. That asymmetry is the user's own two
|
|
294
|
+
* sentences and it is exactly the kind of thing a later reader will
|
|
295
|
+
* "fix" by making this kill everything - which would mean a user who
|
|
296
|
+
* pressed Esc twice to stop a runaway turn also lost the dev server they
|
|
297
|
+
* had been working against for an hour. It is invariant I-4.
|
|
298
|
+
*
|
|
299
|
+
* UNCONDITIONAL ON `bash.background` (P1-6 / D-9). The supervisor is always
|
|
300
|
+
* constructed; with services off its foreground registry is all there is, and
|
|
301
|
+
* that is the half this method uses.
|
|
302
|
+
*/
|
|
303
|
+
forceStop(): void;
|
|
304
|
+
/**
|
|
305
|
+
* The current run generation (I-7).
|
|
306
|
+
*
|
|
307
|
+
* `App` captures it when it subscribes to a run and drops every engine event
|
|
308
|
+
* whose generation is stale. Same shape as the `abortRequested` guard the fast
|
|
309
|
+
* reviewer already uses, and for the same reason: the loop legitimately emits
|
|
310
|
+
* after an abort lands.
|
|
311
|
+
*/
|
|
312
|
+
get runGeneration(): number;
|
|
313
|
+
/** Whether `bash_output` / `bash_kill` are in `this.tools`. Fixed at construction. */
|
|
314
|
+
isBackgroundRegistered(): boolean;
|
|
315
|
+
/**
|
|
316
|
+
* Subscribe to the CLI-local `ProcEvent` stream.
|
|
317
|
+
*
|
|
318
|
+
* Returns a live unsubscribe even when services are off, because the
|
|
319
|
+
* supervisor exists either way - the contract `subscribeTeam` /
|
|
320
|
+
* `subscribeTodos` / `subscribeFast` / `subscribeToolOutput` already set. With
|
|
321
|
+
* services off nothing is ever emitted, so an unconditional subscription in
|
|
322
|
+
* `App` costs one `Set` entry.
|
|
323
|
+
*/
|
|
324
|
+
subscribeProc(listener: ProcEventListener): () => void;
|
|
325
|
+
getServiceSnapshot(id: string): ServiceSnapshot | undefined;
|
|
326
|
+
listServices(): ServiceSnapshot[];
|
|
327
|
+
/** `starting | ready | running`. Drives the status chip and the Ctrl+C rung. */
|
|
328
|
+
liveServiceCount(): number;
|
|
329
|
+
readServiceLog(id: string, since?: number): ReturnType<ProcSupervisor['read']>;
|
|
330
|
+
/**
|
|
331
|
+
* Stop one service, or every service when `id` is `'all'`.
|
|
332
|
+
*
|
|
333
|
+
* The GRACEFUL ladder (`SIGTERM` -> `SIGKILL` after `stopGraceMs`), because
|
|
334
|
+
* this path has a live event loop to run it on. `reapServicesSync` is the
|
|
335
|
+
* other one, and it is the only one an exit path may use.
|
|
336
|
+
*/
|
|
337
|
+
stopService(id: string): Promise<ServiceSnapshot[]>;
|
|
338
|
+
/**
|
|
339
|
+
* Rung one of `Ctrl+C`: stop every live service (§3.6 / G4).
|
|
340
|
+
*
|
|
341
|
+
* `force: true` means `reapSync()` SEMANTICS - immediate `SIGKILL`, no
|
|
342
|
+
* `stopGraceMs` - and is what `doExit` uses, because `doExit` awaits nothing
|
|
343
|
+
* and must not start (§3.6 step 3). The graceful ladder belongs to `Ctrl+C`,
|
|
344
|
+
* `bash_kill` and `/bg stop`.
|
|
345
|
+
*/
|
|
346
|
+
stopAllServices(opts?: {
|
|
347
|
+
force?: boolean;
|
|
348
|
+
}): Promise<ServiceSnapshot[]>;
|
|
349
|
+
/**
|
|
350
|
+
* The synchronous reaper (I-9).
|
|
351
|
+
*
|
|
352
|
+
* Exposed so `doExit` can call it without awaiting anything. It is also what
|
|
353
|
+
* the signal hook registered in the constructor calls, and it is idempotent -
|
|
354
|
+
* which it has to be, since a normal quit reaches it twice.
|
|
355
|
+
*/
|
|
356
|
+
reapServicesSync(): void;
|
|
236
357
|
steer(text: string): void;
|
|
237
358
|
followUp(text: string): void;
|
|
238
359
|
isRunning(): boolean;
|
|
@@ -491,6 +612,77 @@ export declare class AgentController {
|
|
|
491
612
|
* `subscribeTodos` already set.
|
|
492
613
|
*/
|
|
493
614
|
subscribeFast(listener: FastEventListener): () => void;
|
|
615
|
+
/** Whether a `ContextManager` exists at all. Fixed at construction. */
|
|
616
|
+
isCompactionRegistered(): boolean;
|
|
617
|
+
/** Whether it will actually fire. Flipped live by `/compact on|off`. */
|
|
618
|
+
isCompactionEnabled(): boolean;
|
|
619
|
+
/**
|
|
620
|
+
* Flip the live switch.
|
|
621
|
+
*
|
|
622
|
+
* A NO-OP WHEN NOTHING IS REGISTERED, and `/compact` reports that honestly by
|
|
623
|
+
* checking `isCompactionRegistered()` first — the `/fast on` and `/team on`
|
|
624
|
+
* shape. `enabled` decides whether the wiring EXISTS, which happens once at
|
|
625
|
+
* construction and cannot be undone: a session that started with no manager
|
|
626
|
+
* would have to be given one mid-flight, and the `Agent` has no setter for it
|
|
627
|
+
* on purpose (§3.2).
|
|
628
|
+
*/
|
|
629
|
+
setCompactionEnabled(enabled: boolean): void;
|
|
630
|
+
getCompactionConfig(): CompactionConfig;
|
|
631
|
+
/**
|
|
632
|
+
* Adopt a new compaction config for this session.
|
|
633
|
+
*
|
|
634
|
+
* THE `onConfigChanged` CALL IS NOT OPTIONAL, for the reason `setFastConfig`
|
|
635
|
+
* records: a persist without it reports success and changes nothing visible
|
|
636
|
+
* until relaunch, because the chip and `/compact status` read a snapshot.
|
|
637
|
+
*/
|
|
638
|
+
setCompactionConfig(patch: Partial<CompactionConfig>): CompactionConfig;
|
|
639
|
+
/** Everything `/compact status`, the settings row and the chip read. */
|
|
640
|
+
getCompactionSnapshot(): CompactionSnapshot;
|
|
641
|
+
/**
|
|
642
|
+
* The `ModelRef` the next compaction would summarize with, or `null`.
|
|
643
|
+
*
|
|
644
|
+
* IT IS CARRIED, NEVER RE-DERIVED, and that is the whole reason it exists. The
|
|
645
|
+
* summarizer is the fast tier when `useFastTier` is on AND the tier resolves,
|
|
646
|
+
* and the session's own model otherwise — a combination no caller can
|
|
647
|
+
* reconstruct from `CliConfig` without re-implementing `resolveFastTier`, and
|
|
648
|
+
* one that a plausible guess (`fast.enabled ? fast.provider : provider`) gets
|
|
649
|
+
* WRONG whenever `fast.enabled` is true and `compaction.useFastTier` is false.
|
|
650
|
+
* Pricing the spend against the wrong provider looks up a model the static
|
|
651
|
+
* table has never seen, which prices it at `$0.00` — the C-11 / RV-4 lie, on
|
|
652
|
+
* the one feature that spends money without being asked (AC-15).
|
|
653
|
+
*/
|
|
654
|
+
getCompactionSummarizerRef(): ModelRef | null;
|
|
655
|
+
/**
|
|
656
|
+
* This run's archive key, or `null` when compaction is unregistered
|
|
657
|
+
* (context-auto-compaction-hardening §3.5 / W4).
|
|
658
|
+
*
|
|
659
|
+
* `/compact history` and `/compact show` scope themselves to it, so a second
|
|
660
|
+
* `aragon` in another terminal is invisible here rather than interleaved with
|
|
661
|
+
* this one's compactions.
|
|
662
|
+
*/
|
|
663
|
+
getCompactionRunId(): string | null;
|
|
664
|
+
/** Ask for a compaction at the next turn boundary (§4.4 / D-17). */
|
|
665
|
+
queueCompaction(instructions?: string): void;
|
|
666
|
+
/**
|
|
667
|
+
* The IDLE `/compact` path (§4.4 / D-25).
|
|
668
|
+
*
|
|
669
|
+
* IT VALIDATES BEFORE IT SPLICES. `CompactionWiring.compactNow` runs
|
|
670
|
+
* `validateHistory` itself and refuses on failure, because with no loop running
|
|
671
|
+
* the engine's own gate is unreachable and D-4 declares that gate
|
|
672
|
+
* unbypassable. `replaceMessages` validates NOTHING.
|
|
673
|
+
*/
|
|
674
|
+
compactNow(instructions?: string): Promise<{
|
|
675
|
+
ok: boolean;
|
|
676
|
+
reason?: string;
|
|
677
|
+
}>;
|
|
678
|
+
/**
|
|
679
|
+
* Subscribe to the CLI-local compaction event stream.
|
|
680
|
+
*
|
|
681
|
+
* Returns a no-op unsubscribe when compaction was off at construction, so
|
|
682
|
+
* every caller can subscribe unconditionally — the contract `subscribeTeam`,
|
|
683
|
+
* `subscribeTodos` and `subscribeFast` already set.
|
|
684
|
+
*/
|
|
685
|
+
subscribeCompaction(listener: CompactionEventListener): () => void;
|
|
494
686
|
/** List usable tools (name + description) for the /tools command. */
|
|
495
687
|
listTools(): AgentTool[];
|
|
496
688
|
}
|