@armadra/agent 0.6.3 → 0.6.5

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.
Files changed (73) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/CHANGELOG.zh-CN.md +21 -0
  3. package/dist/agent/queue.d.ts +9 -0
  4. package/dist/agent/queue.js +27 -0
  5. package/dist/agent/session-subagent.d.ts +1 -0
  6. package/dist/agent/session-subagent.js +9 -0
  7. package/dist/agent/session.d.ts +5 -0
  8. package/dist/agent/session.js +21 -2
  9. package/dist/agent/subagent-direct.d.ts +5 -2
  10. package/dist/agent/subagent-direct.js +34 -1
  11. package/dist/agent/subagent-registry.d.ts +2 -1
  12. package/dist/agent/subagent-registry.js +2 -2
  13. package/dist/agent/types.d.ts +7 -0
  14. package/dist/agents/task-record.d.ts +3 -3
  15. package/dist/ai/apis/chatgpt-rate-limits.js +7 -2
  16. package/dist/ai/types.d.ts +2 -1
  17. package/dist/bundle/ama.cjs +417 -106
  18. package/dist/config/json-schema.js +1 -0
  19. package/dist/config/key-docs.js +8 -1
  20. package/dist/config/schema.js +2 -0
  21. package/dist/config/settings-registry.js +1 -0
  22. package/dist/config/types.d.ts +2 -0
  23. package/dist/drivers/acp/client.d.ts +13 -4
  24. package/dist/drivers/acp/client.js +17 -6
  25. package/dist/drivers/acp/types.d.ts +22 -2
  26. package/dist/drivers/runner.js +29 -2
  27. package/dist/i18n/catalog.d.ts +13 -0
  28. package/dist/i18n/messages/agents.d.ts +4 -0
  29. package/dist/i18n/messages/agents.js +4 -0
  30. package/dist/i18n/messages/config-keys.d.ts +2 -0
  31. package/dist/i18n/messages/config-keys.js +2 -0
  32. package/dist/i18n/messages/config.d.ts +2 -0
  33. package/dist/i18n/messages/interactive-view.d.ts +8 -0
  34. package/dist/i18n/messages/interactive-view.js +10 -0
  35. package/dist/i18n/messages/interactive.d.ts +10 -0
  36. package/dist/i18n/messages/interactive.js +6 -0
  37. package/dist/i18n/messages/report.d.ts +8 -0
  38. package/dist/i18n/messages/report.js +8 -0
  39. package/dist/i18n/messages/settings.d.ts +2 -0
  40. package/dist/i18n/messages/settings.js +2 -0
  41. package/dist/modes/commands-core.js +11 -0
  42. package/dist/modes/interactive/agent-ui.js +1 -0
  43. package/dist/modes/interactive/agent-view.d.ts +5 -0
  44. package/dist/modes/interactive/agent-view.js +14 -3
  45. package/dist/modes/interactive/interactive-mode.js +13 -1
  46. package/dist/modes/interactive/interrupt-send.d.ts +25 -0
  47. package/dist/modes/interactive/interrupt-send.js +32 -0
  48. package/dist/modes/interactive/key-dispatch.d.ts +8 -1
  49. package/dist/modes/interactive/key-dispatch.js +37 -0
  50. package/dist/modes/interactive/line/line-mode.d.ts +1 -0
  51. package/dist/modes/interactive/line/line-mode.js +29 -7
  52. package/dist/modes/interactive/run-indicator.d.ts +19 -2
  53. package/dist/modes/interactive/run-indicator.js +29 -7
  54. package/dist/modes/interactive/status-bar.d.ts +4 -1
  55. package/dist/modes/interactive/status-bar.js +17 -6
  56. package/dist/modes/interactive/status-line.d.ts +10 -9
  57. package/dist/modes/interactive/status-line.js +46 -38
  58. package/dist/modes/interactive/status-quota.d.ts +16 -2
  59. package/dist/modes/interactive/status-quota.js +54 -34
  60. package/dist/modes/interactive/task-background.d.ts +2 -2
  61. package/dist/modes/rpc/commands.d.ts +2 -0
  62. package/dist/modes/rpc/commands.js +15 -1
  63. package/dist/rpc.d.ts +7 -0
  64. package/dist/tools/types.d.ts +6 -0
  65. package/dist/tui/keybindings.d.ts +7 -0
  66. package/dist/tui/keybindings.js +7 -0
  67. package/docs/acp.md +3 -0
  68. package/docs/en/rpc.md +9 -7
  69. package/docs/en/tui.md +49 -31
  70. package/docs/rpc.md +9 -7
  71. package/docs/session-format.md +1 -1
  72. package/docs/tui.md +49 -31
  73. package/package.json +1 -1
package/docs/en/tui.md CHANGED
@@ -39,26 +39,26 @@ The visual spec (colors, glyphs, screen-by-screen mockups) is in [tui-design.md]
39
39
  ────────────────────────────────────────────────
40
40
  › Type a message, / commands, @ files, Shift+Enter newline ← input box (placeholder)
41
41
  ────────────────────────────────────────────────
42
- tps: 100 tok/s • 546 tok / 5.5s (avg 100 · ttft 1.4s) ↑12k ↓1.2k · cache 80% ♨ · [-] ← rate line (full)
43
- Accept edits claude-opus-5-5 medium | Ctx 3.0% | proj ⎇ main 5ae9e54 ↑2 (+12,-3) | $0.26 | 2h24m
44
- Session: 10.0% | Reset: 2h 18m | Weekly: 31.0% | Weekly Reset: 6d 5h ← subscription quota line (full, ChatGPT subscription model)
42
+ codemode on tps: 100 tok/s • 546 tok / 5.5s (avg 100 · ttft 1.4s) · ↑12k ↓1.2k · cache 80% ♨ · [-] ← rate line (full)
43
+ Accept edits | shift+tab to cycle claude-opus-5-5 medium | Ctx 3.0% | proj ⎇ main 5ae9e54 ↑2 (+12,-3) | $0.26 | 2h24m
44
+ Session: 10.0% | Reset: 2h 18m | Weekly: 31.0% | Weekly Reset: 6d 5h ← subscription quota line (full, ChatGPT subscription model)
45
45
  ```
46
46
 
47
- - **User messages**: start with `›`, continuation lines indented 2 columns; steers while running are marked `↳ steer`, messages queued after this turn `↳ after`, and messages injected by the host (the Armadra canvas) `↳ host` (the `origin` in the session file stays steer / followUp / host).
47
+ - **User messages**: start with `›`, continuation lines indented 2 columns; steers while running are marked `↳ steer`, messages queued after this turn `↳ after`, messages injected by the host (the Armadra canvas) `↳ host`, and the new turn opened by interrupt-and-send `↳ interrupt` (the `origin` in the session file stays steer / followUp / host / interrupt).
48
48
  - **Thinking blocks**: `ui.showThinking` = `collapsed` (default: "thinking…" → "thinking · 1.2k tokens", `Ctrl+O` expands it to an indented body of at most 60 lines) / `full` (always expanded) / `hidden`.
49
49
  - **Tool calls**: titled `⏺ tool name summary`; `⏺` is the accent color while running, green on success, red on failure. The second line after `⎿` is the result summary: lines read, `N changes · +a −b`, `exit 0 · 2.1s · 48 lines`, matches and files, `N inner calls · M lines of script output`, `sub-agent · running 1m05s` / `done · 1m42s · ↑28k ↓4.1k`; while running the summary line carries a spinner in the same frame as the bottom and the seconds. Bodies show the first 3 lines folded; `edit` shows a diff (first 12 lines, with line numbers at ≥ 60 columns); running `bash` scrolls its last 8 lines. `Ctrl+O` expands / folds everything (thinking blocks included). Inner calls of a codemode script hang under the outer call (folded, only the titles and summaries of the latest 5 are listed).
50
50
  - **Notices**: `✗` errors, `↻ retry n/m`, `!` warnings (cache misses, remaining context), `⛔` hook blocks, host notifications, explanations of denied or timed-out approvals; compaction / branch summaries are left-bar cards (`▎ context compacted 128k → 24k tokens`).
51
- - **Running**: `⠋ verb · elapsed · …`, with the verb taken from the deepest current state: waiting for confirmation (approval open), `running bash` / `running 3 tools`, `retry 2/3 · in 2s`, compacting context, replying `· ↓≈1.2k` (estimated tokens of this output), thinking. While a foreground sub-agent task blocks the turn, `Ctrl+B to background` is appended; while the agent bar has tasks, `↓ Agent bar` is appended (`↓ handle approval` instead when an approval is docked): `⠏ running task · 4s · Esc to interrupt · Ctrl+B to background · ↓ Agent bar`; items are dropped whole from the end when the line does not fit.
52
- - **Status bar**: the mode is always on the far left; the status bar is the last line except for the subscription quota line in the `full` layout (`compact` always keeps it last). In `compact` the separator is always `·` (embedding hosts parse it), in `full` it is `|`. The layout follows `ui.statusLine`: `full` (two lines) by default in a standalone terminal, `compact` (one line, same layout as before) by default in an embedding host with a profile; `Ctrl+G` or `/statusline [full|compact]` switches at runtime for this session only. With `full` the input box is the 4th line from the bottom (`compact` keeps it 3rd from the bottom).
53
- - **`full` top line (rate line)**: `tps: <rate> tok/s • <output tokens> tok / <elapsed> (avg <session average> · ttft <time to first token>)`. While streaming the rate is the instantaneous value over the last 2 s (`tps:` in the accent color); afterwards it is the request's average; whole replies generated in under 0.25 s get no rate and show `—`; elapsed time starts at the first token; in ASCII `•` becomes `*`. The right side holds usage items: `↑` input (including cache reads and writes) `↓` output · cache · re-billing · queue count · codemode · tool preset (when not default) · host status, with `[-]` at the end hinting that it folds. Only chat requests count (compaction summaries, warming and the classifier do not). When narrow, these drop in order: output / elapsed, codemode, queue count, tokens, cache, re-billing, preset, host status, avg, ttft; `tps` and `[-]` never drop.
51
+ - **Running**: `⠋ verb · elapsed · …`, with the verb taken from the deepest current state: waiting for confirmation (approval open), `running bash` / `running 3 tools`, `retry 2/3 · in 2s`, compacting context, replying `· ↓≈1.2k` (estimated tokens of this output), thinking. While a foreground sub-agent task blocks the turn, `Ctrl+B to background` is appended; while the agent bar has tasks, `↓ Agent bar` is appended (`↓ handle approval` instead when an approval is docked): `⠏ running task · 4s · Esc to interrupt · Ctrl+B to background · ↓ Agent bar`; items are dropped whole from the end when the line does not fit. With text in the input box, `Enter queue · Ctrl+X interrupt & send` comes first (`Enter interrupt & send · Ctrl+X queue` with `ui.enterWhileRunning: "interrupt"`); with queued steers the queue's last line reads `Alt+↑ take back · Ctrl+X send now · Esc refill and interrupt`.
52
+ - **Status bar**: the mode is always on the far left; `full` splits into two sides — the left column holds state and switches (permission mode, the `shift+tab` hint, codemode, sandbox, preset, fallback), the right column holds metrics and the model (tps, usage, model, Ctx, git, cost, duration, quota), right-aligned, and a line with nothing on the left sits flush right; the status bar is the last line except for the subscription quota line in the `full` layout (`compact` always keeps it last). In `compact` the separator is always `·` (embedding hosts parse it), in `full` it is `|`. The layout follows `ui.statusLine`: `full` (two lines) by default in a standalone terminal, `compact` (one line, same layout as before) by default in an embedding host with a profile; `Ctrl+G` or `/statusline [full|compact]` switches at runtime for this session only. With `full` the input box is the 4th line from the bottom (`compact` keeps it 3rd from the bottom).
53
+ - **`full` top line (rate line)**: the left side holds switches: `codemode on|only` (with `net!` when the network is not isolated) · `sandbox` · `preset <name>` (when not default) · `→ <fallback model>` (during a fallback, yellow) · queue count · host status; it is empty when there are none. The right side is `tps: <rate> tok/s • <output tokens> tok / <elapsed> (avg <session average> · ttft <time to first token>) · ↑<input> ↓<output> · cache · re-billing · [-]`. While streaming the rate is the instantaneous value over the last 2 s (`tps:` in the accent color); afterwards it is the request's average; whole replies generated in under 0.25 s get no rate and show `—`; elapsed time starts at the first token; `↑` input includes cache reads and writes; in ASCII `•` becomes `*` and `→` becomes `->`; `[-]` at the end hints that it folds. Only chat requests count (compaction summaries, warming and the classifier do not). When narrow, the right-side metrics drop first (output / elapsed, tokens, cache, re-billing, avg, ttft), then the left-side switches (host status, queue count, preset, fallback, sandbox, codemode); `tps` and `[-]` never drop.
54
54
  - **`full` bottom line**: on the left `permission mode | shift+tab to switch`, on the right `model thinking-level | Ctx 3.0% | <dir name> ⎇ <branch> <short commit> ↑N ↓N (+a,-d) | $cost | session duration` (Ctx with one decimal, no meter even when wide); when narrow, these drop in order: the switch hint, thinking level, line changes, directory name, branch and commit, duration, cost, context, model.
55
- - **Subscription quota line** (third `full` line, below the status bar): when the current model uses a ChatGPT subscription (the `chatgpt` provider) it shows `Session: <used %> | Reset: <time to reset> | Weekly: <used %> | Weekly Reset: <time to reset>` (Chinese labels in the Chinese interface), from the latest `quota_update` (the codex flavor's `x-codex-primary/secondary-*` response headers and `codex.rate_limits` events; siwc only has it after a 429). Reset times are relative (`2h 18m`, `6d 5h`) and refresh once a minute. Before the first request the codex flavor shows "Quota: shown after the first request" (the first request brings the quota back, so holding the line avoids the row count jumping); siwc without data takes no line (it only gets a quota when over the limit, so a placeholder would stay forever); non-subscription models show nothing. Below 80 columns it compresses to `5h 10% ↻2h18m · wk 31% ↻6d5h`, dropping the reset times first when narrower. A window that is not 5 hours / 7 days is labelled with its actual length. `Ctrl+G` / `/statusline compact` folds the quota line together with the rate line (`compact` stays a single line; hosts anchor on "last line = status bar").
55
+ - **Subscription quota line** (third `full` line, below the status bar): when the current model uses a ChatGPT subscription (the `chatgpt` provider) it shows `Session: <used %> | Reset: <time to reset> | Weekly: <used %> | Weekly Reset: <time to reset>` (Chinese labels in the Chinese interface), from the latest `quota_update` (the codex flavor's `x-codex-primary/secondary-*` response headers and `codex.rate_limits` events; siwc only has it after a 429). Reset times are relative (`2h 18m`, `6d 5h`) and refresh once a minute. Before the first request the codex flavor shows "Quota: shown after the first request" (the first request brings the quota back, so holding the line avoids the row count jumping); siwc without data takes no line (it only gets a quota when over the limit, so a placeholder would stay forever); non-subscription models show nothing. Below 80 columns it compresses to `5h 10% ↻2h18m · wk 31% ↻6d5h`, dropping the reset times first when narrower. The quota line is right-aligned. Labels follow the window length rather than the primary / secondary slot: 300 minutes is `Session`, 10080 minutes is `Weekly`, any other length shows the length itself (`1d: `); without a length, primary counts as Session and secondary as Weekly (or the other one if that name is taken); windows are ordered shortest first. A window with 0 % used, no length and no reset time is the server saying "no such window" and is not shown (some plans get a single weekly window from codex, sent as primary). `Ctrl+G` / `/statusline compact` folds the quota line together with the rate line (`compact` stays a single line; hosts anchor on "last line = status bar").
56
56
  - **Colors** (`full`): labels, units, separators and parentheses dim gray; the rate number purple, output / elapsed / avg blue, ttft purple; model and thinking level blue; Ctx and quota percentages by threshold green / yellow / red (≥ 70% yellow, ≥ 90% red); directory and branch green, short commit dim, `↑N` ahead orange, `↓N` behind red, `(+a,-d)` green / red; cost yellow; duration and reset times purple. All come from theme semantic colors with dark / light and 16-color mappings; `NO_COLOR` and ASCII drop the colors and keep the structure. `compact` colors are unchanged.
57
57
  - **`compact`**: one line; on the right model · thinking level · `↑ ↓` · cache · cost · re-billing · context usage · dir ⎇ branch commit +a −b · session duration · queue count · codemode · preset · host status · a short subscription quota item (`5h 10% wk 31%`, only with quota data; no `·` inside the item); when narrow, these drop in order: the quota item, the switch hint, host status, preset, re-billing, cost, cache, tokens, thinking level, queue count, codemode, line changes, directory name, branch and commit, duration, context, model.
58
58
  - **git**: branch and short commit are read directly from `.git/HEAD` (worktrees understood; detached shows only the short commit; outside git the whole part is omitted, leaving only the directory name). `+a −b` is the working tree (staged included) line diff against HEAD, computed in the background with `git diff --numstat HEAD` after a turn ends, a writing tool finishes, a rewind or `/tree`, at most once every 10 seconds; if it takes longer than 2 seconds or fails, line changes are hidden for the rest of the session; `AMA_STATUS_GIT=0` turns it off. In `full`, `↑N` / `↓N` count the commits the current branch is ahead of / behind its upstream: when the branch has an upstream in the git config (`branch.<name>.merge`), the same throttled cycle then runs `git rev-list --left-right --count @{upstream}...HEAD` (same 2-second timeout; after a timeout it stops for the session); zero, no upstream or detached shows nothing; ASCII uses `^N` / `vN`.
59
59
  - **Cost** includes sub-tasks, warming, the classifier and external agent usage priced in USD (other units only in `/session`); **duration** counts from when this process opened the current session (`Ns` / `Nm` / `NhMm`).
60
60
  - When bash commands run in the OS sandbox (`sandbox.bash: "auto"` and available on this machine, see [sandbox.md](../sandbox.md), Chinese), the usage items gain a sandbox marker, dropped first together with codemode when space runs out.
61
- - During a model fallback (`fallbackModel`: when the main model is overloaded or retries are exhausted, one retry with the fallback model) the model item shows `main model → fallback model` (the fallback in yellow); it disappears once the fallback model replies and the main model is restored, and the message area gets an explanatory line.
61
+ - During a model fallback (`fallbackModel`: when the main model is overloaded or retries are exhausted, one retry with the fallback model) the `compact` model item shows `main model → fallback model` (the fallback in yellow), while `full` keeps only the main model there and shows `→ fallback model` on the left of the rate line; it disappears once the fallback model replies and the main model is restored, and the message area gets an explanatory line.
62
62
  - Model names abbreviate with width (provider dropped below 100 columns, channel below 60, version suffix below 48); `compact` at ≥ 110 columns shows context as a meter `ctx ▮▮▮▯▯▯▯▯▯▯ 34%`; changing numbers reserve their widest shape, so items never flicker in and out as values change. In ASCII mode `⎇` → `git`, `−` → `-`, `♨` → `~`, `↻` → `@`.
63
63
  - **Exit**: a session summary line and the resume command are appended at the end of the message area and stay in the terminal scrollback:
64
64
 
@@ -116,27 +116,44 @@ Trade-offs: the status bar shows the latest hit rate (the session total lives in
116
116
 
117
117
  ## Keys
118
118
 
119
- | Key | Effect |
120
- | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
121
- | Enter | Send; while running = steer (inserted into the current turn) |
122
- | Alt+Enter | While running, queue after this turn (followUp); when idle, same as Enter |
123
- | Shift+Enter / Ctrl+J | New line |
124
- | Esc | Interrupt: queued messages go back into the input box, then the current run stops (with foreground sub-agent tasks; background tasks keep running, as the hint says); closes completion first when it is open |
125
- | Esc Esc (idle) | Empty input: open the rewind list (same as `/rewind`); with text: clear it and save it into input history |
126
- | Alt+↑ | Recall the last queued message |
127
- | Shift+Tab / Tab | Cycle permission modes Manual → Accept edits → Plan → Auto → Bypass permissions (Tab only on an empty input with completion closed, otherwise still completion; entering Bypass asks to confirm, see "Entering Bypass" below) |
128
- | Ctrl+O | Expand / fold tool output and thinking blocks |
129
- | Ctrl+L / Ctrl+T | Pick model / thinking level |
130
- | Ctrl+G | Bottom info line two lines (full) ↔ one line (compact), this session only |
131
- | Ctrl+V | Paste an image from the clipboard: saved in the data directory, `@<path>` inserted at the cursor (same as `/paste`) |
132
- | Ctrl+C | Clear the input; on an empty input, press again within 1.5 seconds to quit (exit code 130) |
133
- | Ctrl+D | Quit on an empty input |
134
- | Tab | Complete |
135
- | ↑ / ↓ | Browse history on a single line (`<data dir>/history`, 500 entries) |
136
- | ↓ (empty input) | Enter the agent bar (whenever there are sub-agent tasks); with text it still moves down / through history and hints once, see "Sub-agents" |
137
- | Ctrl+B | When foreground sub-agent tasks (or a `task_ctl wait`) block the turn, move them all to the background, whatever is in the input box; otherwise cursor left. In tmux press `C-b C-b`, see "Sub-agents" |
138
-
139
- Keys can be overridden in `~/.config/ama/keybindings.json`: keys are action ids (`app.interrupt`, `app.rewind`, `app.message.followUp`, `app.statusLine.toggle`, `app.paste.image`, `app.agents.focus`, `app.tasks.background`, `tui.editor.newLine` …), values are a key or an array of keys, and an empty array disables the action. `app.rewind` is the key double-pressed while idle (Esc by default, at most 800 ms apart).
119
+ | Key | Effect |
120
+ | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
121
+ | Enter | Send; while running = steer (queued until the next delivery point: the end of this model reply or of this tool batch) |
122
+ | Ctrl+X | While running, interrupt and send now: stop the current turn (model stream and running tools; tools record "aborted by user") and start a new turn with the input at once, queued steers first; with an empty input only the queued steers are sent now. When idle, same as Enter. Swapped with Enter under `ui.enterWhileRunning: "interrupt"` |
123
+ | Alt+Enter | While running, queue after this turn (followUp); when idle, same as Enter |
124
+ | Shift+Enter / Ctrl+J | New line |
125
+ | Esc | Interrupt: queued messages go back into the input box, then the current run stops (with foreground sub-agent tasks; background tasks keep running, as the hint says); closes completion first when it is open |
126
+ | Esc Esc (idle) | Empty input: open the rewind list (same as `/rewind`); with text: clear it and save it into input history |
127
+ | Alt+↑ | Recall the last queued message |
128
+ | Shift+Tab / Tab | Cycle permission modes Manual → Accept edits → Plan → Auto → Bypass permissions (Tab only on an empty input with completion closed, otherwise still completion; entering Bypass asks to confirm, see "Entering Bypass" below) |
129
+ | Ctrl+O | Expand / fold tool output and thinking blocks |
130
+ | Ctrl+L / Ctrl+T | Pick model / thinking level |
131
+ | Ctrl+G | Bottom info line two lines (full) ↔ one line (compact), this session only |
132
+ | Ctrl+V | Paste an image from the clipboard: saved in the data directory, `@<path>` inserted at the cursor (same as `/paste`) |
133
+ | Ctrl+C | Clear the input; on an empty input, press again within 1.5 seconds to quit (exit code 130) |
134
+ | Ctrl+D | Quit on an empty input |
135
+ | Tab | Complete |
136
+ | ↑ / ↓ | Browse history on a single line (`<data dir>/history`, 500 entries) |
137
+ | ↓ (empty input) | Enter the agent bar (whenever there are sub-agent tasks); with text it still moves down / through history and hints once, see "Sub-agents" |
138
+ | Ctrl+B | When foreground sub-agent tasks (or a `task_ctl wait`) block the turn, move them all to the background, whatever is in the input box; otherwise cursor left. In tmux press `C-b C-b`, see "Sub-agents" |
139
+
140
+ Keys can be overridden in `~/.config/ama/keybindings.json`: keys are action ids (`app.interrupt`, `app.rewind`, `app.message.followUp`, `app.message.interrupt`, `app.statusLine.toggle`, `app.paste.image`, `app.agents.focus`, `app.tasks.background`, `tui.editor.newLine` …), values are a key or an array of keys, and an empty array disables the action. `app.rewind` is the key double-pressed while idle (Esc by default, at most 800 ms apart).
141
+
142
+ ### Interrupt and send now
143
+
144
+ While running, Enter **queues** by default (steer): the message waits for the next delivery point, which can take a long time while the model writes a long reply or a tool runs a five-minute command. To change course right away, write the message and press **`Ctrl+X`** (action `app.message.interrupt`):
145
+
146
+ - The current turn stops at once: the model stream is cut, running tools finish as interrupted (every tool call has exactly one result, recorded as "aborted by user"), and the interrupted reply stays in the session under the abort rules. Then, **without pressing Enter again**, the text is sent as the user message of a new turn (`origin: "interrupt"` in the session, `↳ interrupt` in the message area).
147
+ - Queued steers come along: they are joined in front of the text in queue order (blank line between); messages queued after this turn (Alt+Enter) stay queued and are delivered after the new turn as usual.
148
+ - Only the foreground stops: foreground sub-agent tasks stop with the main turn; background tasks are not affected.
149
+ - Nothing happens while completion, an approval dialog or a picker is open; slash commands still run as commands; with an empty input only the queued steers are sent now (a hint says when there is nothing to send).
150
+ - The request prefix does not change: the new turn's request starts with every message of the interrupted request, so the cache keeps hitting.
151
+ - Esc is unchanged: it still interrupts and puts queued messages back into the input box (see interrupt to withdraw below); it never sends.
152
+ - To make Enter interrupt instead: set `ui.enterWhileRunning` to `interrupt` in `/config` (applies at once); Enter then interrupts and sends and `Ctrl+X` queues.
153
+
154
+ Why `Ctrl+X` by default: macOS Terminal, iTerm2, tmux and Windows Terminal all pass it through and nothing else is bound to it; `Ctrl+Enter` is indistinguishable from Enter without the kitty keyboard protocol, `Ctrl+S` may be swallowed by XOFF flow control, `Alt+Enter` is already followUp, `Alt+letter` sends no Meta by default on macOS, and `Ctrl+]` is awkward on non-US layouts. Rebind it in `keybindings.json`.
155
+
156
+ In line mode (`--no-tui`), typing `/interrupt <text>` while running does the same (when idle it is an ordinary prompt); the TUI accepts the command too. Over RPC it is `interrupt: true` on `prompt` / `steer`, see [rpc.md](rpc.md).
140
157
 
141
158
  ## Rewind
142
159
 
@@ -367,7 +384,8 @@ t2 explore · running 1m05s · 3 turns · ↑12k ↓3.4k · Esc back · /tasks s
367
384
  - The body follows live: for ama sub-agents it shows every message and tool call of the sub-session (rendered like the message area); when the sub-session handle has been released (at most 16 are kept) or the session was resumed, the sub-session file is loaded read-only and live events are attached when the task runs again. External agents (claude / codex / ACP) show the live output held in this process's memory (text, thinking, tool start / end, turns, notices; at most 2000 items / 1 MB, never written to disk); after ama restarts only one line remains, saying to use the original CLI's resume <session id> for the full text.
368
385
  - With an empty input box: `↑` / PgUp scroll up (pausing follow, with "follow paused · End to resume" at the bottom), `↓` / PgDn scroll down, End (or `f` while paused) resumes following; `←` `→` switch to the previous / next task; Esc returns to the main screen. With text in the input box, Esc clears it first.
369
386
  - Enter sends the input to this sub-agent (recorded in the sub-session as a user message with `origin: "direct"`, see [session-format.md](../session-format.md), Chinese): ama sub-agent running → delivered when its current turn ends; external agent running or task still queued → continued after this run ends; finished → continued in the background (like `task_ctl send`; the main session receives the `<task-notification>` as usual when it completes). A line at the bottom reports the result. The parent session's model does not know you talked to the sub-agent directly; the result comes back through the completion notification.
370
- - Nothing is interrupted from the view: Esc only goes back. To stop the task use `/tasks stop <id>`; to move it to the background use `Ctrl+B` or `/tasks bg [id]`. Both work in the view's input box (the only commands the view accepts).
387
+ - `Ctrl+X` interrupts this sub-agent and sends now: an ama sub-agent that is running stops its current turn (tools finish as interrupted) and starts a new turn with the message at once; the task completes and notifies the main session as usual. An external agent whose driver can interrupt a single turn (ACP `session/cancel`, Claude stream-json interrupt, Codex `turn/interrupt`) is interrupted and its next turn starts with the message (and any messages queued before it); when it cannot (oneshot, host drivers) or the task is still waiting in the concurrency pool, the message is queued instead with a hint; a finished task continues in the background as with Enter. Swapped with Enter under `ui.enterWhileRunning: "interrupt"`. The main session is not affected.
388
+ - Esc in the view interrupts nothing: it only goes back. To stop the task use `/tasks stop <id>`; to move it to the background use `Ctrl+B` or `/tasks bg [id]`. Both work in the view's input box (the only commands the view accepts).
371
389
  - When the viewed task waits for approval the title says "awaiting approval", and the approval dialog pops up over the view as usual (with the `[task:<type>]` origin); if its approval is docked in the bar, opening the view pops it up.
372
390
 
373
391
  ### Docked approvals of background tasks
package/docs/rpc.md CHANGED
@@ -36,16 +36,18 @@
36
36
 
37
37
  ### 提示
38
38
 
39
- | 命令 | 参数 | `data` |
40
- | ------------- | --------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
41
- | `prompt` | `message: string`、`images?: ImageBlock[]`、`streamingBehavior?: "steer" \| "followUp"` | `{ disposition: "started" \| "queued" \| "handled" }` |
42
- | `steer` | `message`、`images?` | 同上 |
43
- | `follow_up` | `message`、`images?` | 同上 |
44
- | `abort` | — | `{}`(回到空闲后应答;不清队列) |
45
- | `clear_queue` | — | `{ steering: string[], followUp: string[] }`(被清掉的文本) |
39
+ | 命令 | 参数 | `data` |
40
+ | ------------- | -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
41
+ | `prompt` | `message: string`、`images?: ImageBlock[]`、`streamingBehavior?: "steer" \| "followUp"`、`interrupt?: boolean` | `{ disposition: "started" \| "queued" \| "handled" }` |
42
+ | `steer` | `message`、`images?`、`interrupt?: boolean` | 同上 |
43
+ | `follow_up` | `message`、`images?` | 同上 |
44
+ | `abort` | — | `{}`(回到空闲后应答;不清队列) |
45
+ | `clear_queue` | — | `{ steering: string[], followUp: string[] }`(被清掉的文本) |
46
46
 
47
47
  提示类命令**不等运行结束**:会话开始运行(`before_agent_start` / `agent_start`)、消息入队或被处理(例如斜杠命令、Hook 阻止)后立刻应答,运行进展走事件。运行中发 `prompt` 且不带 `streamingBehavior` → 失败,`code: "busy"`;带上 `steer` / `followUp` 则入队。应答发出之后的运行失败以 `{"type":"notification","level":"error","message":…}` 报告。
48
48
 
49
+ **打断并立即发送**:`prompt` / `steer` 带 `interrupt: true`(优先于 `streamingBehavior`)时,运行中先取走排队的 steer、中止当前回合(模型流断开,正在执行的工具按中断收尾,每个工具调用恰有一个结果 `aborted by user`,被打断的 assistant 消息以 `stopReason: "aborted"` 落盘),再立刻以「排队的 steer… + 本条」(空行拼接)开新回合,应答 `{ disposition: "started" }`;新回合的 user 消息 `origin: "interrupt"`。排在本轮之后的 followUp 留在队列,新回合结束后照常投递;后台子 Agent 不受影响。空闲时等同不带。`interrupt` 不是布尔 → `invalid_arguments`;运行中但本条与排队的 steer 都为空 → `invalid_arguments`(不中断)。事件顺序:`queue_update`(steer 被取走)→ 旧回合 `message_end`(aborted)→ `agent_settled` → `agent_start` → 应答 → 新的 user `message_end` ……(黄金记录 `test/fixtures/rpc/interrupt.out.jsonl`)。新请求以被打断那次请求的全部消息为前缀,缓存照常命中。SDK 对应 `session.prompt(text, { interrupt: true })` / `session.steer(text, { interrupt: true })`。
50
+
49
51
  ### 状态
50
52
 
51
53
  | 命令 | 参数 | `data` |
@@ -48,7 +48,7 @@
48
48
  ### 消息
49
49
 
50
50
  - `system`:`{ role: "system", sections, toolsAdded?, toolsRemoved?, timestamp }`。首条是全量:系统提示的命名节(固定顺序 `preamble → tools → rules → project_context → skills → memory → hooks → cwd → host → role`;`memory` 是第六波的记忆索引节,未开启记忆时不出现)与工具声明表;之后只落**补丁**——节名级替换、值为 `null` 表示删除该节,`toolsAdded` / `toolsRemoved` 增删工具。依次重放得到当前系统提示;请求时由协议层重装全量。首条 system 消息在首次请求前落盘,也就是建文件的时刻。
51
- - `user`:`content`、`origin?`(缺省 = 普通用户输入;`steer` / `followUp` 是运行中插话与排队,`host` 是宿主 `sendUser` 注入,`direct` 是用户在子 Agent 视图里直接发给该子 Agent 的消息(第六波 W6-A,写在子会话里;投影与普通 user 消息相同),其它字符串原样记录)。
51
+ - `user`:`content`、`origin?`(缺省 = 普通用户输入;`steer` / `followUp` 是运行中插话与排队,`host` 是宿主 `sendUser` 注入,`interrupt` 是打断并立即发送开的新回合(TUI `Ctrl+X`、line 模式 `/interrupt`、RPC / SDK 的 `interrupt: true`;投影与普通 user 消息相同),`direct` 是用户在子 Agent 视图里直接发给该子 Agent 的消息(第六波 W6-A,写在子会话里;投影与普通 user 消息相同),其它字符串原样记录)。
52
52
  - `assistant`:`content`(文本 / 思考 / 工具调用块)、`api`、`provider`、`model`、`usage`、`stopReason`,以及可选的 `responseId`、`thinkingLevel`、`providerThinkingLevel`、`rawStopReason`、`errorMessage`。`usage` 是 `{ input, output, cacheRead, cacheWrite, cacheWrite1h?, reasoning?, totalTokens, cost?, cacheReported? }`:`input` 不含缓存部分,`cost` 是 `{ input, output, cacheRead, cacheWrite, total }`(美元,模型无价格时缺省),`cacheReported` 表示原始响应里出现过缓存字段。
53
53
  - `toolResult`:对应工具调用的结果(`toolCallId`、`toolName`、`content`、`isError`、`details?`)。
54
54
 
package/docs/tui.md CHANGED
@@ -33,26 +33,26 @@
33
33
  ────────────────────────────────────────────────
34
34
  › 输入消息,/ 命令,@ 文件,Shift+Enter 换行 ← 输入框(占位)
35
35
  ────────────────────────────────────────────────
36
- tps: 100 tok/s • 546 tok / 5.5s (avg 100 · ttft 1.4s) ↑12k ↓1.2k · cache 80% ♨ · [-] ← 速率行(full)
37
- Accept edits claude-opus-5-5 medium | Ctx 3.0% | proj ⎇ main 5ae9e54 ↑2 (+12,-3) | $0.26 | 2h24m
38
- 5 小时:10.0% | 重置:2h 18m | 本周:31.0% | 本周重置:6d 5h ← 订阅配额行(full,ChatGPT 订阅模型)
36
+ codemode on tps: 100 tok/s • 546 tok / 5.5s (avg 100 · ttft 1.4s) · ↑12k ↓1.2k · cache 80% ♨ · [-] ← 速率行(full)
37
+ Accept edits | shift+tab 切换 claude-opus-5-5 medium | Ctx 3.0% | proj ⎇ main 5ae9e54 ↑2 (+12,-3) | $0.26 | 2h24m
38
+ 5 小时:10.0% | 重置:2h 18m | 本周:31.0% | 本周重置:6d 5h ← 订阅配额行(full,ChatGPT 订阅模型)
39
39
  ```
40
40
 
41
- - **用户消息**:`›` 开头,续行缩进 2 列;运行中插话标 `↳ 插话`,排到本轮之后的标 `↳ 之后`,宿主(Armadra 画布)注入的标 `↳ 宿主`(会话文件里的 `origin` 不变:steer / followUp / host)。
41
+ - **用户消息**:`›` 开头,续行缩进 2 列;运行中插话标 `↳ 插话`,排到本轮之后的标 `↳ 之后`,宿主(Armadra 画布)注入的标 `↳ 宿主`,打断并发送开的新回合标 `↳ 打断`(会话文件里的 `origin` 不变:steer / followUp / host / interrupt)。
42
42
  - **思考块**:`ui.showThinking` = `collapsed`(缺省,`✻ 思考中…` → `✻ 思考 · 1.2k token`,`Ctrl+O` 展开为缩进的正文,最多 60 行)/ `full`(总是展开)/ `hidden`。
43
43
  - **工具调用**:标题 `⏺ 工具名 摘要`,`⏺` 运行中为强调色、成功绿、失败红;第二行 `⎿` 后是结果摘要——`读取 N 行`、`N 处修改 · +a −b`、`退出 0 · 2.1s · 48 行`、`14 处匹配 · 6 个文件`、`N 个内层调用 · 脚本输出 M 行`、`子 Agent · 运行中 1m05s` / `完成 · 1m42s · ↑28k ↓4.1k`;运行中摘要行带与底部同帧的 spinner 与秒数。正文折叠显示前 3 行,`edit` 显示 diff(前 12 行,≥ 60 列带行号),`bash` 运行中滚动显示最后 8 行。`Ctrl+O` 展开 / 折叠全部(含思考块)。codemode 脚本里的内层调用挂在外层调用下面(折叠时只列最近 5 个的标题与摘要)。
44
44
  - **提示**:`✗` 错误、`↻ 重试 n/m`、`!` 警告(缓存未命中、上下文余量)、`⛔ Hook 阻止`、宿主通知、审批被拒或超时的说明;压缩 / 分支摘要是左竖条卡片(`▎ 上下文已压缩 128k → 24k token`)。
45
- - **运行中**:`⠋ 动词 · 已用时 · …`,动词按当前最深状态取:`等待确认`(审批打开)、`运行 bash` / `运行 3 个工具`、`重试 2/3 · 2s 后`、`压缩上下文`、`回复中 · ↓≈1.2k`(本条输出的估算 token)、`思考中`。有阻塞中的前台子 Agent 任务时加 `Ctrl+B 转后台`,Agent 栏里有任务时加 `↓ Agent 栏`(有停靠的审批时换成 `↓ 处理审批`):`⠏ 运行 task · 4s · Esc 中断 · Ctrl+B 转后台 · ↓ Agent 栏`,一行放不下时从后往前整项丢掉。
46
- - **状态栏**:模式永远在最左;除 full 布局下的订阅配额行外,状态栏是最后一行(`compact` 永远是最后一行)。`compact` 的分隔符固定为 `·`(嵌入宿主按此解析),`full` 用 `|`。布局由 `ui.statusLine` 决定:独立终端缺省 `full`(两行),有 profile 的嵌入宿主缺省 `compact`(一行,布局与以前相同);运行时 `Ctrl+G` 或 `/statusline [full|compact]` 切换,只影响本会话。`full` 时输入框在倒数第 4 行(`compact` 仍是倒数第 3 行)。
47
- - **`full` 上行(速率行)**:`tps: <速率> tok/s • <输出 token> tok / <耗时> (avg <会话均速> · ttft <首 token 延迟>)`——速率在流式中是最近 2 s 的瞬时值(`tps:` 强调色),结束后是该请求的平均值,生成不足 0.25 s 的整块回复不算速率、显示 `—`;耗时从首 token 起;ASCII 下 `•` 为 `*`。右区是用量类项 `↑` 输入(含缓存读写)`↓` 输出 · 缓存 · 重计费 · 排队数 · codemode · 工具预设(非 default 时)· 宿主状态,行尾 `[-]` 提示可折叠。只统计对话请求(压缩摘要、保温、分类器不计)。窄时依次丢弃 输出量 / 耗时、codemode、排队数、token、缓存、重计费、预设、宿主状态、avg、ttft;`tps` 与 `[-]` 不丢。
45
+ - **运行中**:`⠋ 动词 · 已用时 · …`,动词按当前最深状态取:`等待确认`(审批打开)、`运行 bash` / `运行 3 个工具`、`重试 2/3 · 2s 后`、`压缩上下文`、`回复中 · ↓≈1.2k`(本条输出的估算 token)、`思考中`。有阻塞中的前台子 Agent 任务时加 `Ctrl+B 转后台`,Agent 栏里有任务时加 `↓ Agent 栏`(有停靠的审批时换成 `↓ 处理审批`):`⠏ 运行 task · 4s · Esc 中断 · Ctrl+B 转后台 · ↓ Agent 栏`,一行放不下时从后往前整项丢掉。输入框有字时最前面加 `Enter 排队 · Ctrl+X 打断并发送`(`ui.enterWhileRunning: "interrupt"` 时是 `Enter 打断并发送 · Ctrl+X 排队`);有排队的插话时队列末行是 `Alt+↑ 取回 · Ctrl+X 立即发送 · Esc 回填并中断`。
46
+ - **状态栏**:模式永远在最左;`full` 左右分区——左列是状态与开关(权限模式、`shift+tab` 提示、codemode、沙箱、预设、回退),右列是度量与模型(tps、用量、模型、Ctx、git、费用、时长、配额),右列右对齐、左列为空时整行靠右;除 full 布局下的订阅配额行外,状态栏是最后一行(`compact` 永远是最后一行)。`compact` 的分隔符固定为 `·`(嵌入宿主按此解析),`full` 用 `|`。布局由 `ui.statusLine` 决定:独立终端缺省 `full`(两行),有 profile 的嵌入宿主缺省 `compact`(一行,布局与以前相同);运行时 `Ctrl+G` 或 `/statusline [full|compact]` 切换,只影响本会话。`full` 时输入框在倒数第 4 行(`compact` 仍是倒数第 3 行)。
47
+ - **`full` 上行(速率行)**:左区是开关类项 `codemode on|only`(网络未隔离时追加 `net!`)· `沙箱` · `preset <名>`(非 default 时)· `→ <回退模型>`(回退中,黄色)· 排队数 · 宿主状态,没有时左区为空。右区 `tps: <速率> tok/s • <输出 token> tok / <耗时> (avg <会话均速> · ttft <首 token 延迟>) · ↑<输入> ↓<输出> · 缓存 · 重计费 · [-]`——速率在流式中是最近 2 s 的瞬时值(`tps:` 强调色),结束后是该请求的平均值,生成不足 0.25 s 的整块回复不算速率、显示 `—`;耗时从首 token 起;`↑` 输入含缓存读写;ASCII 下 `•` 为 `*`、`→` 为 `->`;行尾 `[-]` 提示可折叠。只统计对话请求(压缩摘要、保温、分类器不计)。窄时先丢右区度量(输出量 / 耗时、token、缓存、重计费、avg、ttft),再丢左区开关(宿主状态、排队数、预设、回退、沙箱、codemode);`tps` 与 `[-]` 不丢。
48
48
  - **`full` 下行**:左区 `权限模式 | shift+tab 切换`,右区 `模型 思考级别 | Ctx 3.0% | <目录名> ⎇ <分支> <短提交> ↑N ↓N (+a,-d) | $费用 | 会话时长`(Ctx 一位小数,宽屏也不换余量表);窄时依次丢弃切换提示、思考级别、增删行、目录名、分支与提交、时长、费用、上下文、模型。
49
- - **订阅配额行**(`full` 第三行,在状态栏下方):当前模型走 ChatGPT 订阅(`chatgpt` 供应商)时显示 `5 小时:<已用%> | 重置:<距重置> | 本周:<已用%> | 本周重置:<距重置>`(英文界面 `Session: … | Reset: … | Weekly: … | Weekly Reset: …`),数据来自最近一次 `quota_update`(codex 方式的 `x-codex-primary/secondary-*` 响应头与 `codex.rate_limits` 事件;siwc 只有超限 429 时才有)。重置时间是相对时长(`2h 18m`、`6d 5h`),每分钟刷新一次。codex 方式在第一次请求前显示「配额:首次请求后显示」(第一次请求就会带回配额,先占住行免得行数跳动);siwc 没有数据时不占行(只有超限才有配额,占位会一直挂着);非订阅模型不显示。窄于 80 列时压缩为 `5h 10% ↻2h18m · 周 31% ↻6d5h`,再窄先丢重置时间。窗口长度不是 5 小时 / 7 天时标签换成实际时长。`Ctrl+G` / `/statusline compact` 折叠时配额行与速率行一起收起(`compact` 只保留一行,宿主按「最后一行 = 状态栏」锚定)。
49
+ - **订阅配额行**(`full` 第三行,在状态栏下方):当前模型走 ChatGPT 订阅(`chatgpt` 供应商)时显示 `5 小时:<已用%> | 重置:<距重置> | 本周:<已用%> | 本周重置:<距重置>`(英文界面 `Session: … | Reset: … | Weekly: … | Weekly Reset: …`),数据来自最近一次 `quota_update`(codex 方式的 `x-codex-primary/secondary-*` 响应头与 `codex.rate_limits` 事件;siwc 只有超限 429 时才有)。重置时间是相对时长(`2h 18m`、`6d 5h`),每分钟刷新一次。codex 方式在第一次请求前显示「配额:首次请求后显示」(第一次请求就会带回配额,先占住行免得行数跳动);siwc 没有数据时不占行(只有超限才有配额,占位会一直挂着);非订阅模型不显示。窄于 80 列时压缩为 `5h 10% ↻2h18m · 周 31% ↻6d5h`,再窄先丢重置时间。配额行在右区右对齐。标签按窗口时长认而不是按 primary / secondary 槽位:300 分钟是「5 小时」、10080 分钟是「本周」,其它时长用实际时长(`1d:`);缺时长时 primary 当 5 小时、secondary 当本周(与另一个窗口撞名时取另一种);按时长从短到长排。用量 0、无时长、无重置时间的窗口是服务端的「没有这个窗口」,不显示(有的套餐 codex 只送一个周窗口,放在 primary)。`Ctrl+G` / `/statusline compact` 折叠时配额行与速率行一起收起(`compact` 只保留一行,宿主按「最后一行 = 状态栏」锚定)。
50
50
  - **配色**(`full`):标签、单位、分隔符与括号暗灰;速率数字紫、输出量 / 耗时 / avg 蓝、ttft 紫;模型与思考级别蓝;Ctx 与配额百分比按阈值绿 / 黄 / 红(≥ 70% 黄、≥ 90% 红);目录与分支绿、短提交暗灰、`↑N` 领先橙、`↓N` 落后红、`(+a,-d)` 绿 / 红;费用黄;时长与重置时间紫。都取主题语义色,深 / 浅主题与 16 色各有对应;`NO_COLOR` 与 ASCII 不着色、结构不变。`compact` 的着色不变。
51
51
  - **`compact`**:一行,右区 模型 · 思考级别 · `↑ ↓` · 缓存 · 费用 · 重计费 · 上下文占用 · 目录 ⎇ 分支 提交 +a −b · 会话时长 · 排队数 · codemode · 预设 · 宿主状态 · 订阅配额短项(`5h 10% 周 31%`,只在有配额数据时;项内不含 `·`);窄时依次丢弃配额短项、切换提示、宿主状态、预设、重计费、费用、缓存、token、思考级别、排队数、codemode、增删行、目录名、分支与提交、时长、上下文、模型。
52
52
  - **git**:分支与短提交直接读 `.git/HEAD`(worktree 认;detached 只显示短提交;非 git 目录整段省略,只剩目录名);`+a −b` 是工作区(含暂存)相对 HEAD 的增删行,回合结束、写类工具结束、回滚、`/tree` 之后在后台跑 `git diff --numstat HEAD`,至多 10 秒一次,超过 2 秒或失败就本会话不再显示增删;`AMA_STATUS_GIT=0` 关闭。`full` 的 `↑N` / `↓N` 是当前分支领先 / 落后上游的提交数:分支在 git 配置里有上游(`branch.<名>.merge`)时,同一节流周期接着跑 `git rev-list --left-right --count @{upstream}...HEAD`(同样 2 秒超时,超时本会话不再统计);为 0、没有上游或 detached 不显示;ASCII 下为 `^N` / `vN`。
53
53
  - **费用**含子任务、保温、分类器与外部 Agent 以美元计的用量(其它单位只在 `/session`);**时长**从本进程打开当前会话起算(`Ns` / `Nm` / `NhMm`)。
54
54
  - bash 命令在操作系统沙箱里跑时(`sandbox.bash: "auto"` 且本机可用,见 [sandbox.md](sandbox.md))用量类项多一个 `沙箱`,宽度不够时与 codemode 一起先丢。
55
- - 模型回退中(`fallbackModel`,主模型过载或重试用尽后改用回退模型重试一次)模型项显示 `主模型 → 回退模型`(回退模型黄色),回退模型回复、切回主模型后消失;消息区同时有一行说明。
55
+ - 模型回退中(`fallbackModel`,主模型过载或重试用尽后改用回退模型重试一次)`compact` 的模型项显示 `主模型 → 回退模型`(回退模型黄色),`full` 的模型项只留主模型、速率行左区显示 `→ 回退模型`,回退模型回复、切回主模型后消失;消息区同时有一行说明。
56
56
  - 模型名随宽度缩写(< 100 列去供应商、< 60 去渠道、< 48 去版本后缀);`compact` ≥ 110 列时上下文显示为余量表 `ctx ▮▮▮▯▯▯▯▯▯▯ 34%`;会变的数字按最宽形状占位,数值变化不会让某项时有时无。ASCII 模式 `⎇` → `git`、`−` → `-`、`♨` → `~`、`↻` → `@`。
57
57
  - **退出**:消息区最后追加一行会话摘要与恢复命令,留在终端回滚里:
58
58
 
@@ -110,27 +110,44 @@ Accept edits claude-opus-5-5 medium | Ctx 3.0% | proj ⎇ main 5ae9e54 ↑2
110
110
 
111
111
  ## 按键
112
112
 
113
- | 按键 | 作用 |
114
- | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
115
- | Enter | 发送;运行中 = steer(插到当前轮) |
116
- | Alt+Enter | 运行中排到本轮之后(followUp);空闲时等同 Enter |
117
- | Shift+Enter / Ctrl+J | 换行 |
118
- | Esc | 中断:排队的消息回填到输入框,然后停止当前运行(连带前台子 Agent 任务;后台任务不受影响,提示里写明);补全打开时先关补全 |
119
- | Esc Esc(空闲) | 输入框为空:打开回滚列表(同 `/rewind`);有字:清空并存进输入历史 |
120
- | Alt+↑ | 取回最后一条排队消息 |
121
- | Shift+Tab / Tab | 循环权限模式 Manual → Accept edits → Plan → Auto → Bypass permissions(Tab 只在输入为空、补全未打开时,否则仍是补全;进入 Bypass 前确认,见下文「进入 Bypass」) |
122
- | Ctrl+O | 展开 / 折叠工具输出与思考块 |
123
- | Ctrl+L / Ctrl+T | 选择模型 / 思考级别 |
124
- | Ctrl+G | 底部信息行 两行(full)↔ 一行(compact),只影响本会话 |
125
- | Ctrl+V | 粘贴剪贴板里的图片:存进数据目录,光标处插入 `@<路径>`(同 `/paste`) |
126
- | Ctrl+C | 清空输入;输入为空时 1.5 秒内再按一次退出(退出码 130) |
127
- | Ctrl+D | 输入为空时退出 |
128
- | Tab | 补全 |
129
- | ↑ / ↓ | 单行时浏览历史(`<数据目录>/history`,500 条) |
130
- | ↓(空输入) | 进入 Agent 栏(有子 Agent 任务即可);有字时仍是下移 / 历史并提示一次,见「子 Agent」 |
131
- | Ctrl+B | 有阻塞中的前台子 Agent 任务(或 `task_ctl wait`)时全部转后台,不看输入框有没有字;没有时是光标左移。tmux 里按 `C-b C-b`,见「子 Agent」 |
132
-
133
- 按键可在 `~/.config/ama/keybindings.json` 覆盖,键是动作 id(`app.interrupt`、`app.rewind`、`app.message.followUp`、`app.statusLine.toggle`、`app.paste.image`、`app.agents.focus`、`app.tasks.background`、`tui.editor.newLine` ……),值是按键或按键数组,空数组表示禁用。`app.rewind` 是空闲时双击的那个键(缺省 Esc,两次间隔 ≤ 800 ms)。
113
+ | 按键 | 作用 |
114
+ | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
115
+ | Enter | 发送;运行中 = steer(排队,等下一个投递点:本次模型回复结束或本批工具结束) |
116
+ | Ctrl+X | 运行中打断并立即发送:中止当前回合(模型流与正在跑的工具,工具记「aborted by user」),立刻以输入框的文字开新回合,排队的插话拼在前面;输入为空时只把排队的插话立即送出。空闲时等同 Enter。`ui.enterWhileRunning: "interrupt"` 时与 Enter 互换 |
117
+ | Alt+Enter | 运行中排到本轮之后(followUp);空闲时等同 Enter |
118
+ | Shift+Enter / Ctrl+J | 换行 |
119
+ | Esc | 中断:排队的消息回填到输入框,然后停止当前运行(连带前台子 Agent 任务;后台任务不受影响,提示里写明);补全打开时先关补全 |
120
+ | Esc Esc(空闲) | 输入框为空:打开回滚列表(同 `/rewind`);有字:清空并存进输入历史 |
121
+ | Alt+↑ | 取回最后一条排队消息 |
122
+ | Shift+Tab / Tab | 循环权限模式 Manual → Accept edits → Plan → Auto → Bypass permissions(Tab 只在输入为空、补全未打开时,否则仍是补全;进入 Bypass 前确认,见下文「进入 Bypass」) |
123
+ | Ctrl+O | 展开 / 折叠工具输出与思考块 |
124
+ | Ctrl+L / Ctrl+T | 选择模型 / 思考级别 |
125
+ | Ctrl+G | 底部信息行 两行(full)↔ 一行(compact),只影响本会话 |
126
+ | Ctrl+V | 粘贴剪贴板里的图片:存进数据目录,光标处插入 `@<路径>`(同 `/paste`) |
127
+ | Ctrl+C | 清空输入;输入为空时 1.5 秒内再按一次退出(退出码 130) |
128
+ | Ctrl+D | 输入为空时退出 |
129
+ | Tab | 补全 |
130
+ | ↑ / ↓ | 单行时浏览历史(`<数据目录>/history`,500 条) |
131
+ | ↓(空输入) | 进入 Agent 栏(有子 Agent 任务即可);有字时仍是下移 / 历史并提示一次,见「子 Agent」 |
132
+ | Ctrl+B | 有阻塞中的前台子 Agent 任务(或 `task_ctl wait`)时全部转后台,不看输入框有没有字;没有时是光标左移。tmux 里按 `C-b C-b`,见「子 Agent」 |
133
+
134
+ 按键可在 `~/.config/ama/keybindings.json` 覆盖,键是动作 id(`app.interrupt`、`app.rewind`、`app.message.followUp`、`app.message.interrupt`、`app.statusLine.toggle`、`app.paste.image`、`app.agents.focus`、`app.tasks.background`、`tui.editor.newLine` ……),值是按键或按键数组,空数组表示禁用。`app.rewind` 是空闲时双击的那个键(缺省 Esc,两次间隔 ≤ 800 ms)。
135
+
136
+ ### 打断并立即发送
137
+
138
+ 运行中按 Enter 缺省是**排队**(steer):消息等下一个投递点才送达——模型在长篇输出、或工具在跑一个 5 分钟的命令时要等很久。要立刻改方向,在输入框写好后按 **`Ctrl+X`**(动作 `app.message.interrupt`):
139
+
140
+ - 当前回合立即中止:模型流断开,正在执行的工具按中断收尾(每个工具调用恰有一个结果,记「aborted by user」),被打断的回复按中断规则留在会话里;随后**不用再按 Enter**,这段文字直接作为新回合的用户消息发出(会话里 `origin: "interrupt"`,消息区标 `↳ 打断`)。
141
+ - 已排队的插话一起带上:按入队顺序拼在这段文字前面(空行分隔);排到本轮之后的(Alt+Enter)留在队列,新回合结束后照常送达。
142
+ - 只连带前台:前台子 Agent 任务随主回合中止,后台任务不受影响。
143
+ - 补全打开、审批框或选择器打开时不触发;斜杠命令照常当命令执行;输入为空时只把排队的插话立即送出(没有可发的内容时提示一行)。
144
+ - 中断的请求前缀不变:新回合的请求以被打断那次请求的全部消息为前缀,缓存照常命中。
145
+ - Esc 不变:仍是中断并把排队消息回填输入框(中断即撤回见下文),不会自动发送。
146
+ - 想让 Enter 直接打断:`/config` 里把 `ui.enterWhileRunning` 设为 `interrupt`(立即生效),这时 Enter 打断并发送、`Ctrl+X` 排队。
147
+
148
+ 缺省键选 `Ctrl+X` 的原因:macOS Terminal、iTerm2、tmux、Windows Terminal 都原样送达,且没有别的绑定;`Ctrl+Enter` 不开 kitty 键盘协议时与 Enter 无法区分,`Ctrl+S` 可能被 XOFF 流控吃掉,`Alt+Enter` 已是 followUp,`Alt+字母` 在 macOS 缺省不送 Meta,`Ctrl+]` 在非美式键盘上难按。可在 `keybindings.json` 改。
149
+
150
+ line 模式(`--no-tui`)运行中输入 `/interrupt <文本>` 效果相同(空闲时就是普通提示);交互界面里也认这条命令。RPC 是 `prompt` / `steer` 的 `interrupt: true`,见 [rpc.md](rpc.md)。
134
151
 
135
152
  ## 回滚
136
153
 
@@ -360,7 +377,8 @@ t2 explore · 运行中 1m05s · 3 轮 · ↑12k ↓3.4k · Esc 返回 · /tasks
360
377
  - 正文实时跟随:ama 子 Agent 显示子会话的全部消息与工具调用(与消息区同样的渲染);子会话句柄已被释放(保留上限 16 个)或会话是 resume 进来的,就只读加载子会话文件,任务再次运行时接上实时事件。外部 Agent(claude / codex / ACP)显示本进程内存里的实时输出(文本、思考、工具起止、回合、提示;最多 2000 条 / 1 MB,不落盘);ama 重启后只剩一行说明「用原 CLI resume <会话 id> 查看全文」。
361
378
  - 输入框为空时:`↑` / PgUp 上翻(暂停跟随,底部提示「已暂停跟随 · End 继续」),`↓` / PgDn 下翻,End(暂停时也可按 `f`)回到跟随;`←` `→` 切到上一个 / 下一个任务;Esc 返回主界面。输入框有字时 Esc 先清空。
362
379
  - Enter 把输入发给这个子 Agent(会话里记为 `origin: "direct"` 的 user 消息,见 [session-format.md](session-format.md)):ama 子 Agent 运行中 → 排到它本轮结束时送达;外部 Agent 运行中或任务还在排队 → 等本次运行结束后续聊;已结束 → 后台续聊(同 `task_ctl send`,完成后主会话照常收到 `<task-notification>`)。底部一行提示发送结果。父会话的模型不知道你直接和子 Agent 说过话,结果经结束通知自然带回。
363
- - 视图里不中断任何东西:Esc 只是返回。停止子任务用 `/tasks stop <id>`,转后台用 `Ctrl+B` 或 `/tasks bg [id]`——在视图输入框里也能用(视图里只认这两条命令)。
380
+ - `Ctrl+X` 打断并发送给这个子 Agent:ama 子 Agent 运行中 → 中止它当前这一轮(工具按中断收尾)并立即以这条消息开新一轮,任务照常完成、照常通知主会话;外部 Agent 的驱动能中断单个回合(ACP `session/cancel`、Claude stream-json interrupt、Codex `turn/interrupt`)→ 中断后立即以它(连同之前排着的消息)开下一回合;不能(oneshot、宿主驱动)或任务还在并发池排队 → 退回排队并提示「不支持打断,已排队」;已结束 → 同 Enter 的后台续聊。`ui.enterWhileRunning: "interrupt"` 时与 Enter 互换。主会话不受影响。
381
+ - 视图里 Esc 不中断任何东西:Esc 只是返回。停止子任务用 `/tasks stop <id>`,转后台用 `Ctrl+B` 或 `/tasks bg [id]`——在视图输入框里也能用(视图里只认这两条命令)。
364
382
  - 正在看的任务等审批时标题显示「等待审批」,审批框照常弹在视图上面(带 `[task:<类型>]` 来源);它的审批停靠在栏里时,打开视图即弹出。
365
383
 
366
384
  ### 后台任务的审批停靠
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@armadra/agent",
3
- "version": "0.6.3",
3
+ "version": "0.6.5",
4
4
  "description": "A coding and coordination agent that runs standalone or embedded in Armadra",
5
5
  "type": "module",
6
6
  "keywords": [