@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.
- package/CHANGELOG.md +29 -0
- package/CHANGELOG.zh-CN.md +21 -0
- package/dist/agent/queue.d.ts +9 -0
- package/dist/agent/queue.js +27 -0
- package/dist/agent/session-subagent.d.ts +1 -0
- package/dist/agent/session-subagent.js +9 -0
- package/dist/agent/session.d.ts +5 -0
- package/dist/agent/session.js +21 -2
- package/dist/agent/subagent-direct.d.ts +5 -2
- package/dist/agent/subagent-direct.js +34 -1
- package/dist/agent/subagent-registry.d.ts +2 -1
- package/dist/agent/subagent-registry.js +2 -2
- package/dist/agent/types.d.ts +7 -0
- package/dist/agents/task-record.d.ts +3 -3
- package/dist/ai/apis/chatgpt-rate-limits.js +7 -2
- package/dist/ai/types.d.ts +2 -1
- package/dist/bundle/ama.cjs +417 -106
- package/dist/config/json-schema.js +1 -0
- package/dist/config/key-docs.js +8 -1
- package/dist/config/schema.js +2 -0
- package/dist/config/settings-registry.js +1 -0
- package/dist/config/types.d.ts +2 -0
- package/dist/drivers/acp/client.d.ts +13 -4
- package/dist/drivers/acp/client.js +17 -6
- package/dist/drivers/acp/types.d.ts +22 -2
- package/dist/drivers/runner.js +29 -2
- package/dist/i18n/catalog.d.ts +13 -0
- package/dist/i18n/messages/agents.d.ts +4 -0
- package/dist/i18n/messages/agents.js +4 -0
- package/dist/i18n/messages/config-keys.d.ts +2 -0
- package/dist/i18n/messages/config-keys.js +2 -0
- package/dist/i18n/messages/config.d.ts +2 -0
- package/dist/i18n/messages/interactive-view.d.ts +8 -0
- package/dist/i18n/messages/interactive-view.js +10 -0
- package/dist/i18n/messages/interactive.d.ts +10 -0
- package/dist/i18n/messages/interactive.js +6 -0
- package/dist/i18n/messages/report.d.ts +8 -0
- package/dist/i18n/messages/report.js +8 -0
- package/dist/i18n/messages/settings.d.ts +2 -0
- package/dist/i18n/messages/settings.js +2 -0
- package/dist/modes/commands-core.js +11 -0
- package/dist/modes/interactive/agent-ui.js +1 -0
- package/dist/modes/interactive/agent-view.d.ts +5 -0
- package/dist/modes/interactive/agent-view.js +14 -3
- package/dist/modes/interactive/interactive-mode.js +13 -1
- package/dist/modes/interactive/interrupt-send.d.ts +25 -0
- package/dist/modes/interactive/interrupt-send.js +32 -0
- package/dist/modes/interactive/key-dispatch.d.ts +8 -1
- package/dist/modes/interactive/key-dispatch.js +37 -0
- package/dist/modes/interactive/line/line-mode.d.ts +1 -0
- package/dist/modes/interactive/line/line-mode.js +29 -7
- package/dist/modes/interactive/run-indicator.d.ts +19 -2
- package/dist/modes/interactive/run-indicator.js +29 -7
- package/dist/modes/interactive/status-bar.d.ts +4 -1
- package/dist/modes/interactive/status-bar.js +17 -6
- package/dist/modes/interactive/status-line.d.ts +10 -9
- package/dist/modes/interactive/status-line.js +46 -38
- package/dist/modes/interactive/status-quota.d.ts +16 -2
- package/dist/modes/interactive/status-quota.js +54 -34
- package/dist/modes/interactive/task-background.d.ts +2 -2
- package/dist/modes/rpc/commands.d.ts +2 -0
- package/dist/modes/rpc/commands.js +15 -1
- package/dist/rpc.d.ts +7 -0
- package/dist/tools/types.d.ts +6 -0
- package/dist/tui/keybindings.d.ts +7 -0
- package/dist/tui/keybindings.js +7 -0
- package/docs/acp.md +3 -0
- package/docs/en/rpc.md +9 -7
- package/docs/en/tui.md +49 -31
- package/docs/rpc.md +9 -7
- package/docs/session-format.md +1 -1
- package/docs/tui.md +49 -31
- package/package.json +1 -1
package/dist/bundle/ama.cjs
CHANGED
|
@@ -41,7 +41,7 @@ var AMA_VERSION;
|
|
|
41
41
|
var init_version = __esm({
|
|
42
42
|
"src/version.ts"() {
|
|
43
43
|
"use strict";
|
|
44
|
-
AMA_VERSION = true ? "0.6.
|
|
44
|
+
AMA_VERSION = true ? "0.6.5" : readPackageVersion();
|
|
45
45
|
}
|
|
46
46
|
});
|
|
47
47
|
|
|
@@ -1734,7 +1734,8 @@ var init_interactive_view = __esm({
|
|
|
1734
1734
|
followUp: "follow-up",
|
|
1735
1735
|
host: "host",
|
|
1736
1736
|
task: "subagent notice",
|
|
1737
|
-
plan: "plan"
|
|
1737
|
+
plan: "plan",
|
|
1738
|
+
interrupt: "interrupt"
|
|
1738
1739
|
},
|
|
1739
1740
|
planHandoff: "Start executing the approved plan",
|
|
1740
1741
|
thinkingStreaming: (glyph, ellipsis) => `${glyph} Thinking${ellipsis}`,
|
|
@@ -1762,7 +1763,11 @@ var init_interactive_view = __esm({
|
|
|
1762
1763
|
replying: "Replying",
|
|
1763
1764
|
thinking: "Thinking",
|
|
1764
1765
|
queueMore: (ellipsis, n) => `${ellipsis} ${n} more`,
|
|
1765
|
-
queueHint: (arrow) => `Alt+${arrow} take back · Esc refill and interrupt
|
|
1766
|
+
queueHint: (arrow) => `Alt+${arrow} take back · Esc refill and interrupt`,
|
|
1767
|
+
/** 有排队的插话时(`key` = 立即送出它们的键:专用键,或 interrupt 模式下的 Enter)。 */
|
|
1768
|
+
queueHintNow: (arrow, key) => `Alt+${arrow} take back · ${key} send now · Esc refill and interrupt`,
|
|
1769
|
+
/** 输入框有字时:Enter 与专用键各做什么(`ui.enterWhileRunning`)。 */
|
|
1770
|
+
sendHint: (mode, key) => mode === "queue" ? `Enter queue · ${key} interrupt & send` : `Enter interrupt & send · ${key} queue`
|
|
1766
1771
|
},
|
|
1767
1772
|
tool: {
|
|
1768
1773
|
interrupted: "interrupted",
|
|
@@ -1800,7 +1805,8 @@ var init_interactive_view = __esm({
|
|
|
1800
1805
|
followUp: "之后",
|
|
1801
1806
|
host: "宿主",
|
|
1802
1807
|
task: "子 Agent 通知",
|
|
1803
|
-
plan: "计划"
|
|
1808
|
+
plan: "计划",
|
|
1809
|
+
interrupt: "打断"
|
|
1804
1810
|
},
|
|
1805
1811
|
planHandoff: "按批准的计划开始执行",
|
|
1806
1812
|
thinkingStreaming: (glyph, ellipsis) => `${glyph} 思考中${ellipsis}`,
|
|
@@ -1828,7 +1834,9 @@ var init_interactive_view = __esm({
|
|
|
1828
1834
|
replying: "回复中",
|
|
1829
1835
|
thinking: "思考中",
|
|
1830
1836
|
queueMore: (ellipsis, n) => `${ellipsis} 另 ${n} 条`,
|
|
1831
|
-
queueHint: (arrow) => `Alt+${arrow} 取回 · Esc
|
|
1837
|
+
queueHint: (arrow) => `Alt+${arrow} 取回 · Esc 回填并中断`,
|
|
1838
|
+
queueHintNow: (arrow, key) => `Alt+${arrow} 取回 · ${key} 立即发送 · Esc 回填并中断`,
|
|
1839
|
+
sendHint: (mode, key) => mode === "queue" ? `Enter 排队 · ${key} 打断并发送` : `Enter 打断并发送 · ${key} 排队`
|
|
1832
1840
|
},
|
|
1833
1841
|
tool: {
|
|
1834
1842
|
interrupted: "已中断",
|
|
@@ -1875,6 +1883,7 @@ var init_interactive = __esm({
|
|
|
1875
1883
|
keyHints: [
|
|
1876
1884
|
"Enter send (while running = steer) Alt+Enter queue after this turn Shift+Enter / Ctrl+J newline",
|
|
1877
1885
|
"Esc interrupt (queued messages go back to the editor) Alt+↑ take back the last queued message",
|
|
1886
|
+
"Ctrl+X (while running) interrupt the current turn and send the input now, queued steers first; ui.enterWhileRunning: interrupt swaps it with Enter",
|
|
1878
1887
|
"Idle Esc Esc: empty input = rewind (/rewind), with text = clear (↑ to restore)",
|
|
1879
1888
|
"Shift+Tab / Tab (empty input) cycle permission mode (confirm before Bypass) Ctrl+L model Ctrl+T thinking level Ctrl+O expand tool output and thinking",
|
|
1880
1889
|
"Approval: 1–3 or ↑↓ Enter to choose, y allow a allow for this session n / Esc deny v full input",
|
|
@@ -1917,6 +1926,8 @@ var init_interactive = __esm({
|
|
|
1917
1926
|
clearedCtrlC: "Input cleared · press Ctrl+C again to quit",
|
|
1918
1927
|
ctrlCAgain: "Press Ctrl+C again to quit",
|
|
1919
1928
|
interrupted: "Interrupted",
|
|
1929
|
+
interruptSent: "Interrupted · sending now",
|
|
1930
|
+
nothingToSend: "Nothing to send",
|
|
1920
1931
|
toolsExpanded: "Tool output: expanded",
|
|
1921
1932
|
toolsCollapsed: "Tool output: collapsed"
|
|
1922
1933
|
},
|
|
@@ -2007,6 +2018,7 @@ var init_interactive = __esm({
|
|
|
2007
2018
|
keyHints: [
|
|
2008
2019
|
"Enter 发送(运行中 = 插话) Alt+Enter 排到本轮之后 Shift+Enter / Ctrl+J 换行",
|
|
2009
2020
|
"Esc 中断(排队消息回填编辑器) Alt+↑ 取回最后一条排队消息",
|
|
2021
|
+
"Ctrl+X(运行中)打断当前回合并立即发送输入(排队的插话在前);ui.enterWhileRunning: interrupt 时与 Enter 互换",
|
|
2010
2022
|
"空闲时 Esc Esc:输入框为空 = 回滚(/rewind),有字 = 清空(↑ 取回)",
|
|
2011
2023
|
"Shift+Tab / Tab(输入为空时)切换权限模式(进入 Bypass 前确认) Ctrl+L 模型 Ctrl+T 思考级别 Ctrl+O 展开工具输出与思考",
|
|
2012
2024
|
"审批:1–3 或 ↑↓ Enter 选择,y 允许 a 本会话允许同类 n / Esc 拒绝 v 完整输入",
|
|
@@ -2047,6 +2059,8 @@ var init_interactive = __esm({
|
|
|
2047
2059
|
clearedCtrlC: "已清空输入 · 再按 Ctrl+C 退出",
|
|
2048
2060
|
ctrlCAgain: "再按一次 Ctrl+C 退出",
|
|
2049
2061
|
interrupted: "已中断",
|
|
2062
|
+
interruptSent: "已打断,立即发送",
|
|
2063
|
+
nothingToSend: "没有可发送的内容",
|
|
2050
2064
|
toolsExpanded: "工具输出:展开",
|
|
2051
2065
|
toolsCollapsed: "工具输出:折叠"
|
|
2052
2066
|
},
|
|
@@ -2983,6 +2997,8 @@ var init_report = __esm({
|
|
|
2983
2997
|
tasks: "Sub-agent tasks: status, output, stop, background",
|
|
2984
2998
|
agents: "Sub-agent types and external agents (installed, version)",
|
|
2985
2999
|
paste: "Paste an image from the clipboard (Ctrl+V)",
|
|
3000
|
+
interruptArgs: "<text>",
|
|
3001
|
+
interrupt: "Interrupt the current turn and send this now, queued steers first (Ctrl+X)",
|
|
2986
3002
|
exit: "Exit",
|
|
2987
3003
|
config: "Settings panel; key=value sets one item directly (user level)",
|
|
2988
3004
|
traceArgs: "[task id]",
|
|
@@ -3001,6 +3017,8 @@ var init_report = __esm({
|
|
|
3001
3017
|
cacheUsage: "usage: /cache [warm off|streaming|idle | fingerprint]",
|
|
3002
3018
|
taskStopped: (id) => `Stopped ${id}`,
|
|
3003
3019
|
tasksUsage: "usage: /tasks [id] | /tasks stop <id> | /tasks bg [id]",
|
|
3020
|
+
interruptUsage: "usage: /interrupt <text>",
|
|
3021
|
+
interruptSent: (text) => `Interrupted; sending now: ${text}`,
|
|
3004
3022
|
newSession: (id) => `New session ${id}`,
|
|
3005
3023
|
resumed: (id, messages) => `Resumed session ${id} (${plural(messages, "message")})`,
|
|
3006
3024
|
forked: (id) => `Forked to new session ${id}`,
|
|
@@ -3222,6 +3240,8 @@ Available: ${inactive.join(", ")}` : ""}`,
|
|
|
3222
3240
|
tasks: "子 Agent 任务:状态、输出、停止、转后台",
|
|
3223
3241
|
agents: "子 Agent 类型与外部 Agent(安装状态、版本)",
|
|
3224
3242
|
paste: "粘贴剪贴板里的图片(Ctrl+V)",
|
|
3243
|
+
interruptArgs: "<文本>",
|
|
3244
|
+
interrupt: "打断当前回合并立即发送这段文字,排队的插话在前(Ctrl+X)",
|
|
3225
3245
|
exit: "退出",
|
|
3226
3246
|
config: "设置面板;key=value 直接设一项(用户级)",
|
|
3227
3247
|
traceArgs: "[任务 id]",
|
|
@@ -3239,6 +3259,8 @@ Available: ${inactive.join(", ")}` : ""}`,
|
|
|
3239
3259
|
cacheUsage: "用法:/cache [warm off|streaming|idle | fingerprint]",
|
|
3240
3260
|
taskStopped: (id) => `已停止 ${id}`,
|
|
3241
3261
|
tasksUsage: "用法:/tasks [id] | /tasks stop <id> | /tasks bg [id]",
|
|
3262
|
+
interruptUsage: "用法:/interrupt <文本>",
|
|
3263
|
+
interruptSent: (text) => `已打断,立即发送:${text}`,
|
|
3242
3264
|
newSession: (id) => `已新建会话 ${id}`,
|
|
3243
3265
|
resumed: (id, messages) => `已恢复会话 ${id}(${messages} 条消息)`,
|
|
3244
3266
|
forked: (id) => `已分叉到新会话 ${id}`,
|
|
@@ -3628,6 +3650,7 @@ var init_config_keys = __esm({
|
|
|
3628
3650
|
"ui.logo": "AMA logo in the startup header: auto draws it when the terminal is at least 48 columns wide, off shows only the info lines",
|
|
3629
3651
|
"ui.animation": "false: the spinner stays still while running and redraws only when seconds change; the startup logo does not animate",
|
|
3630
3652
|
"ui.restoreOnCancel": "When Esc interrupts a run before any reply or tool call in this turn, withdraw the turn and put the message back into the input box",
|
|
3653
|
+
"ui.enterWhileRunning": "Enter while a run is in progress: queue (default) queues the message as a steer delivered at the next delivery point; interrupt stops the current turn and sends it at once. The app.message.interrupt key (default Ctrl+X) does the other one",
|
|
3631
3654
|
"ui.statusLine": "Bottom info line: full shows two lines (rate line + status line), compact one; toggle at runtime with Ctrl+G or /statusline (effective from wave 5 W5-A)",
|
|
3632
3655
|
"ui.language": "Interface language: auto decides from LC_ALL / LC_MESSAGES / LANG (zh* is Chinese, anything else English), zh, en; AMA_LANG and --lang override; affects the interface only, text sent to the model is always English",
|
|
3633
3656
|
"ui.replyLanguage": "Reply language for the model (e.g. Chinese): one English rule is appended to the end of the rules section at session start; zero-byte change when unset; user level only (effective from wave 6)",
|
|
@@ -3750,6 +3773,7 @@ var init_config_keys = __esm({
|
|
|
3750
3773
|
"ui.logo": "启动头的 AMA 字符画:auto 在终端宽 48 列以上时画,off 只显示信息行",
|
|
3751
3774
|
"ui.animation": "false:运行中 spinner 静止,只在秒数变化时重绘;启动字符画不播放动画",
|
|
3752
3775
|
"ui.restoreOnCancel": "运行中 Esc 中断、本回合还没有任何回复或工具调用时,撤回该回合并把原消息放回输入框",
|
|
3776
|
+
"ui.enterWhileRunning": "运行中按 Enter:queue(缺省)排队插话,等下一个投递点送达;interrupt 打断当前回合并立即发送。app.message.interrupt 键(缺省 Ctrl+X)做另一种",
|
|
3753
3777
|
"ui.statusLine": "底部信息行:full 两行(速率行 + 状态行),compact 一行;运行时 Ctrl+G 或 /statusline 切换(第五波 W5-A 起生效)",
|
|
3754
3778
|
"ui.language": "界面语言:auto 按 LC_ALL / LC_MESSAGES / LANG 判断(zh* 为中文,其余英文),zh,en;AMA_LANG、--lang 覆盖;只影响界面,发给模型的文本固定英文",
|
|
3755
3779
|
"ui.replyLanguage": "模型回复语言(如 Chinese):会话开始在 rules 节末尾追加一句英文规则;不设时零字节变化;只认用户级(第六波起生效)",
|
|
@@ -4696,6 +4720,8 @@ var init_agents = __esm({
|
|
|
4696
4720
|
steered: (taskId) => `Sent to ${taskId}; delivered when its current turn ends`,
|
|
4697
4721
|
queued: (taskId) => `Queued for ${taskId}; sent when its current run ends`,
|
|
4698
4722
|
resumed: (taskId) => `Sent to ${taskId}; it continues in the background`,
|
|
4723
|
+
interrupted: (taskId) => `Interrupted ${taskId}; your message starts its next turn now`,
|
|
4724
|
+
queuedNoInterrupt: (taskId) => `${taskId} cannot be interrupted here; queued, sent when its current run ends`,
|
|
4699
4725
|
sendFailed: (message) => `Could not send: ${message}`,
|
|
4700
4726
|
stopped: (taskId) => `Stopped ${taskId}`,
|
|
4701
4727
|
commandsHere: "Only /tasks stop and /tasks bg work here; press Esc to go back for other commands",
|
|
@@ -4758,6 +4784,8 @@ var init_agents = __esm({
|
|
|
4758
4784
|
steered: (taskId) => `已发给 ${taskId},本轮结束后送达`,
|
|
4759
4785
|
queued: (taskId) => `已排队,${taskId} 本次运行结束后发送`,
|
|
4760
4786
|
resumed: (taskId) => `已发给 ${taskId},在后台继续`,
|
|
4787
|
+
interrupted: (taskId) => `已打断 ${taskId},这条消息立即开始新一轮`,
|
|
4788
|
+
queuedNoInterrupt: (taskId) => `${taskId} 不支持打断,已排队,本次运行结束后发送`,
|
|
4761
4789
|
sendFailed: (message) => `发送失败:${message}`,
|
|
4762
4790
|
stopped: (taskId) => `已停止 ${taskId}`,
|
|
4763
4791
|
commandsHere: "这里只能用 /tasks stop 与 /tasks bg;其它命令按 Esc 返回后输入",
|
|
@@ -5396,6 +5424,7 @@ var init_settings = __esm({
|
|
|
5396
5424
|
"ui.logo": "Startup logo",
|
|
5397
5425
|
"ui.statusLine": "Status line",
|
|
5398
5426
|
"ui.restoreOnCancel": "Restore on cancel",
|
|
5427
|
+
"ui.enterWhileRunning": "Enter while running",
|
|
5399
5428
|
"ui.quietStartup": "Startup screen",
|
|
5400
5429
|
"ui.ascii": "ASCII glyphs",
|
|
5401
5430
|
"ui.language": "Interface language",
|
|
@@ -5567,6 +5596,7 @@ var init_settings = __esm({
|
|
|
5567
5596
|
"ui.logo": "启动字符画",
|
|
5568
5597
|
"ui.statusLine": "底部信息行",
|
|
5569
5598
|
"ui.restoreOnCancel": "中断后放回原消息",
|
|
5599
|
+
"ui.enterWhileRunning": "运行中按 Enter",
|
|
5570
5600
|
"ui.quietStartup": "启动画面",
|
|
5571
5601
|
"ui.ascii": "ASCII 字形",
|
|
5572
5602
|
"ui.language": "界面语言",
|
|
@@ -7101,6 +7131,7 @@ function validateConfig(value) {
|
|
|
7101
7131
|
"logo",
|
|
7102
7132
|
"animation",
|
|
7103
7133
|
"restoreOnCancel",
|
|
7134
|
+
"enterWhileRunning",
|
|
7104
7135
|
...W5_UI_KEYS,
|
|
7105
7136
|
...W6_UI_KEYS
|
|
7106
7137
|
],
|
|
@@ -7115,6 +7146,7 @@ function validateConfig(value) {
|
|
|
7115
7146
|
c.oneOf(s2, "logo", p, ["auto", "off"]);
|
|
7116
7147
|
c.boolean(s2, "animation", p);
|
|
7117
7148
|
c.boolean(s2, "restoreOnCancel", p);
|
|
7149
|
+
c.oneOf(s2, "enterWhileRunning", p, ["queue", "interrupt"]);
|
|
7118
7150
|
checkUiW5(c, s2, p);
|
|
7119
7151
|
checkUiW6(c, s2, p);
|
|
7120
7152
|
}
|
|
@@ -18176,6 +18208,24 @@ function queuedText(message) {
|
|
|
18176
18208
|
if (typeof content === "string") return content;
|
|
18177
18209
|
return content.map((block) => block.type === "text" ? block.text : "[image]").join("");
|
|
18178
18210
|
}
|
|
18211
|
+
function mergeForInterrupt(queued, text, images = []) {
|
|
18212
|
+
const texts2 = [];
|
|
18213
|
+
const merged = [];
|
|
18214
|
+
for (const message of queued) {
|
|
18215
|
+
if (message.role !== "user") continue;
|
|
18216
|
+
const { content } = message;
|
|
18217
|
+
if (typeof content === "string") texts2.push(content);
|
|
18218
|
+
else {
|
|
18219
|
+
texts2.push(content.map((block) => block.type === "text" ? block.text : "").join(""));
|
|
18220
|
+
for (const block of content) if (block.type === "image") merged.push(block);
|
|
18221
|
+
}
|
|
18222
|
+
}
|
|
18223
|
+
texts2.push(text);
|
|
18224
|
+
merged.push(...images);
|
|
18225
|
+
const parts = texts2.filter((part) => part.trim() !== "");
|
|
18226
|
+
if (parts.length === 0 && merged.length === 0) return void 0;
|
|
18227
|
+
return { text: parts.join("\n\n"), images: merged };
|
|
18228
|
+
}
|
|
18179
18229
|
var PendingMessageQueue;
|
|
18180
18230
|
var init_queue = __esm({
|
|
18181
18231
|
"src/agent/queue.ts"() {
|
|
@@ -23296,10 +23346,16 @@ function liveOf(record3) {
|
|
|
23296
23346
|
if (entries !== void 0) live2.entries = () => entries.call(handle);
|
|
23297
23347
|
return live2;
|
|
23298
23348
|
}
|
|
23299
|
-
async function directMessage(record3, text, host) {
|
|
23349
|
+
async function directMessage(record3, text, host, interrupt = false) {
|
|
23300
23350
|
if (text.trim() === "") throw new AmaError("invalid_arguments", "empty message");
|
|
23301
23351
|
if (record3.running !== void 0) {
|
|
23302
23352
|
const handle = record3.handle;
|
|
23353
|
+
if (interrupt && record3.queued !== true && await interruptRun(record3, text))
|
|
23354
|
+
return "interrupted";
|
|
23355
|
+
if (interrupt) {
|
|
23356
|
+
(record3.direct ??= []).push(text);
|
|
23357
|
+
return "queuedNoInterrupt";
|
|
23358
|
+
}
|
|
23303
23359
|
if (handle?.message !== void 0 && record3.queued !== true) {
|
|
23304
23360
|
try {
|
|
23305
23361
|
await handle.message(text, "followUp");
|
|
@@ -23314,6 +23370,24 @@ async function directMessage(record3, text, host) {
|
|
|
23314
23370
|
await resumeDirect(record3, text, host);
|
|
23315
23371
|
return "resumed";
|
|
23316
23372
|
}
|
|
23373
|
+
async function interruptRun(record3, text) {
|
|
23374
|
+
const handle = record3.handle;
|
|
23375
|
+
if (handle?.message !== void 0) {
|
|
23376
|
+
try {
|
|
23377
|
+
await handle.message(text, "interrupt");
|
|
23378
|
+
return true;
|
|
23379
|
+
} catch (error2) {
|
|
23380
|
+
if (error2 instanceof AmaError && error2.code === "task_idle") return false;
|
|
23381
|
+
throw error2;
|
|
23382
|
+
}
|
|
23383
|
+
}
|
|
23384
|
+
if (handle?.interrupt === void 0) return false;
|
|
23385
|
+
const queued = record3.direct ?? [];
|
|
23386
|
+
const merged = [...queued, text].join("\n\n");
|
|
23387
|
+
if (!await handle.interrupt(merged)) return false;
|
|
23388
|
+
queued.splice(0);
|
|
23389
|
+
return true;
|
|
23390
|
+
}
|
|
23317
23391
|
async function resumeDirect(record3, text, host) {
|
|
23318
23392
|
const spawn9 = host.spawnSubagent;
|
|
23319
23393
|
if (spawn9 === void 0)
|
|
@@ -23656,10 +23730,10 @@ var init_subagent_registry = __esm({
|
|
|
23656
23730
|
return record3 === void 0 ? void 0 : liveOf(record3);
|
|
23657
23731
|
}
|
|
23658
23732
|
/** [W6-A] 人在子 Agent 视图里发的消息(subagent-direct.ts)。 */
|
|
23659
|
-
async message(taskId, text) {
|
|
23733
|
+
async message(taskId, text, interrupt = false) {
|
|
23660
23734
|
const record3 = this.tasks.get(taskId);
|
|
23661
23735
|
if (record3 === void 0) throw new AmaError("task_not_found", `unknown task ${taskId}`);
|
|
23662
|
-
return directMessage(record3, text, this.host);
|
|
23736
|
+
return directMessage(record3, text, this.host, interrupt);
|
|
23663
23737
|
}
|
|
23664
23738
|
async stop(taskId) {
|
|
23665
23739
|
const record3 = this.tasks.get(taskId);
|
|
@@ -24109,6 +24183,7 @@ async function startAmaChild(parent, spec2, createChild, run7) {
|
|
|
24109
24183
|
run7.signal.addEventListener("abort", onAbort, { once: true });
|
|
24110
24184
|
let billed = { cacheRead: 0, prompt: 0, reBilled: 0 };
|
|
24111
24185
|
let active = false;
|
|
24186
|
+
const forced2 = [];
|
|
24112
24187
|
const runOnce = async (prompt, origin) => {
|
|
24113
24188
|
const startTurns = turns;
|
|
24114
24189
|
let error2;
|
|
@@ -24117,6 +24192,7 @@ async function startAmaChild(parent, spec2, createChild, run7) {
|
|
|
24117
24192
|
if (run7.signal.aborted) throw new AmaError("aborted", "aborted");
|
|
24118
24193
|
await child.prompt(prompt, origin === void 0 ? {} : { origin });
|
|
24119
24194
|
for (; ; ) {
|
|
24195
|
+
while (forced2.length > 0) await forced2.shift();
|
|
24120
24196
|
const left = child.clearQueue?.().followUp ?? [];
|
|
24121
24197
|
if (left.length === 0 || run7.signal.aborted) break;
|
|
24122
24198
|
await child.prompt(left.join("\n\n"), { origin: "direct" });
|
|
@@ -24161,6 +24237,10 @@ async function startAmaChild(parent, spec2, createChild, run7) {
|
|
|
24161
24237
|
}
|
|
24162
24238
|
if (!active || child.followUp === void 0)
|
|
24163
24239
|
throw new AmaError("task_idle", "the sub-agent is not running");
|
|
24240
|
+
if (when === "interrupt") {
|
|
24241
|
+
forced2.push(child.prompt(text, { origin: "direct", interrupt: true }));
|
|
24242
|
+
return;
|
|
24243
|
+
}
|
|
24164
24244
|
await child.followUp(text, { origin: "direct" });
|
|
24165
24245
|
},
|
|
24166
24246
|
wait: () => current3,
|
|
@@ -26088,6 +26168,8 @@ var init_session2 = __esm({
|
|
|
26088
26168
|
// -------------------------------------------------------------------------
|
|
26089
26169
|
async prompt(text, options = {}) {
|
|
26090
26170
|
this.assertUsable();
|
|
26171
|
+
if (options.interrupt === true && this.cycle !== void 0)
|
|
26172
|
+
return this.interruptWith(text, options.images, options.origin);
|
|
26091
26173
|
if (this.cycle !== void 0) {
|
|
26092
26174
|
const behavior = options.streamingBehavior;
|
|
26093
26175
|
if (behavior === void 0) {
|
|
@@ -26115,7 +26197,9 @@ var init_session2 = __esm({
|
|
|
26115
26197
|
}
|
|
26116
26198
|
async enqueueOrRun(text, queue, options) {
|
|
26117
26199
|
this.assertUsable();
|
|
26118
|
-
|
|
26200
|
+
if (options.interrupt === true && this.cycle !== void 0)
|
|
26201
|
+
return this.interruptWith(text, void 0, options.origin).then(() => "handled");
|
|
26202
|
+
const origin = normalizeOrigin(options.origin ?? (options.interrupt === true ? "user" : queue));
|
|
26119
26203
|
if (this.cycle === void 0) {
|
|
26120
26204
|
await this.startCycle((signal) => runPrompt(this.runDeps(), text, void 0, origin, signal));
|
|
26121
26205
|
return "handled";
|
|
@@ -26129,6 +26213,19 @@ var init_session2 = __esm({
|
|
|
26129
26213
|
followUp(text, options = {}) {
|
|
26130
26214
|
return this.enqueueOrRun(text, "followUp", options);
|
|
26131
26215
|
}
|
|
26216
|
+
/**
|
|
26217
|
+
* 打断并立即发送:取走排队的 steer、中止当前周期(工具按 abort 收尾),以「steer… + 本条」开新回合;
|
|
26218
|
+
* followUp 留在队列。没有可发的内容 → invalid_arguments(不打断)。
|
|
26219
|
+
*/
|
|
26220
|
+
async interruptWith(text, images, origin) {
|
|
26221
|
+
const merged = mergeForInterrupt(this.agent.steeringQueue.snapshot(), text, images);
|
|
26222
|
+
if (merged === void 0) throw new AmaError("invalid_arguments", "nothing to send");
|
|
26223
|
+
this.agent.steeringQueue.clear();
|
|
26224
|
+
this.emitQueue();
|
|
26225
|
+
while (this.cycle !== void 0) await this.abort();
|
|
26226
|
+
const kind = normalizeOrigin(origin ?? "interrupt");
|
|
26227
|
+
return this.startCycle((s2) => runPrompt(this.runDeps(), merged.text, merged.images, kind, s2));
|
|
26228
|
+
}
|
|
26132
26229
|
async abort() {
|
|
26133
26230
|
const cycle = this.cycle;
|
|
26134
26231
|
if (cycle === void 0) return;
|
|
@@ -30641,6 +30738,9 @@ var init_jsonrpc = __esm({
|
|
|
30641
30738
|
});
|
|
30642
30739
|
|
|
30643
30740
|
// src/drivers/acp/client.ts
|
|
30741
|
+
function mcpServersOf(options) {
|
|
30742
|
+
return [...options?.mcpServers ?? []];
|
|
30743
|
+
}
|
|
30644
30744
|
function unattendedOutcome(params) {
|
|
30645
30745
|
const reject2 = params.options.find((o) => o.kind === "reject_once");
|
|
30646
30746
|
return {
|
|
@@ -30672,6 +30772,11 @@ var init_client = __esm({
|
|
|
30672
30772
|
});
|
|
30673
30773
|
}
|
|
30674
30774
|
options;
|
|
30775
|
+
/**
|
|
30776
|
+
* 本版客户端支持的可选能力,供宿主做特性检测(旧版没有这个字段):
|
|
30777
|
+
* - `mcpServers`:开会话时可经 {@link AcpSessionOptions} 传 MCP 服务器。
|
|
30778
|
+
*/
|
|
30779
|
+
static features = { mcpServers: true };
|
|
30675
30780
|
peer;
|
|
30676
30781
|
/** sessionId → 挂起权限请求的取消器。 */
|
|
30677
30782
|
pendingPermissions = /* @__PURE__ */ new Map();
|
|
@@ -30721,16 +30826,28 @@ var init_client = __esm({
|
|
|
30721
30826
|
supportsImages() {
|
|
30722
30827
|
return this.agentCapabilities.promptCapabilities?.image === true;
|
|
30723
30828
|
}
|
|
30724
|
-
newSession(cwd, signal) {
|
|
30725
|
-
return this.peer.request(
|
|
30829
|
+
newSession(cwd, signal, options) {
|
|
30830
|
+
return this.peer.request(
|
|
30831
|
+
ACP_METHODS.sessionNew,
|
|
30832
|
+
{ cwd, mcpServers: mcpServersOf(options) },
|
|
30833
|
+
signal
|
|
30834
|
+
);
|
|
30726
30835
|
}
|
|
30727
30836
|
/** 不回放历史(优先,R13:v2 计划取消 load)。 */
|
|
30728
|
-
resumeSession(sessionId, cwd, signal) {
|
|
30729
|
-
return this.peer.request(
|
|
30837
|
+
resumeSession(sessionId, cwd, signal, options) {
|
|
30838
|
+
return this.peer.request(
|
|
30839
|
+
ACP_METHODS.sessionResume,
|
|
30840
|
+
{ sessionId, cwd, mcpServers: mcpServersOf(options) },
|
|
30841
|
+
signal
|
|
30842
|
+
);
|
|
30730
30843
|
}
|
|
30731
30844
|
/** 回放历史(以 session/update 通知)。 */
|
|
30732
|
-
loadSession(sessionId, cwd, signal) {
|
|
30733
|
-
return this.peer.request(
|
|
30845
|
+
loadSession(sessionId, cwd, signal, options) {
|
|
30846
|
+
return this.peer.request(
|
|
30847
|
+
ACP_METHODS.sessionLoad,
|
|
30848
|
+
{ sessionId, cwd, mcpServers: mcpServersOf(options) },
|
|
30849
|
+
signal
|
|
30850
|
+
);
|
|
30734
30851
|
}
|
|
30735
30852
|
listSessions(cwd, cursor) {
|
|
30736
30853
|
return this.peer.request(ACP_METHODS.sessionList, {
|
|
@@ -32742,7 +32859,7 @@ function failed3(text, sessionId, runner) {
|
|
|
32742
32859
|
...sessionId !== "" ? { sessionRef: { runner, sessionId } } : {}
|
|
32743
32860
|
};
|
|
32744
32861
|
}
|
|
32745
|
-
var RUN_TIMEOUT_MS, IDLE_CLOSE_MS, ProcessRunner, ProcessHandle;
|
|
32862
|
+
var RUN_TIMEOUT_MS, IDLE_CLOSE_MS, ProcessRunner, TURN_INTERRUPT, ProcessHandle;
|
|
32746
32863
|
var init_runner = __esm({
|
|
32747
32864
|
"src/drivers/runner.ts"() {
|
|
32748
32865
|
"use strict";
|
|
@@ -32828,6 +32945,12 @@ var init_runner = __esm({
|
|
|
32828
32945
|
return this.deps;
|
|
32829
32946
|
}
|
|
32830
32947
|
};
|
|
32948
|
+
TURN_INTERRUPT = /* @__PURE__ */ new Set([
|
|
32949
|
+
"acp",
|
|
32950
|
+
"acp-adapter",
|
|
32951
|
+
"claude-stream",
|
|
32952
|
+
"codex-app-server"
|
|
32953
|
+
]);
|
|
32831
32954
|
ProcessHandle = class {
|
|
32832
32955
|
constructor(runner, chosen, request, deps) {
|
|
32833
32956
|
this.runner = runner;
|
|
@@ -32899,8 +33022,22 @@ var init_runner = __esm({
|
|
|
32899
33022
|
}
|
|
32900
33023
|
this.chain = this.chain.then(() => this.runTurn(text));
|
|
32901
33024
|
}
|
|
32902
|
-
|
|
32903
|
-
|
|
33025
|
+
/** 跟到链尾:回合进行中被 `interrupt` 接上的下一回合也算在这次运行里。 */
|
|
33026
|
+
async wait() {
|
|
33027
|
+
for (; ; ) {
|
|
33028
|
+
const chain = this.chain;
|
|
33029
|
+
const result = await chain;
|
|
33030
|
+
if (chain === this.chain) return result;
|
|
33031
|
+
}
|
|
33032
|
+
}
|
|
33033
|
+
/** 子 Agent 视图的「打断并发送」:中断当前回合,紧接着以 `text` 开下一回合。 */
|
|
33034
|
+
async interrupt(text) {
|
|
33035
|
+
const session = this.session;
|
|
33036
|
+
if (this.stopped || !this.busy || session === void 0) return false;
|
|
33037
|
+
if (!TURN_INTERRUPT.has(this.chosen.driver.kind)) return false;
|
|
33038
|
+
this.chain = this.chain.then(() => this.runTurn(text));
|
|
33039
|
+
await session.cancel();
|
|
33040
|
+
return true;
|
|
32904
33041
|
}
|
|
32905
33042
|
async stop() {
|
|
32906
33043
|
if (this.stopped) return;
|
|
@@ -34957,10 +35094,11 @@ function window(used, minutes, resetSeconds) {
|
|
|
34957
35094
|
if (usedPercent === void 0) return void 0;
|
|
34958
35095
|
const out = { usedPercent: Math.max(0, Math.min(100, usedPercent)) };
|
|
34959
35096
|
const m = num(minutes);
|
|
34960
|
-
if (m !== void 0) out.windowMinutes = m;
|
|
35097
|
+
if (m !== void 0 && m > 0) out.windowMinutes = m;
|
|
34961
35098
|
const reset = num(resetSeconds);
|
|
34962
35099
|
if (reset !== void 0 && reset > 0) out.resetsAt = reset * 1e3;
|
|
34963
|
-
|
|
35100
|
+
const empty = out.usedPercent === 0 && out.windowMinutes === void 0 && out.resetsAt === void 0;
|
|
35101
|
+
return empty ? void 0 : out;
|
|
34964
35102
|
}
|
|
34965
35103
|
function snapshot(primary, secondary, plan2) {
|
|
34966
35104
|
const out = {};
|
|
@@ -35306,7 +35444,14 @@ var init_key_docs = __esm({
|
|
|
35306
35444
|
codemode: { inlineBudget: DEFAULT_INLINE_BUDGET, requireStrict: false },
|
|
35307
35445
|
cache: { ...DEFAULT_CACHE_CONFIG },
|
|
35308
35446
|
request: { idleTimeoutMs: DEFAULT_IDLE_TIMEOUT_MS },
|
|
35309
|
-
ui: {
|
|
35447
|
+
ui: {
|
|
35448
|
+
compact: false,
|
|
35449
|
+
logo: "auto",
|
|
35450
|
+
animation: true,
|
|
35451
|
+
restoreOnCancel: true,
|
|
35452
|
+
enterWhileRunning: "queue",
|
|
35453
|
+
language: "auto"
|
|
35454
|
+
},
|
|
35310
35455
|
// [W6-C0] 第六波键的缺省(行为由各批次实现)
|
|
35311
35456
|
memory: {
|
|
35312
35457
|
enabled: false,
|
|
@@ -35709,6 +35854,7 @@ function buildBaseSchema() {
|
|
|
35709
35854
|
logo: oneOf(["auto", "off"]),
|
|
35710
35855
|
animation: bool(),
|
|
35711
35856
|
restoreOnCancel: bool(),
|
|
35857
|
+
enterWhileRunning: oneOf(["queue", "interrupt"]),
|
|
35712
35858
|
statusLine: oneOf(STATUS_LINE_MODES),
|
|
35713
35859
|
language: oneOf(LANGUAGE_SETTINGS),
|
|
35714
35860
|
replyLanguage: str3(),
|
|
@@ -39722,6 +39868,7 @@ var init_settings_registry = __esm({
|
|
|
39722
39868
|
row("ui.logo", "ui", "restart", "any"),
|
|
39723
39869
|
row("ui.statusLine", "ui", "now", "any"),
|
|
39724
39870
|
row("ui.restoreOnCancel", "ui", "nextSession", "any"),
|
|
39871
|
+
row("ui.enterWhileRunning", "ui", "now", "any"),
|
|
39725
39872
|
row("ui.quietStartup", "ui", "restart", "any"),
|
|
39726
39873
|
row("ui.ascii", "ui", "restart", "any", { envOverride: "AMA_ASCII" }),
|
|
39727
39874
|
row("ui.language", "ui", "restart", "any", { envOverride: "AMA_LANG" }),
|
|
@@ -41477,6 +41624,13 @@ var init_keybindings = __esm({
|
|
|
41477
41624
|
"app.exit": ["ctrl+d"],
|
|
41478
41625
|
"app.message.followUp": ["alt+enter"],
|
|
41479
41626
|
"app.message.dequeue": ["alt+up"],
|
|
41627
|
+
/**
|
|
41628
|
+
* 运行中打断当前回合并立即发送输入框的文字(连同排队的插话);`ui.enterWhileRunning: "interrupt"` 时与
|
|
41629
|
+
* Enter 互换(它变成排队)。缺省 `Ctrl+X`:各终端(macOS Terminal、iTerm2、tmux、Windows Terminal)都原样
|
|
41630
|
+
* 送达 0x18,且没有别的绑定;`Ctrl+Enter` 不开 kitty 键盘协议时与 Enter 无法区分,`Ctrl+S` 可能被 XOFF
|
|
41631
|
+
* 流控吃掉,`Alt+Enter` 已是 followUp,`Alt+<字母>` 在 macOS 缺省不送 Meta,`Ctrl+]` 在非美式键盘难按。
|
|
41632
|
+
*/
|
|
41633
|
+
"app.message.interrupt": ["ctrl+x"],
|
|
41480
41634
|
"app.permission.cycle": ["shift+tab", "tab"],
|
|
41481
41635
|
"app.tools.expand": ["ctrl+o"],
|
|
41482
41636
|
"app.model.select": ["ctrl+l"],
|
|
@@ -44928,34 +45082,46 @@ function windowSpan(minutes) {
|
|
|
44928
45082
|
if (minutes % 60 === 0) return `${minutes / 60}h`;
|
|
44929
45083
|
return `${Math.round(minutes)}m`;
|
|
44930
45084
|
}
|
|
44931
|
-
function
|
|
44932
|
-
const m =
|
|
44933
|
-
|
|
44934
|
-
|
|
44935
|
-
|
|
44936
|
-
|
|
44937
|
-
|
|
45085
|
+
function minutesOf(w) {
|
|
45086
|
+
const m = w.windowMinutes;
|
|
45087
|
+
return m !== void 0 && Number.isFinite(m) && m > 0 ? m : void 0;
|
|
45088
|
+
}
|
|
45089
|
+
function kindOf(minutes) {
|
|
45090
|
+
if (minutes === FIVE_HOURS) return "session";
|
|
45091
|
+
if (minutes === WEEK) return "weekly";
|
|
45092
|
+
return minutes;
|
|
44938
45093
|
}
|
|
44939
|
-
function
|
|
45094
|
+
function labels(kind) {
|
|
44940
45095
|
const m = msg().interactive.statusLine.quota;
|
|
44941
|
-
|
|
44942
|
-
if (
|
|
44943
|
-
|
|
44944
|
-
return
|
|
45096
|
+
if (kind === "session") return { pct: m.session, reset: m.reset, short: m.short5h };
|
|
45097
|
+
if (kind === "weekly") return { pct: m.weekly, reset: m.weeklyReset, short: m.shortWeek };
|
|
45098
|
+
const span = windowSpan(kind);
|
|
45099
|
+
return { pct: m.window(span), reset: m.windowReset(span), short: span };
|
|
44945
45100
|
}
|
|
44946
45101
|
function percent2(theme, used, decimal) {
|
|
44947
45102
|
return theme.fg(levelColor(used / 100), decimal ? `${used.toFixed(1)}%` : `${Math.round(used)}%`);
|
|
44948
45103
|
}
|
|
44949
|
-
function
|
|
44950
|
-
|
|
44951
|
-
|
|
44952
|
-
|
|
44953
|
-
|
|
45104
|
+
function hasData(w) {
|
|
45105
|
+
return w.usedPercent !== 0 || minutesOf(w) !== void 0 || w.resetsAt !== void 0;
|
|
45106
|
+
}
|
|
45107
|
+
function shownWindows(quota) {
|
|
45108
|
+
const slots = ["primary", "secondary"].map((which) => ({ which, w: quota[which] })).filter((x) => x.w !== void 0).filter((x) => hasData(x.w));
|
|
45109
|
+
const known = slots.map((x) => kindOf(minutesOf(x.w)));
|
|
45110
|
+
const out = slots.map((x, i) => {
|
|
45111
|
+
const own = known[i];
|
|
45112
|
+
if (own !== void 0) return { kind: own, window: x.w };
|
|
45113
|
+
const guess = x.which === "primary" ? "session" : "weekly";
|
|
45114
|
+
const taken = known.some((k, j) => j !== i && k === guess);
|
|
45115
|
+
const kind = taken ? guess === "session" ? "weekly" : "session" : guess;
|
|
45116
|
+
return { kind, window: x.w };
|
|
45117
|
+
});
|
|
45118
|
+
const span = (k) => typeof k === "number" ? k : SPAN[k];
|
|
45119
|
+
return out.sort((a, b) => span(a.kind) - span(b.kind));
|
|
44954
45120
|
}
|
|
44955
45121
|
function compactQuotaItem(quota, theme) {
|
|
44956
45122
|
const dim = (text) => theme.fg("dim", text);
|
|
44957
|
-
const items =
|
|
44958
|
-
(
|
|
45123
|
+
const items = shownWindows(quota).map(
|
|
45124
|
+
({ kind, window: w }) => `${dim(labels(kind).short)} ${percent2(theme, w.usedPercent, false)}`
|
|
44959
45125
|
);
|
|
44960
45126
|
return items.length === 0 ? void 0 : items.join(" ");
|
|
44961
45127
|
}
|
|
@@ -44963,30 +45129,31 @@ function quotaParts2(quota, width2, now, theme) {
|
|
|
44963
45129
|
const dim = (text) => theme.fg("dim", text);
|
|
44964
45130
|
const narrow = width2 < QUOTA_NARROW_WIDTH;
|
|
44965
45131
|
const parts = [];
|
|
44966
|
-
|
|
45132
|
+
shownWindows(quota).forEach(({ kind, window: w }, i) => {
|
|
44967
45133
|
const first = i === 0;
|
|
44968
|
-
const group = narrow ?
|
|
44969
|
-
const
|
|
45134
|
+
const group = narrow ? `w${i}` : void 0;
|
|
45135
|
+
const label2 = labels(kind);
|
|
45136
|
+
const name = narrow ? `${label2.short} ` : label2.pct;
|
|
44970
45137
|
parts.push({
|
|
44971
45138
|
text: dim(name) + percent2(theme, w.usedPercent, !narrow),
|
|
44972
45139
|
priority: first ? void 0 : 2,
|
|
44973
|
-
zone: "
|
|
45140
|
+
zone: "right",
|
|
44974
45141
|
...group !== void 0 ? { group } : {}
|
|
44975
45142
|
});
|
|
44976
45143
|
if (w.resetsAt === void 0) return;
|
|
44977
45144
|
const left = formatRemaining(w.resetsAt - now, narrow);
|
|
44978
45145
|
parts.push({
|
|
44979
|
-
text: narrow ? theme.fg("tool", `${theme.glyphs.retry}${left}`) : dim(
|
|
45146
|
+
text: narrow ? theme.fg("tool", `${theme.glyphs.retry}${left}`) : dim(label2.reset) + theme.fg("tool", left),
|
|
44980
45147
|
priority: first ? 3 : 1,
|
|
44981
|
-
zone: "
|
|
45148
|
+
zone: "right",
|
|
44982
45149
|
// 宽格式按最宽形状占位(`23h 59m`),数值变化不让某项时有时无
|
|
44983
|
-
reserve: narrow ? 0 : visibleWidth(
|
|
45150
|
+
reserve: narrow ? 0 : visibleWidth(label2.reset) + 7,
|
|
44984
45151
|
...group !== void 0 ? { group } : {}
|
|
44985
45152
|
});
|
|
44986
45153
|
});
|
|
44987
45154
|
return parts;
|
|
44988
45155
|
}
|
|
44989
|
-
var QUOTA_NARROW_WIDTH, FIVE_HOURS, WEEK, QuotaLine;
|
|
45156
|
+
var QUOTA_NARROW_WIDTH, FIVE_HOURS, WEEK, SPAN, QuotaLine;
|
|
44990
45157
|
var init_status_quota = __esm({
|
|
44991
45158
|
"src/modes/interactive/status-quota.ts"() {
|
|
44992
45159
|
"use strict";
|
|
@@ -44996,6 +45163,7 @@ var init_status_quota = __esm({
|
|
|
44996
45163
|
QUOTA_NARROW_WIDTH = 80;
|
|
44997
45164
|
FIVE_HOURS = 300;
|
|
44998
45165
|
WEEK = 10080;
|
|
45166
|
+
SPAN = { session: FIVE_HOURS, weekly: WEEK };
|
|
44999
45167
|
QuotaLine = class {
|
|
45000
45168
|
constructor(source, theme) {
|
|
45001
45169
|
this.source = source;
|
|
@@ -45009,7 +45177,8 @@ var init_status_quota = __esm({
|
|
|
45009
45177
|
if (view === void 0) return [];
|
|
45010
45178
|
const theme = this.theme;
|
|
45011
45179
|
if (view === "pending") {
|
|
45012
|
-
|
|
45180
|
+
const text = theme.fg("dim", msg().interactive.statusLine.quota.pending);
|
|
45181
|
+
return [layoutRow([{ text, priority: void 0, zone: "right" }], width2, theme)];
|
|
45013
45182
|
}
|
|
45014
45183
|
const parts = quotaParts2(view.quota, width2, this.source.now(), theme);
|
|
45015
45184
|
if (parts.length === 0) return [];
|
|
@@ -45085,9 +45254,10 @@ function layoutRow(parts, width2, theme, style = {}) {
|
|
|
45085
45254
|
let kept = [...parts];
|
|
45086
45255
|
const zone = (z) => kept.filter((p) => p.zone === z);
|
|
45087
45256
|
const fits = () => {
|
|
45088
|
-
const
|
|
45257
|
+
const left = zone("left");
|
|
45089
45258
|
const right = zone("right");
|
|
45090
|
-
|
|
45259
|
+
const between = left.length === 0 || right.length === 0 ? 0 : sep5.length;
|
|
45260
|
+
return join66(left)[1] + between + join66(right)[1] <= width2;
|
|
45091
45261
|
};
|
|
45092
45262
|
while (!fits()) {
|
|
45093
45263
|
const droppable = kept.filter((p) => p.priority !== void 0);
|
|
@@ -45098,7 +45268,7 @@ function layoutRow(parts, width2, theme, style = {}) {
|
|
|
45098
45268
|
const l = join66(zone("left"))[0];
|
|
45099
45269
|
const r = join66(zone("right"))[0];
|
|
45100
45270
|
const gap = width2 - visibleWidth(l) - visibleWidth(r);
|
|
45101
|
-
const line2 = r === "" ? l : gap >= MIN_GAP ? l + " ".repeat(gap) + r : l + dim(sep5) + r;
|
|
45271
|
+
const line2 = r === "" ? l : l === "" ? " ".repeat(Math.max(0, gap)) + r : gap >= MIN_GAP ? l + " ".repeat(gap) + r : l + dim(sep5) + r;
|
|
45102
45272
|
return truncateToWidth(line2, width2);
|
|
45103
45273
|
}
|
|
45104
45274
|
function abbreviateModel(ref, width2) {
|
|
@@ -45230,7 +45400,7 @@ var init_status_bar = __esm({
|
|
|
45230
45400
|
}
|
|
45231
45401
|
const model = state.model === void 0 ? "?" : abbreviateModel(formatModelRef(state.model), width2);
|
|
45232
45402
|
const p = full ? FULL : COMPACT;
|
|
45233
|
-
const fallback = this.source.fallback?.();
|
|
45403
|
+
const fallback = full ? void 0 : this.source.fallback?.();
|
|
45234
45404
|
const modelText = fallback === void 0 ? theme.fg("accent", model) : theme.fg("accent", abbreviateModel(fallback.from, width2)) + dim(g.ascii ? " -> " : " → ") + theme.fg("warning", abbreviateModel(fallback.to, width2));
|
|
45235
45405
|
right(modelText, p.model, full ? { group: "model" } : {});
|
|
45236
45406
|
if (state.thinkingLevel !== "off") {
|
|
@@ -49024,6 +49194,13 @@ async function runSlashCommand(line2, ctx) {
|
|
|
49024
49194
|
return planCommand(session, args, ctx);
|
|
49025
49195
|
case "tasks":
|
|
49026
49196
|
return { kind: "handled", message: await tasksCommand(session, args) };
|
|
49197
|
+
case "interrupt": {
|
|
49198
|
+
if (args === "") throw new AmaError("invalid_arguments", msg().report.command.interruptUsage);
|
|
49199
|
+
const { isStreaming, isCompacting } = session.state;
|
|
49200
|
+
if (!isStreaming && !isCompacting) return { kind: "prompt", text: args };
|
|
49201
|
+
void session.prompt(args, { interrupt: true }).catch(() => void 0);
|
|
49202
|
+
return { kind: "handled", message: msg().report.command.interruptSent(args) };
|
|
49203
|
+
}
|
|
49027
49204
|
case "agents":
|
|
49028
49205
|
return { kind: "handled", message: describeAgents(session.state.sessionId) };
|
|
49029
49206
|
case "paste": {
|
|
@@ -49079,6 +49256,7 @@ var init_commands_core = __esm({
|
|
|
49079
49256
|
command("tasks", "tasks", "[id] | stop <id> | bg [id]"),
|
|
49080
49257
|
command("agents", "agents"),
|
|
49081
49258
|
command("paste", "paste"),
|
|
49259
|
+
command("interrupt", "interrupt", { key: "interruptArgs" }),
|
|
49082
49260
|
command("exit", "exit"),
|
|
49083
49261
|
// [W6-C0] 第六波(W6-S / W6-T1 / W6-M 实现)
|
|
49084
49262
|
command("config", "config", "[key=value]"),
|
|
@@ -49129,6 +49307,11 @@ function applyPlanAttendance(ctx) {
|
|
|
49129
49307
|
ctx.capabilities.has("plans") ? "client" : "unattended"
|
|
49130
49308
|
);
|
|
49131
49309
|
}
|
|
49310
|
+
function interruptFlag(value) {
|
|
49311
|
+
if (value !== void 0 && typeof value !== "boolean")
|
|
49312
|
+
throw new AmaError("invalid_arguments", "interrupt must be a boolean");
|
|
49313
|
+
return value === true;
|
|
49314
|
+
}
|
|
49132
49315
|
async function startRun(ctx, run7) {
|
|
49133
49316
|
const session = ctx.session();
|
|
49134
49317
|
let settled = false;
|
|
@@ -49251,10 +49434,17 @@ var init_commands = __esm({
|
|
|
49251
49434
|
ctx,
|
|
49252
49435
|
() => ctx.session().prompt(p.message, {
|
|
49253
49436
|
...p.images !== void 0 ? { images: p.images } : {},
|
|
49254
|
-
...p.streamingBehavior !== void 0 ? { streamingBehavior: p.streamingBehavior } : {}
|
|
49437
|
+
...p.streamingBehavior !== void 0 ? { streamingBehavior: p.streamingBehavior } : {},
|
|
49438
|
+
...interruptFlag(p.interrupt) ? { interrupt: true } : {}
|
|
49255
49439
|
})
|
|
49256
49440
|
),
|
|
49257
|
-
steer: (p, ctx) => startRun(
|
|
49441
|
+
steer: (p, ctx) => startRun(
|
|
49442
|
+
ctx,
|
|
49443
|
+
() => interruptFlag(p.interrupt) ? ctx.session().prompt(p.message, {
|
|
49444
|
+
interrupt: true,
|
|
49445
|
+
...p.images !== void 0 ? { images: p.images } : {}
|
|
49446
|
+
}) : ctx.session().steer(p.message)
|
|
49447
|
+
),
|
|
49258
49448
|
follow_up: (p, ctx) => startRun(ctx, () => ctx.session().followUp(p.message)),
|
|
49259
49449
|
abort: async (_p, ctx) => {
|
|
49260
49450
|
await ctx.session().abort();
|
|
@@ -52879,13 +53069,13 @@ ${bypassRiskLines().map((l) => ` ${l}
|
|
|
52879
53069
|
void ed.ask(`
|
|
52880
53070
|
${preview.join("")}${question}`, "n").then((answer) => {
|
|
52881
53071
|
resolve39(answer === "y" ? "allow" : answer === "a" ? "allow_session" : "deny");
|
|
52882
|
-
if (
|
|
53072
|
+
if (running === 0) ed.render();
|
|
52883
53073
|
});
|
|
52884
53074
|
})
|
|
52885
53075
|
});
|
|
52886
53076
|
runtime.notifier.set((message, level) => err(`ama: [${level}] ${message}
|
|
52887
53077
|
`));
|
|
52888
|
-
let
|
|
53078
|
+
let running = 0;
|
|
52889
53079
|
let lastInterrupt = 0;
|
|
52890
53080
|
return new Promise((resolve39) => {
|
|
52891
53081
|
let finished = false;
|
|
@@ -52905,11 +53095,23 @@ ${preview.join("")}${question}`, "n").then((answer) => {
|
|
|
52905
53095
|
});
|
|
52906
53096
|
};
|
|
52907
53097
|
const run7 = (text) => {
|
|
52908
|
-
|
|
53098
|
+
running++;
|
|
52909
53099
|
void handle(text).then((outcome) => {
|
|
52910
|
-
|
|
53100
|
+
running--;
|
|
52911
53101
|
if (outcome === "exit") finish2(ExitCode.Ok);
|
|
52912
|
-
else ed.render();
|
|
53102
|
+
else if (running === 0) ed.render();
|
|
53103
|
+
});
|
|
53104
|
+
};
|
|
53105
|
+
const interruptWith = (text) => {
|
|
53106
|
+
if (text === "") return err(`ama: ${msg().report.command.interruptUsage}
|
|
53107
|
+
`);
|
|
53108
|
+
out(`${msg().report.command.interruptSent(text)}
|
|
53109
|
+
`);
|
|
53110
|
+
running++;
|
|
53111
|
+
void session.prompt(text, { interrupt: true }).catch((error2) => err(`ama: ${errorText3(error2)}
|
|
53112
|
+
`)).finally(() => {
|
|
53113
|
+
printer.endLine();
|
|
53114
|
+
if (--running === 0) ed.render();
|
|
52913
53115
|
});
|
|
52914
53116
|
};
|
|
52915
53117
|
let flushTimer;
|
|
@@ -52917,7 +53119,7 @@ ${preview.join("")}${question}`, "n").then((answer) => {
|
|
|
52917
53119
|
for (const action of actions) {
|
|
52918
53120
|
if (action.kind === "eof") return finish2(ExitCode.Ok);
|
|
52919
53121
|
if (action.kind === "interrupt") {
|
|
52920
|
-
if (
|
|
53122
|
+
if (running > 0) {
|
|
52921
53123
|
void session.abort();
|
|
52922
53124
|
err(`${msg().interactive.line.interrupted}
|
|
52923
53125
|
`);
|
|
@@ -52932,7 +53134,12 @@ ${msg().interactive.line.ctrlCAgain}
|
|
|
52932
53134
|
}
|
|
52933
53135
|
continue;
|
|
52934
53136
|
}
|
|
52935
|
-
if (
|
|
53137
|
+
if (running > 0) {
|
|
53138
|
+
const forced2 = /^\/interrupt(?:\s+([\s\S]*))?$/.exec(action.text.trim());
|
|
53139
|
+
if (forced2 !== null) {
|
|
53140
|
+
interruptWith((forced2[1] ?? "").trim());
|
|
53141
|
+
continue;
|
|
53142
|
+
}
|
|
52936
53143
|
if (/^\/tasks\s+bg(\s+\S+)?\s*$/.test(action.text.trim())) {
|
|
52937
53144
|
void handle(action.text.trim());
|
|
52938
53145
|
continue;
|
|
@@ -53421,7 +53628,7 @@ var init_agent_view = __esm({
|
|
|
53421
53628
|
maxVisibleLines: 4,
|
|
53422
53629
|
placeholder: msg().agents.view.placeholder(taskId),
|
|
53423
53630
|
requestRender: () => deps.render(),
|
|
53424
|
-
onSubmit: (text) => void this.submit(text)
|
|
53631
|
+
onSubmit: (text) => void this.submit(text, this.enterInterrupts())
|
|
53425
53632
|
});
|
|
53426
53633
|
this.attach();
|
|
53427
53634
|
}
|
|
@@ -53519,7 +53726,10 @@ var init_agent_view = __esm({
|
|
|
53519
53726
|
this.attach();
|
|
53520
53727
|
this.deps.onSwitch?.(next);
|
|
53521
53728
|
}
|
|
53522
|
-
|
|
53729
|
+
enterInterrupts() {
|
|
53730
|
+
return this.deps.enterMode?.() === "interrupt";
|
|
53731
|
+
}
|
|
53732
|
+
async submit(text, interrupt = false) {
|
|
53523
53733
|
const m = msg().agents.view;
|
|
53524
53734
|
const trimmed = text.trim();
|
|
53525
53735
|
if (trimmed === "") return;
|
|
@@ -53545,7 +53755,7 @@ var init_agent_view = __esm({
|
|
|
53545
53755
|
const registry2 = this.deps.registry();
|
|
53546
53756
|
try {
|
|
53547
53757
|
if (registry2 === void 0) throw new Error(m.unknown(taskId));
|
|
53548
|
-
const reply = await registry2.message(taskId, text);
|
|
53758
|
+
const reply = await registry2.message(taskId, text, interrupt);
|
|
53549
53759
|
this.flash = m[reply](taskId);
|
|
53550
53760
|
} catch (error2) {
|
|
53551
53761
|
this.flash = m.sendFailed(error2 instanceof Error ? error2.message : String(error2));
|
|
@@ -53565,6 +53775,11 @@ var init_agent_view = __esm({
|
|
|
53565
53775
|
return;
|
|
53566
53776
|
}
|
|
53567
53777
|
}
|
|
53778
|
+
if (keys.matches(data2, "app.message.interrupt") && !this.editor.isCompletionOpen) {
|
|
53779
|
+
const text = this.editor.takeSubmission();
|
|
53780
|
+
if (text !== null) void this.submit(text, !this.enterInterrupts());
|
|
53781
|
+
return;
|
|
53782
|
+
}
|
|
53568
53783
|
if (keys.matches(data2, "tui.select.cancel") && !this.editor.isCompletionOpen) {
|
|
53569
53784
|
if (!empty) this.editor.clear();
|
|
53570
53785
|
else this.deps.close();
|
|
@@ -54691,6 +54906,7 @@ var init_agent_ui = __esm({
|
|
|
54691
54906
|
close: () => this.closeView(),
|
|
54692
54907
|
stop: (id) => stopTask(this.deps.session().state.sessionId, id),
|
|
54693
54908
|
background: (id) => this.deps.session().backgroundTask(id, "user"),
|
|
54909
|
+
enterMode: () => this.deps.area?.ui().enterWhileRunning === "interrupt" ? "interrupt" : "queue",
|
|
54694
54910
|
messages: {
|
|
54695
54911
|
...ui.showThinking !== void 0 ? { showThinking: ui.showThinking } : {},
|
|
54696
54912
|
...ui.markdown !== void 0 ? { markdown: ui.markdown } : {},
|
|
@@ -55624,16 +55840,18 @@ var init_status_line = __esm({
|
|
|
55624
55840
|
init_status_bar();
|
|
55625
55841
|
RESERVE = { tps: 14, amount: 16, avg: 7, ttft: 9 };
|
|
55626
55842
|
PRIORITY = {
|
|
55627
|
-
|
|
55628
|
-
|
|
55629
|
-
|
|
55843
|
+
codemode: 1,
|
|
55844
|
+
sandbox: 2,
|
|
55845
|
+
fallback: 3,
|
|
55630
55846
|
preset: 4,
|
|
55631
|
-
|
|
55632
|
-
|
|
55633
|
-
|
|
55634
|
-
|
|
55635
|
-
|
|
55636
|
-
|
|
55847
|
+
queue: 5,
|
|
55848
|
+
host: 6,
|
|
55849
|
+
ttft: 7,
|
|
55850
|
+
avg: 8,
|
|
55851
|
+
rebill: 9,
|
|
55852
|
+
cache: 10,
|
|
55853
|
+
tokens: 11,
|
|
55854
|
+
amount: 12
|
|
55637
55855
|
};
|
|
55638
55856
|
COLLAPSE_HINT = "[-]";
|
|
55639
55857
|
RATE_STYLE = { groups: { stats: { glue: " · ", open: "(", close: ")" } } };
|
|
@@ -55646,7 +55864,7 @@ var init_status_line = __esm({
|
|
|
55646
55864
|
bar;
|
|
55647
55865
|
source;
|
|
55648
55866
|
theme;
|
|
55649
|
-
parts() {
|
|
55867
|
+
parts(width2) {
|
|
55650
55868
|
const theme = this.theme;
|
|
55651
55869
|
const dim = (text) => theme.fg("dim", text);
|
|
55652
55870
|
const stats = this.bar.current();
|
|
@@ -55654,9 +55872,9 @@ var init_status_line = __esm({
|
|
|
55654
55872
|
const live2 = telemetry?.live;
|
|
55655
55873
|
const last = telemetry?.last;
|
|
55656
55874
|
const parts = [];
|
|
55657
|
-
const
|
|
55658
|
-
const
|
|
55659
|
-
if (text !== void 0) parts.push({ text, priority, zone
|
|
55875
|
+
const metric = (text, priority, reserve, extra = {}) => void parts.push({ text, priority, zone: "right", reserve, ...extra });
|
|
55876
|
+
const add3 = (zone, text, priority) => {
|
|
55877
|
+
if (text !== void 0) parts.push({ text, priority, zone });
|
|
55660
55878
|
};
|
|
55661
55879
|
const blue = (text) => theme.fg("accent", text);
|
|
55662
55880
|
const purple = (text) => theme.fg("tool", text);
|
|
@@ -55673,20 +55891,25 @@ var init_status_line = __esm({
|
|
|
55673
55891
|
}
|
|
55674
55892
|
}
|
|
55675
55893
|
const label2 = live2 !== void 0 ? theme.fg("accent", "tps:") : dim("tps:");
|
|
55676
|
-
|
|
55894
|
+
metric(
|
|
55677
55895
|
`${label2} ${tps === void 0 ? dim("—") : `${purple(formatRate(tps))}${dim(" tok/s")}`}`,
|
|
55678
55896
|
void 0,
|
|
55679
55897
|
RESERVE.tps
|
|
55680
55898
|
);
|
|
55681
55899
|
if (amount !== void 0) {
|
|
55682
|
-
|
|
55900
|
+
metric(amount, PRIORITY.amount, RESERVE.amount, { lead: ` ${theme.glyphs.dot} ` });
|
|
55683
55901
|
}
|
|
55684
55902
|
const stat16 = { group: "stats", lead: " " };
|
|
55685
55903
|
if (telemetry?.avgTps !== void 0) {
|
|
55686
|
-
|
|
55904
|
+
metric(
|
|
55905
|
+
`${dim("avg ")}${blue(formatRate(telemetry.avgTps))}`,
|
|
55906
|
+
PRIORITY.avg,
|
|
55907
|
+
RESERVE.avg,
|
|
55908
|
+
stat16
|
|
55909
|
+
);
|
|
55687
55910
|
}
|
|
55688
55911
|
if (last?.ttftMs !== void 0) {
|
|
55689
|
-
|
|
55912
|
+
metric(
|
|
55690
55913
|
`${dim("ttft ")}${purple(formatSeconds2(last.ttftMs))}`,
|
|
55691
55914
|
PRIORITY.ttft,
|
|
55692
55915
|
RESERVE.ttft,
|
|
@@ -55694,20 +55917,29 @@ var init_status_line = __esm({
|
|
|
55694
55917
|
);
|
|
55695
55918
|
}
|
|
55696
55919
|
const usage = usageItems(stats, this.bar.queued(), this.source, theme);
|
|
55697
|
-
right
|
|
55698
|
-
right
|
|
55699
|
-
right
|
|
55700
|
-
right(
|
|
55701
|
-
|
|
55702
|
-
|
|
55703
|
-
|
|
55704
|
-
|
|
55705
|
-
|
|
55920
|
+
add3("right", usage.tokens, PRIORITY.tokens);
|
|
55921
|
+
add3("right", usage.cache, PRIORITY.cache);
|
|
55922
|
+
add3("right", usage.rebill, PRIORITY.rebill);
|
|
55923
|
+
add3("right", dim(COLLAPSE_HINT), void 0);
|
|
55924
|
+
add3("left", usage.codemode, PRIORITY.codemode);
|
|
55925
|
+
add3("left", usage.sandbox, PRIORITY.sandbox);
|
|
55926
|
+
add3("left", usage.preset, PRIORITY.preset);
|
|
55927
|
+
const fallback = this.source.fallback?.();
|
|
55928
|
+
if (fallback !== void 0) {
|
|
55929
|
+
const arrow = theme.glyphs.ascii ? "-> " : "→ ";
|
|
55930
|
+
add3(
|
|
55931
|
+
"left",
|
|
55932
|
+
dim(arrow) + theme.fg("warning", abbreviateModel(fallback.to, width2)),
|
|
55933
|
+
PRIORITY.fallback
|
|
55934
|
+
);
|
|
55935
|
+
}
|
|
55936
|
+
add3("left", usage.queue, PRIORITY.queue);
|
|
55937
|
+
add3("left", usage.host, PRIORITY.host);
|
|
55706
55938
|
return parts;
|
|
55707
55939
|
}
|
|
55708
55940
|
render(width2) {
|
|
55709
55941
|
if (this.bar.layout() !== "full") return [];
|
|
55710
|
-
return [truncateToWidth(layoutRow(this.parts(), width2, this.theme, RATE_STYLE), width2)];
|
|
55942
|
+
return [truncateToWidth(layoutRow(this.parts(width2), width2, this.theme, RATE_STYLE), width2)];
|
|
55711
55943
|
}
|
|
55712
55944
|
invalidate() {
|
|
55713
55945
|
}
|
|
@@ -56008,6 +56240,27 @@ ${current3}`);
|
|
|
56008
56240
|
if (typeof answer === "boolean") settle(answer);
|
|
56009
56241
|
else void answer.then(settle);
|
|
56010
56242
|
};
|
|
56243
|
+
const sendKeys = (is) => {
|
|
56244
|
+
if (deps.interruptSend === void 0 || editor.isCompletionOpen) return false;
|
|
56245
|
+
const viaKey = is("app.message.interrupt");
|
|
56246
|
+
if (!deps.busy()) {
|
|
56247
|
+
if (!viaKey || editor.isEmpty()) return false;
|
|
56248
|
+
const text = editor.takeSubmission();
|
|
56249
|
+
if (text !== null) deps.submit(text, "enter");
|
|
56250
|
+
return true;
|
|
56251
|
+
}
|
|
56252
|
+
const interruptMode = deps.enterWhileRunning?.() === "interrupt";
|
|
56253
|
+
if (!viaKey && !(interruptMode && is("tui.editor.submit"))) return false;
|
|
56254
|
+
const command3 = editor.getExpandedText().trimStart().startsWith("/");
|
|
56255
|
+
if (command3 || viaKey === interruptMode) {
|
|
56256
|
+
if (!viaKey) return false;
|
|
56257
|
+
const text = editor.takeSubmission();
|
|
56258
|
+
if (text !== null) deps.submit(text, "enter");
|
|
56259
|
+
return true;
|
|
56260
|
+
}
|
|
56261
|
+
deps.interruptSend(editor.takeSubmission() ?? "");
|
|
56262
|
+
return true;
|
|
56263
|
+
};
|
|
56011
56264
|
const atLastLine = () => editor.cursor.line >= editor.getText().split("\n").length - 1;
|
|
56012
56265
|
const focusAgents = (agents, data2) => {
|
|
56013
56266
|
if (editor.isCompletionOpen || editor.isBrowsingHistory) return false;
|
|
@@ -56064,6 +56317,7 @@ ${current3}`);
|
|
|
56064
56317
|
return true;
|
|
56065
56318
|
}
|
|
56066
56319
|
ctrlCArmedAt = Number.NEGATIVE_INFINITY;
|
|
56320
|
+
if (sendKeys(is)) return true;
|
|
56067
56321
|
if (is("app.interrupt") && !editor.isCompletionOpen && deps.busy()) {
|
|
56068
56322
|
esc.reset();
|
|
56069
56323
|
interrupt();
|
|
@@ -56138,6 +56392,34 @@ var init_key_dispatch = __esm({
|
|
|
56138
56392
|
}
|
|
56139
56393
|
});
|
|
56140
56394
|
|
|
56395
|
+
// src/modes/interactive/interrupt-send.ts
|
|
56396
|
+
function interruptSender(deps) {
|
|
56397
|
+
return (text) => {
|
|
56398
|
+
const images = deps.takeImages();
|
|
56399
|
+
deps.showHint(msg().interactive.keys.interruptSent);
|
|
56400
|
+
const options = images.length > 0 ? { interrupt: true, images } : { interrupt: true };
|
|
56401
|
+
void deps.session().prompt(text, options).catch((error2) => {
|
|
56402
|
+
if (isAmaError(error2) && error2.code === "invalid_arguments")
|
|
56403
|
+
deps.showHint(msg().interactive.keys.nothingToSend);
|
|
56404
|
+
});
|
|
56405
|
+
};
|
|
56406
|
+
}
|
|
56407
|
+
function enterModeOf(runtime) {
|
|
56408
|
+
return runtime.config.ui?.enterWhileRunning === "interrupt" ? "interrupt" : "queue";
|
|
56409
|
+
}
|
|
56410
|
+
function interruptKeys(keys, mode) {
|
|
56411
|
+
const key = keyLabel(keys, "app.message.interrupt");
|
|
56412
|
+
return { key, now: () => mode() === "interrupt" ? "Enter" : key };
|
|
56413
|
+
}
|
|
56414
|
+
var init_interrupt_send = __esm({
|
|
56415
|
+
"src/modes/interactive/interrupt-send.ts"() {
|
|
56416
|
+
"use strict";
|
|
56417
|
+
init_errors();
|
|
56418
|
+
init_i18n();
|
|
56419
|
+
init_task_background();
|
|
56420
|
+
}
|
|
56421
|
+
});
|
|
56422
|
+
|
|
56141
56423
|
// src/modes/interactive/model-picker.ts
|
|
56142
56424
|
async function openModelPicker(host, options) {
|
|
56143
56425
|
const catalog = await loadModelCatalog(options.providers);
|
|
@@ -57500,10 +57782,7 @@ var init_run_indicator = __esm({
|
|
|
57500
57782
|
RunIndicator = class {
|
|
57501
57783
|
constructor(deps) {
|
|
57502
57784
|
this.deps = deps;
|
|
57503
|
-
deps.loader.onFrame(() =>
|
|
57504
|
-
if (this.busy && !this.approval && this.optionalHints().join("\n") !== this.hintKey)
|
|
57505
|
-
this.applyVerb();
|
|
57506
|
-
});
|
|
57785
|
+
deps.loader.onFrame(() => this.refreshHints());
|
|
57507
57786
|
}
|
|
57508
57787
|
deps;
|
|
57509
57788
|
running = false;
|
|
@@ -57517,12 +57796,24 @@ var init_run_indicator = __esm({
|
|
|
57517
57796
|
background = () => false;
|
|
57518
57797
|
/** [W7-C] 有停靠在 Agent 栏的审批。 */
|
|
57519
57798
|
docked = () => false;
|
|
57799
|
+
/** 输入框有字(显示 Enter / 专用键的提示)。 */
|
|
57800
|
+
draft = () => false;
|
|
57801
|
+
/** 运行中 Enter 的语义。 */
|
|
57802
|
+
enterMode = () => "queue";
|
|
57520
57803
|
hintKey = "";
|
|
57804
|
+
/** 可丢弃提示变了才换动词(每帧、输入框内容变化时调)。 */
|
|
57805
|
+
refreshHints() {
|
|
57806
|
+
if (this.busy && !this.approval && this.optionalHints().join("\n") !== this.hintKey)
|
|
57807
|
+
this.applyVerb();
|
|
57808
|
+
}
|
|
57521
57809
|
/** 可丢弃的按键提示(按丢弃的逆序排列)。 */
|
|
57522
57810
|
optionalHints() {
|
|
57523
57811
|
const down = this.deps.theme.glyphs.arrowDown;
|
|
57524
57812
|
const key = this.deps.backgroundKey;
|
|
57525
57813
|
const out = [];
|
|
57814
|
+
const send2 = this.deps.interruptKey;
|
|
57815
|
+
if (send2 !== void 0 && this.draft())
|
|
57816
|
+
out.push(msg().interactive.view.run.sendHint(this.enterMode(), send2));
|
|
57526
57817
|
if (key !== void 0 && this.background()) out.push(msg().agents.background.runHint(key));
|
|
57527
57818
|
if (this.docked()) out.push(msg().agents.approval.runHint(down));
|
|
57528
57819
|
else if (this.agents()) out.push(msg().agents.bar.runHint(down));
|
|
@@ -57643,11 +57934,16 @@ var init_run_indicator = __esm({
|
|
|
57643
57934
|
}
|
|
57644
57935
|
};
|
|
57645
57936
|
QueueView = class extends Text {
|
|
57646
|
-
|
|
57937
|
+
/**
|
|
57938
|
+
* @param nowKey 立即送出排队插话的键(专用键;interrupt 模式下是 Enter);undefined 不提示。
|
|
57939
|
+
*/
|
|
57940
|
+
constructor(theme, nowKey = () => void 0) {
|
|
57647
57941
|
super("");
|
|
57648
57942
|
this.theme = theme;
|
|
57943
|
+
this.nowKey = nowKey;
|
|
57649
57944
|
}
|
|
57650
57945
|
theme;
|
|
57946
|
+
nowKey;
|
|
57651
57947
|
setQueue(steering, followUp) {
|
|
57652
57948
|
const t = this.theme;
|
|
57653
57949
|
const row3 = (origin, text) => ` ${t.fg("dim", `${t.glyphs.queued} ${originLabel(origin)}`)} ${t.fg("muted", oneLine8(text))}`;
|
|
@@ -57665,7 +57961,10 @@ var init_run_indicator = __esm({
|
|
|
57665
57961
|
);
|
|
57666
57962
|
}
|
|
57667
57963
|
if (rows.length > 0) {
|
|
57668
|
-
|
|
57964
|
+
const run7 = msg().interactive.view.run;
|
|
57965
|
+
const now = steering.length > 0 ? this.nowKey() : void 0;
|
|
57966
|
+
const hint = now === void 0 ? run7.queueHint(t.glyphs.arrowUp) : run7.queueHintNow(t.glyphs.arrowUp, now);
|
|
57967
|
+
shown2.push(" " + t.fg("dim", hint));
|
|
57669
57968
|
}
|
|
57670
57969
|
this.setText(shown2.join("\n"));
|
|
57671
57970
|
}
|
|
@@ -57830,7 +58129,9 @@ function runInteractiveMode(runtime, context, options = {}) {
|
|
|
57830
58129
|
spinner: () => loader.frame,
|
|
57831
58130
|
subagent: (toolCallId2) => subagents.forToolCall(toolCallId2)
|
|
57832
58131
|
});
|
|
57833
|
-
const
|
|
58132
|
+
const enterMode = () => enterModeOf(runtime);
|
|
58133
|
+
const sendKeys = interruptKeys(keys, enterMode);
|
|
58134
|
+
const queueView = new QueueView(theme, sendKeys.now);
|
|
57834
58135
|
const loaderSlot = new Container();
|
|
57835
58136
|
const loader = new Loader(() => tui.requestRender(), {
|
|
57836
58137
|
theme,
|
|
@@ -57867,7 +58168,8 @@ function runInteractiveMode(runtime, context, options = {}) {
|
|
|
57867
58168
|
autocomplete: completion,
|
|
57868
58169
|
requestRender: () => tui.requestRender(),
|
|
57869
58170
|
...historyFile !== void 0 ? { historyFile } : {},
|
|
57870
|
-
onSubmit: (text) => submit(text, "enter")
|
|
58171
|
+
onSubmit: (text) => submit(text, "enter"),
|
|
58172
|
+
onChange: () => indicator.refreshHints()
|
|
57871
58173
|
});
|
|
57872
58174
|
tui.addChild(view);
|
|
57873
58175
|
tui.addChild(new Spacer());
|
|
@@ -57902,8 +58204,10 @@ function runInteractiveMode(runtime, context, options = {}) {
|
|
|
57902
58204
|
const backgroundKey = keyLabel(keys, "app.tasks.background");
|
|
57903
58205
|
const indicator = new RunIndicator({
|
|
57904
58206
|
...{ theme, loader, slot: loaderSlot, tools, render },
|
|
57905
|
-
...backgroundKey !== void 0 ? { backgroundKey } : {}
|
|
58207
|
+
...backgroundKey !== void 0 ? { backgroundKey } : {},
|
|
58208
|
+
...sendKeys.key !== void 0 ? { interruptKey: sendKeys.key } : {}
|
|
57906
58209
|
});
|
|
58210
|
+
Object.assign(indicator, { draft: () => !editor.isEmpty(), enterMode });
|
|
57907
58211
|
const setQueue = (steering, followUp) => {
|
|
57908
58212
|
status.setQueue(steering.length, followUp.length);
|
|
57909
58213
|
queueView.setQueue(steering, followUp);
|
|
@@ -58095,6 +58399,12 @@ function runInteractiveMode(runtime, context, options = {}) {
|
|
|
58095
58399
|
onPasteImage: () => void agentUi.paste(),
|
|
58096
58400
|
confirmMode,
|
|
58097
58401
|
submit: (text, via) => submit(text, via),
|
|
58402
|
+
enterWhileRunning: enterMode,
|
|
58403
|
+
interruptSend: interruptSender({
|
|
58404
|
+
session: () => session,
|
|
58405
|
+
takeImages: () => draftImages.splice(0),
|
|
58406
|
+
showHint
|
|
58407
|
+
}),
|
|
58098
58408
|
runCommand: (line2) => void runCommand2(line2),
|
|
58099
58409
|
exit: (code) => exit(code),
|
|
58100
58410
|
onInterrupted: (empty) => void rewind.afterInterrupt(empty),
|
|
@@ -58225,6 +58535,7 @@ var init_interactive_mode = __esm({
|
|
|
58225
58535
|
init_confirm_dialog();
|
|
58226
58536
|
init_config_ui();
|
|
58227
58537
|
init_key_dispatch();
|
|
58538
|
+
init_interrupt_send();
|
|
58228
58539
|
init_message_view();
|
|
58229
58540
|
init_pickers();
|
|
58230
58541
|
init_model_picker();
|
|
@@ -65078,19 +65389,19 @@ function redactedLookup(lookup) {
|
|
|
65078
65389
|
}
|
|
65079
65390
|
function axisPoints(trace) {
|
|
65080
65391
|
const t0 = trace.startedAt;
|
|
65081
|
-
const
|
|
65392
|
+
const windows = [];
|
|
65082
65393
|
for (const turn of trace.turns) {
|
|
65083
65394
|
const span = turnSpan(turn);
|
|
65084
|
-
if (span !== void 0)
|
|
65395
|
+
if (span !== void 0) windows.push([span.start - t0, span.end - t0]);
|
|
65085
65396
|
}
|
|
65086
65397
|
for (const aux of trace.aux)
|
|
65087
65398
|
if (aux.startedAt !== void 0)
|
|
65088
|
-
|
|
65089
|
-
|
|
65399
|
+
windows.push([aux.startedAt - t0, (aux.endedAt ?? aux.startedAt) - t0]);
|
|
65400
|
+
windows.sort((a, b) => a[0] - b[0] || a[1] - b[1]);
|
|
65090
65401
|
const points = [[0, 0]];
|
|
65091
65402
|
let raw = 0;
|
|
65092
65403
|
let mapped = 0;
|
|
65093
|
-
for (const [start, end] of
|
|
65404
|
+
for (const [start, end] of windows) {
|
|
65094
65405
|
if (end <= raw) continue;
|
|
65095
65406
|
const from = Math.max(start, raw);
|
|
65096
65407
|
if (from > raw) {
|