@armadra/agent 0.6.3 → 0.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/CHANGELOG.zh-CN.md +15 -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 +391 -100
- 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/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/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.4" : 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;
|
|
@@ -32742,7 +32839,7 @@ function failed3(text, sessionId, runner) {
|
|
|
32742
32839
|
...sessionId !== "" ? { sessionRef: { runner, sessionId } } : {}
|
|
32743
32840
|
};
|
|
32744
32841
|
}
|
|
32745
|
-
var RUN_TIMEOUT_MS, IDLE_CLOSE_MS, ProcessRunner, ProcessHandle;
|
|
32842
|
+
var RUN_TIMEOUT_MS, IDLE_CLOSE_MS, ProcessRunner, TURN_INTERRUPT, ProcessHandle;
|
|
32746
32843
|
var init_runner = __esm({
|
|
32747
32844
|
"src/drivers/runner.ts"() {
|
|
32748
32845
|
"use strict";
|
|
@@ -32828,6 +32925,12 @@ var init_runner = __esm({
|
|
|
32828
32925
|
return this.deps;
|
|
32829
32926
|
}
|
|
32830
32927
|
};
|
|
32928
|
+
TURN_INTERRUPT = /* @__PURE__ */ new Set([
|
|
32929
|
+
"acp",
|
|
32930
|
+
"acp-adapter",
|
|
32931
|
+
"claude-stream",
|
|
32932
|
+
"codex-app-server"
|
|
32933
|
+
]);
|
|
32831
32934
|
ProcessHandle = class {
|
|
32832
32935
|
constructor(runner, chosen, request, deps) {
|
|
32833
32936
|
this.runner = runner;
|
|
@@ -32899,8 +33002,22 @@ var init_runner = __esm({
|
|
|
32899
33002
|
}
|
|
32900
33003
|
this.chain = this.chain.then(() => this.runTurn(text));
|
|
32901
33004
|
}
|
|
32902
|
-
|
|
32903
|
-
|
|
33005
|
+
/** 跟到链尾:回合进行中被 `interrupt` 接上的下一回合也算在这次运行里。 */
|
|
33006
|
+
async wait() {
|
|
33007
|
+
for (; ; ) {
|
|
33008
|
+
const chain = this.chain;
|
|
33009
|
+
const result = await chain;
|
|
33010
|
+
if (chain === this.chain) return result;
|
|
33011
|
+
}
|
|
33012
|
+
}
|
|
33013
|
+
/** 子 Agent 视图的「打断并发送」:中断当前回合,紧接着以 `text` 开下一回合。 */
|
|
33014
|
+
async interrupt(text) {
|
|
33015
|
+
const session = this.session;
|
|
33016
|
+
if (this.stopped || !this.busy || session === void 0) return false;
|
|
33017
|
+
if (!TURN_INTERRUPT.has(this.chosen.driver.kind)) return false;
|
|
33018
|
+
this.chain = this.chain.then(() => this.runTurn(text));
|
|
33019
|
+
await session.cancel();
|
|
33020
|
+
return true;
|
|
32904
33021
|
}
|
|
32905
33022
|
async stop() {
|
|
32906
33023
|
if (this.stopped) return;
|
|
@@ -34957,10 +35074,11 @@ function window(used, minutes, resetSeconds) {
|
|
|
34957
35074
|
if (usedPercent === void 0) return void 0;
|
|
34958
35075
|
const out = { usedPercent: Math.max(0, Math.min(100, usedPercent)) };
|
|
34959
35076
|
const m = num(minutes);
|
|
34960
|
-
if (m !== void 0) out.windowMinutes = m;
|
|
35077
|
+
if (m !== void 0 && m > 0) out.windowMinutes = m;
|
|
34961
35078
|
const reset = num(resetSeconds);
|
|
34962
35079
|
if (reset !== void 0 && reset > 0) out.resetsAt = reset * 1e3;
|
|
34963
|
-
|
|
35080
|
+
const empty = out.usedPercent === 0 && out.windowMinutes === void 0 && out.resetsAt === void 0;
|
|
35081
|
+
return empty ? void 0 : out;
|
|
34964
35082
|
}
|
|
34965
35083
|
function snapshot(primary, secondary, plan2) {
|
|
34966
35084
|
const out = {};
|
|
@@ -35306,7 +35424,14 @@ var init_key_docs = __esm({
|
|
|
35306
35424
|
codemode: { inlineBudget: DEFAULT_INLINE_BUDGET, requireStrict: false },
|
|
35307
35425
|
cache: { ...DEFAULT_CACHE_CONFIG },
|
|
35308
35426
|
request: { idleTimeoutMs: DEFAULT_IDLE_TIMEOUT_MS },
|
|
35309
|
-
ui: {
|
|
35427
|
+
ui: {
|
|
35428
|
+
compact: false,
|
|
35429
|
+
logo: "auto",
|
|
35430
|
+
animation: true,
|
|
35431
|
+
restoreOnCancel: true,
|
|
35432
|
+
enterWhileRunning: "queue",
|
|
35433
|
+
language: "auto"
|
|
35434
|
+
},
|
|
35310
35435
|
// [W6-C0] 第六波键的缺省(行为由各批次实现)
|
|
35311
35436
|
memory: {
|
|
35312
35437
|
enabled: false,
|
|
@@ -35709,6 +35834,7 @@ function buildBaseSchema() {
|
|
|
35709
35834
|
logo: oneOf(["auto", "off"]),
|
|
35710
35835
|
animation: bool(),
|
|
35711
35836
|
restoreOnCancel: bool(),
|
|
35837
|
+
enterWhileRunning: oneOf(["queue", "interrupt"]),
|
|
35712
35838
|
statusLine: oneOf(STATUS_LINE_MODES),
|
|
35713
35839
|
language: oneOf(LANGUAGE_SETTINGS),
|
|
35714
35840
|
replyLanguage: str3(),
|
|
@@ -39722,6 +39848,7 @@ var init_settings_registry = __esm({
|
|
|
39722
39848
|
row("ui.logo", "ui", "restart", "any"),
|
|
39723
39849
|
row("ui.statusLine", "ui", "now", "any"),
|
|
39724
39850
|
row("ui.restoreOnCancel", "ui", "nextSession", "any"),
|
|
39851
|
+
row("ui.enterWhileRunning", "ui", "now", "any"),
|
|
39725
39852
|
row("ui.quietStartup", "ui", "restart", "any"),
|
|
39726
39853
|
row("ui.ascii", "ui", "restart", "any", { envOverride: "AMA_ASCII" }),
|
|
39727
39854
|
row("ui.language", "ui", "restart", "any", { envOverride: "AMA_LANG" }),
|
|
@@ -41477,6 +41604,13 @@ var init_keybindings = __esm({
|
|
|
41477
41604
|
"app.exit": ["ctrl+d"],
|
|
41478
41605
|
"app.message.followUp": ["alt+enter"],
|
|
41479
41606
|
"app.message.dequeue": ["alt+up"],
|
|
41607
|
+
/**
|
|
41608
|
+
* 运行中打断当前回合并立即发送输入框的文字(连同排队的插话);`ui.enterWhileRunning: "interrupt"` 时与
|
|
41609
|
+
* Enter 互换(它变成排队)。缺省 `Ctrl+X`:各终端(macOS Terminal、iTerm2、tmux、Windows Terminal)都原样
|
|
41610
|
+
* 送达 0x18,且没有别的绑定;`Ctrl+Enter` 不开 kitty 键盘协议时与 Enter 无法区分,`Ctrl+S` 可能被 XOFF
|
|
41611
|
+
* 流控吃掉,`Alt+Enter` 已是 followUp,`Alt+<字母>` 在 macOS 缺省不送 Meta,`Ctrl+]` 在非美式键盘难按。
|
|
41612
|
+
*/
|
|
41613
|
+
"app.message.interrupt": ["ctrl+x"],
|
|
41480
41614
|
"app.permission.cycle": ["shift+tab", "tab"],
|
|
41481
41615
|
"app.tools.expand": ["ctrl+o"],
|
|
41482
41616
|
"app.model.select": ["ctrl+l"],
|
|
@@ -44928,34 +45062,46 @@ function windowSpan(minutes) {
|
|
|
44928
45062
|
if (minutes % 60 === 0) return `${minutes / 60}h`;
|
|
44929
45063
|
return `${Math.round(minutes)}m`;
|
|
44930
45064
|
}
|
|
44931
|
-
function
|
|
44932
|
-
const m =
|
|
44933
|
-
|
|
44934
|
-
|
|
44935
|
-
|
|
44936
|
-
|
|
44937
|
-
|
|
45065
|
+
function minutesOf(w) {
|
|
45066
|
+
const m = w.windowMinutes;
|
|
45067
|
+
return m !== void 0 && Number.isFinite(m) && m > 0 ? m : void 0;
|
|
45068
|
+
}
|
|
45069
|
+
function kindOf(minutes) {
|
|
45070
|
+
if (minutes === FIVE_HOURS) return "session";
|
|
45071
|
+
if (minutes === WEEK) return "weekly";
|
|
45072
|
+
return minutes;
|
|
44938
45073
|
}
|
|
44939
|
-
function
|
|
45074
|
+
function labels(kind) {
|
|
44940
45075
|
const m = msg().interactive.statusLine.quota;
|
|
44941
|
-
|
|
44942
|
-
if (
|
|
44943
|
-
|
|
44944
|
-
return
|
|
45076
|
+
if (kind === "session") return { pct: m.session, reset: m.reset, short: m.short5h };
|
|
45077
|
+
if (kind === "weekly") return { pct: m.weekly, reset: m.weeklyReset, short: m.shortWeek };
|
|
45078
|
+
const span = windowSpan(kind);
|
|
45079
|
+
return { pct: m.window(span), reset: m.windowReset(span), short: span };
|
|
44945
45080
|
}
|
|
44946
45081
|
function percent2(theme, used, decimal) {
|
|
44947
45082
|
return theme.fg(levelColor(used / 100), decimal ? `${used.toFixed(1)}%` : `${Math.round(used)}%`);
|
|
44948
45083
|
}
|
|
44949
|
-
function
|
|
44950
|
-
|
|
44951
|
-
|
|
44952
|
-
|
|
44953
|
-
|
|
45084
|
+
function hasData(w) {
|
|
45085
|
+
return w.usedPercent !== 0 || minutesOf(w) !== void 0 || w.resetsAt !== void 0;
|
|
45086
|
+
}
|
|
45087
|
+
function shownWindows(quota) {
|
|
45088
|
+
const slots = ["primary", "secondary"].map((which) => ({ which, w: quota[which] })).filter((x) => x.w !== void 0).filter((x) => hasData(x.w));
|
|
45089
|
+
const known = slots.map((x) => kindOf(minutesOf(x.w)));
|
|
45090
|
+
const out = slots.map((x, i) => {
|
|
45091
|
+
const own = known[i];
|
|
45092
|
+
if (own !== void 0) return { kind: own, window: x.w };
|
|
45093
|
+
const guess = x.which === "primary" ? "session" : "weekly";
|
|
45094
|
+
const taken = known.some((k, j) => j !== i && k === guess);
|
|
45095
|
+
const kind = taken ? guess === "session" ? "weekly" : "session" : guess;
|
|
45096
|
+
return { kind, window: x.w };
|
|
45097
|
+
});
|
|
45098
|
+
const span = (k) => typeof k === "number" ? k : SPAN[k];
|
|
45099
|
+
return out.sort((a, b) => span(a.kind) - span(b.kind));
|
|
44954
45100
|
}
|
|
44955
45101
|
function compactQuotaItem(quota, theme) {
|
|
44956
45102
|
const dim = (text) => theme.fg("dim", text);
|
|
44957
|
-
const items =
|
|
44958
|
-
(
|
|
45103
|
+
const items = shownWindows(quota).map(
|
|
45104
|
+
({ kind, window: w }) => `${dim(labels(kind).short)} ${percent2(theme, w.usedPercent, false)}`
|
|
44959
45105
|
);
|
|
44960
45106
|
return items.length === 0 ? void 0 : items.join(" ");
|
|
44961
45107
|
}
|
|
@@ -44963,30 +45109,31 @@ function quotaParts2(quota, width2, now, theme) {
|
|
|
44963
45109
|
const dim = (text) => theme.fg("dim", text);
|
|
44964
45110
|
const narrow = width2 < QUOTA_NARROW_WIDTH;
|
|
44965
45111
|
const parts = [];
|
|
44966
|
-
|
|
45112
|
+
shownWindows(quota).forEach(({ kind, window: w }, i) => {
|
|
44967
45113
|
const first = i === 0;
|
|
44968
|
-
const group = narrow ?
|
|
44969
|
-
const
|
|
45114
|
+
const group = narrow ? `w${i}` : void 0;
|
|
45115
|
+
const label2 = labels(kind);
|
|
45116
|
+
const name = narrow ? `${label2.short} ` : label2.pct;
|
|
44970
45117
|
parts.push({
|
|
44971
45118
|
text: dim(name) + percent2(theme, w.usedPercent, !narrow),
|
|
44972
45119
|
priority: first ? void 0 : 2,
|
|
44973
|
-
zone: "
|
|
45120
|
+
zone: "right",
|
|
44974
45121
|
...group !== void 0 ? { group } : {}
|
|
44975
45122
|
});
|
|
44976
45123
|
if (w.resetsAt === void 0) return;
|
|
44977
45124
|
const left = formatRemaining(w.resetsAt - now, narrow);
|
|
44978
45125
|
parts.push({
|
|
44979
|
-
text: narrow ? theme.fg("tool", `${theme.glyphs.retry}${left}`) : dim(
|
|
45126
|
+
text: narrow ? theme.fg("tool", `${theme.glyphs.retry}${left}`) : dim(label2.reset) + theme.fg("tool", left),
|
|
44980
45127
|
priority: first ? 3 : 1,
|
|
44981
|
-
zone: "
|
|
45128
|
+
zone: "right",
|
|
44982
45129
|
// 宽格式按最宽形状占位(`23h 59m`),数值变化不让某项时有时无
|
|
44983
|
-
reserve: narrow ? 0 : visibleWidth(
|
|
45130
|
+
reserve: narrow ? 0 : visibleWidth(label2.reset) + 7,
|
|
44984
45131
|
...group !== void 0 ? { group } : {}
|
|
44985
45132
|
});
|
|
44986
45133
|
});
|
|
44987
45134
|
return parts;
|
|
44988
45135
|
}
|
|
44989
|
-
var QUOTA_NARROW_WIDTH, FIVE_HOURS, WEEK, QuotaLine;
|
|
45136
|
+
var QUOTA_NARROW_WIDTH, FIVE_HOURS, WEEK, SPAN, QuotaLine;
|
|
44990
45137
|
var init_status_quota = __esm({
|
|
44991
45138
|
"src/modes/interactive/status-quota.ts"() {
|
|
44992
45139
|
"use strict";
|
|
@@ -44996,6 +45143,7 @@ var init_status_quota = __esm({
|
|
|
44996
45143
|
QUOTA_NARROW_WIDTH = 80;
|
|
44997
45144
|
FIVE_HOURS = 300;
|
|
44998
45145
|
WEEK = 10080;
|
|
45146
|
+
SPAN = { session: FIVE_HOURS, weekly: WEEK };
|
|
44999
45147
|
QuotaLine = class {
|
|
45000
45148
|
constructor(source, theme) {
|
|
45001
45149
|
this.source = source;
|
|
@@ -45009,7 +45157,8 @@ var init_status_quota = __esm({
|
|
|
45009
45157
|
if (view === void 0) return [];
|
|
45010
45158
|
const theme = this.theme;
|
|
45011
45159
|
if (view === "pending") {
|
|
45012
|
-
|
|
45160
|
+
const text = theme.fg("dim", msg().interactive.statusLine.quota.pending);
|
|
45161
|
+
return [layoutRow([{ text, priority: void 0, zone: "right" }], width2, theme)];
|
|
45013
45162
|
}
|
|
45014
45163
|
const parts = quotaParts2(view.quota, width2, this.source.now(), theme);
|
|
45015
45164
|
if (parts.length === 0) return [];
|
|
@@ -45085,9 +45234,10 @@ function layoutRow(parts, width2, theme, style = {}) {
|
|
|
45085
45234
|
let kept = [...parts];
|
|
45086
45235
|
const zone = (z) => kept.filter((p) => p.zone === z);
|
|
45087
45236
|
const fits = () => {
|
|
45088
|
-
const
|
|
45237
|
+
const left = zone("left");
|
|
45089
45238
|
const right = zone("right");
|
|
45090
|
-
|
|
45239
|
+
const between = left.length === 0 || right.length === 0 ? 0 : sep5.length;
|
|
45240
|
+
return join66(left)[1] + between + join66(right)[1] <= width2;
|
|
45091
45241
|
};
|
|
45092
45242
|
while (!fits()) {
|
|
45093
45243
|
const droppable = kept.filter((p) => p.priority !== void 0);
|
|
@@ -45098,7 +45248,7 @@ function layoutRow(parts, width2, theme, style = {}) {
|
|
|
45098
45248
|
const l = join66(zone("left"))[0];
|
|
45099
45249
|
const r = join66(zone("right"))[0];
|
|
45100
45250
|
const gap = width2 - visibleWidth(l) - visibleWidth(r);
|
|
45101
|
-
const line2 = r === "" ? l : gap >= MIN_GAP ? l + " ".repeat(gap) + r : l + dim(sep5) + r;
|
|
45251
|
+
const line2 = r === "" ? l : l === "" ? " ".repeat(Math.max(0, gap)) + r : gap >= MIN_GAP ? l + " ".repeat(gap) + r : l + dim(sep5) + r;
|
|
45102
45252
|
return truncateToWidth(line2, width2);
|
|
45103
45253
|
}
|
|
45104
45254
|
function abbreviateModel(ref, width2) {
|
|
@@ -45230,7 +45380,7 @@ var init_status_bar = __esm({
|
|
|
45230
45380
|
}
|
|
45231
45381
|
const model = state.model === void 0 ? "?" : abbreviateModel(formatModelRef(state.model), width2);
|
|
45232
45382
|
const p = full ? FULL : COMPACT;
|
|
45233
|
-
const fallback = this.source.fallback?.();
|
|
45383
|
+
const fallback = full ? void 0 : this.source.fallback?.();
|
|
45234
45384
|
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
45385
|
right(modelText, p.model, full ? { group: "model" } : {});
|
|
45236
45386
|
if (state.thinkingLevel !== "off") {
|
|
@@ -49024,6 +49174,13 @@ async function runSlashCommand(line2, ctx) {
|
|
|
49024
49174
|
return planCommand(session, args, ctx);
|
|
49025
49175
|
case "tasks":
|
|
49026
49176
|
return { kind: "handled", message: await tasksCommand(session, args) };
|
|
49177
|
+
case "interrupt": {
|
|
49178
|
+
if (args === "") throw new AmaError("invalid_arguments", msg().report.command.interruptUsage);
|
|
49179
|
+
const { isStreaming, isCompacting } = session.state;
|
|
49180
|
+
if (!isStreaming && !isCompacting) return { kind: "prompt", text: args };
|
|
49181
|
+
void session.prompt(args, { interrupt: true }).catch(() => void 0);
|
|
49182
|
+
return { kind: "handled", message: msg().report.command.interruptSent(args) };
|
|
49183
|
+
}
|
|
49027
49184
|
case "agents":
|
|
49028
49185
|
return { kind: "handled", message: describeAgents(session.state.sessionId) };
|
|
49029
49186
|
case "paste": {
|
|
@@ -49079,6 +49236,7 @@ var init_commands_core = __esm({
|
|
|
49079
49236
|
command("tasks", "tasks", "[id] | stop <id> | bg [id]"),
|
|
49080
49237
|
command("agents", "agents"),
|
|
49081
49238
|
command("paste", "paste"),
|
|
49239
|
+
command("interrupt", "interrupt", { key: "interruptArgs" }),
|
|
49082
49240
|
command("exit", "exit"),
|
|
49083
49241
|
// [W6-C0] 第六波(W6-S / W6-T1 / W6-M 实现)
|
|
49084
49242
|
command("config", "config", "[key=value]"),
|
|
@@ -49129,6 +49287,11 @@ function applyPlanAttendance(ctx) {
|
|
|
49129
49287
|
ctx.capabilities.has("plans") ? "client" : "unattended"
|
|
49130
49288
|
);
|
|
49131
49289
|
}
|
|
49290
|
+
function interruptFlag(value) {
|
|
49291
|
+
if (value !== void 0 && typeof value !== "boolean")
|
|
49292
|
+
throw new AmaError("invalid_arguments", "interrupt must be a boolean");
|
|
49293
|
+
return value === true;
|
|
49294
|
+
}
|
|
49132
49295
|
async function startRun(ctx, run7) {
|
|
49133
49296
|
const session = ctx.session();
|
|
49134
49297
|
let settled = false;
|
|
@@ -49251,10 +49414,17 @@ var init_commands = __esm({
|
|
|
49251
49414
|
ctx,
|
|
49252
49415
|
() => ctx.session().prompt(p.message, {
|
|
49253
49416
|
...p.images !== void 0 ? { images: p.images } : {},
|
|
49254
|
-
...p.streamingBehavior !== void 0 ? { streamingBehavior: p.streamingBehavior } : {}
|
|
49417
|
+
...p.streamingBehavior !== void 0 ? { streamingBehavior: p.streamingBehavior } : {},
|
|
49418
|
+
...interruptFlag(p.interrupt) ? { interrupt: true } : {}
|
|
49255
49419
|
})
|
|
49256
49420
|
),
|
|
49257
|
-
steer: (p, ctx) => startRun(
|
|
49421
|
+
steer: (p, ctx) => startRun(
|
|
49422
|
+
ctx,
|
|
49423
|
+
() => interruptFlag(p.interrupt) ? ctx.session().prompt(p.message, {
|
|
49424
|
+
interrupt: true,
|
|
49425
|
+
...p.images !== void 0 ? { images: p.images } : {}
|
|
49426
|
+
}) : ctx.session().steer(p.message)
|
|
49427
|
+
),
|
|
49258
49428
|
follow_up: (p, ctx) => startRun(ctx, () => ctx.session().followUp(p.message)),
|
|
49259
49429
|
abort: async (_p, ctx) => {
|
|
49260
49430
|
await ctx.session().abort();
|
|
@@ -52879,13 +53049,13 @@ ${bypassRiskLines().map((l) => ` ${l}
|
|
|
52879
53049
|
void ed.ask(`
|
|
52880
53050
|
${preview.join("")}${question}`, "n").then((answer) => {
|
|
52881
53051
|
resolve39(answer === "y" ? "allow" : answer === "a" ? "allow_session" : "deny");
|
|
52882
|
-
if (
|
|
53052
|
+
if (running === 0) ed.render();
|
|
52883
53053
|
});
|
|
52884
53054
|
})
|
|
52885
53055
|
});
|
|
52886
53056
|
runtime.notifier.set((message, level) => err(`ama: [${level}] ${message}
|
|
52887
53057
|
`));
|
|
52888
|
-
let
|
|
53058
|
+
let running = 0;
|
|
52889
53059
|
let lastInterrupt = 0;
|
|
52890
53060
|
return new Promise((resolve39) => {
|
|
52891
53061
|
let finished = false;
|
|
@@ -52905,11 +53075,23 @@ ${preview.join("")}${question}`, "n").then((answer) => {
|
|
|
52905
53075
|
});
|
|
52906
53076
|
};
|
|
52907
53077
|
const run7 = (text) => {
|
|
52908
|
-
|
|
53078
|
+
running++;
|
|
52909
53079
|
void handle(text).then((outcome) => {
|
|
52910
|
-
|
|
53080
|
+
running--;
|
|
52911
53081
|
if (outcome === "exit") finish2(ExitCode.Ok);
|
|
52912
|
-
else ed.render();
|
|
53082
|
+
else if (running === 0) ed.render();
|
|
53083
|
+
});
|
|
53084
|
+
};
|
|
53085
|
+
const interruptWith = (text) => {
|
|
53086
|
+
if (text === "") return err(`ama: ${msg().report.command.interruptUsage}
|
|
53087
|
+
`);
|
|
53088
|
+
out(`${msg().report.command.interruptSent(text)}
|
|
53089
|
+
`);
|
|
53090
|
+
running++;
|
|
53091
|
+
void session.prompt(text, { interrupt: true }).catch((error2) => err(`ama: ${errorText3(error2)}
|
|
53092
|
+
`)).finally(() => {
|
|
53093
|
+
printer.endLine();
|
|
53094
|
+
if (--running === 0) ed.render();
|
|
52913
53095
|
});
|
|
52914
53096
|
};
|
|
52915
53097
|
let flushTimer;
|
|
@@ -52917,7 +53099,7 @@ ${preview.join("")}${question}`, "n").then((answer) => {
|
|
|
52917
53099
|
for (const action of actions) {
|
|
52918
53100
|
if (action.kind === "eof") return finish2(ExitCode.Ok);
|
|
52919
53101
|
if (action.kind === "interrupt") {
|
|
52920
|
-
if (
|
|
53102
|
+
if (running > 0) {
|
|
52921
53103
|
void session.abort();
|
|
52922
53104
|
err(`${msg().interactive.line.interrupted}
|
|
52923
53105
|
`);
|
|
@@ -52932,7 +53114,12 @@ ${msg().interactive.line.ctrlCAgain}
|
|
|
52932
53114
|
}
|
|
52933
53115
|
continue;
|
|
52934
53116
|
}
|
|
52935
|
-
if (
|
|
53117
|
+
if (running > 0) {
|
|
53118
|
+
const forced2 = /^\/interrupt(?:\s+([\s\S]*))?$/.exec(action.text.trim());
|
|
53119
|
+
if (forced2 !== null) {
|
|
53120
|
+
interruptWith((forced2[1] ?? "").trim());
|
|
53121
|
+
continue;
|
|
53122
|
+
}
|
|
52936
53123
|
if (/^\/tasks\s+bg(\s+\S+)?\s*$/.test(action.text.trim())) {
|
|
52937
53124
|
void handle(action.text.trim());
|
|
52938
53125
|
continue;
|
|
@@ -53421,7 +53608,7 @@ var init_agent_view = __esm({
|
|
|
53421
53608
|
maxVisibleLines: 4,
|
|
53422
53609
|
placeholder: msg().agents.view.placeholder(taskId),
|
|
53423
53610
|
requestRender: () => deps.render(),
|
|
53424
|
-
onSubmit: (text) => void this.submit(text)
|
|
53611
|
+
onSubmit: (text) => void this.submit(text, this.enterInterrupts())
|
|
53425
53612
|
});
|
|
53426
53613
|
this.attach();
|
|
53427
53614
|
}
|
|
@@ -53519,7 +53706,10 @@ var init_agent_view = __esm({
|
|
|
53519
53706
|
this.attach();
|
|
53520
53707
|
this.deps.onSwitch?.(next);
|
|
53521
53708
|
}
|
|
53522
|
-
|
|
53709
|
+
enterInterrupts() {
|
|
53710
|
+
return this.deps.enterMode?.() === "interrupt";
|
|
53711
|
+
}
|
|
53712
|
+
async submit(text, interrupt = false) {
|
|
53523
53713
|
const m = msg().agents.view;
|
|
53524
53714
|
const trimmed = text.trim();
|
|
53525
53715
|
if (trimmed === "") return;
|
|
@@ -53545,7 +53735,7 @@ var init_agent_view = __esm({
|
|
|
53545
53735
|
const registry2 = this.deps.registry();
|
|
53546
53736
|
try {
|
|
53547
53737
|
if (registry2 === void 0) throw new Error(m.unknown(taskId));
|
|
53548
|
-
const reply = await registry2.message(taskId, text);
|
|
53738
|
+
const reply = await registry2.message(taskId, text, interrupt);
|
|
53549
53739
|
this.flash = m[reply](taskId);
|
|
53550
53740
|
} catch (error2) {
|
|
53551
53741
|
this.flash = m.sendFailed(error2 instanceof Error ? error2.message : String(error2));
|
|
@@ -53565,6 +53755,11 @@ var init_agent_view = __esm({
|
|
|
53565
53755
|
return;
|
|
53566
53756
|
}
|
|
53567
53757
|
}
|
|
53758
|
+
if (keys.matches(data2, "app.message.interrupt") && !this.editor.isCompletionOpen) {
|
|
53759
|
+
const text = this.editor.takeSubmission();
|
|
53760
|
+
if (text !== null) void this.submit(text, !this.enterInterrupts());
|
|
53761
|
+
return;
|
|
53762
|
+
}
|
|
53568
53763
|
if (keys.matches(data2, "tui.select.cancel") && !this.editor.isCompletionOpen) {
|
|
53569
53764
|
if (!empty) this.editor.clear();
|
|
53570
53765
|
else this.deps.close();
|
|
@@ -54691,6 +54886,7 @@ var init_agent_ui = __esm({
|
|
|
54691
54886
|
close: () => this.closeView(),
|
|
54692
54887
|
stop: (id) => stopTask(this.deps.session().state.sessionId, id),
|
|
54693
54888
|
background: (id) => this.deps.session().backgroundTask(id, "user"),
|
|
54889
|
+
enterMode: () => this.deps.area?.ui().enterWhileRunning === "interrupt" ? "interrupt" : "queue",
|
|
54694
54890
|
messages: {
|
|
54695
54891
|
...ui.showThinking !== void 0 ? { showThinking: ui.showThinking } : {},
|
|
54696
54892
|
...ui.markdown !== void 0 ? { markdown: ui.markdown } : {},
|
|
@@ -55624,16 +55820,18 @@ var init_status_line = __esm({
|
|
|
55624
55820
|
init_status_bar();
|
|
55625
55821
|
RESERVE = { tps: 14, amount: 16, avg: 7, ttft: 9 };
|
|
55626
55822
|
PRIORITY = {
|
|
55627
|
-
|
|
55628
|
-
|
|
55629
|
-
|
|
55823
|
+
codemode: 1,
|
|
55824
|
+
sandbox: 2,
|
|
55825
|
+
fallback: 3,
|
|
55630
55826
|
preset: 4,
|
|
55631
|
-
|
|
55632
|
-
|
|
55633
|
-
|
|
55634
|
-
|
|
55635
|
-
|
|
55636
|
-
|
|
55827
|
+
queue: 5,
|
|
55828
|
+
host: 6,
|
|
55829
|
+
ttft: 7,
|
|
55830
|
+
avg: 8,
|
|
55831
|
+
rebill: 9,
|
|
55832
|
+
cache: 10,
|
|
55833
|
+
tokens: 11,
|
|
55834
|
+
amount: 12
|
|
55637
55835
|
};
|
|
55638
55836
|
COLLAPSE_HINT = "[-]";
|
|
55639
55837
|
RATE_STYLE = { groups: { stats: { glue: " · ", open: "(", close: ")" } } };
|
|
@@ -55646,7 +55844,7 @@ var init_status_line = __esm({
|
|
|
55646
55844
|
bar;
|
|
55647
55845
|
source;
|
|
55648
55846
|
theme;
|
|
55649
|
-
parts() {
|
|
55847
|
+
parts(width2) {
|
|
55650
55848
|
const theme = this.theme;
|
|
55651
55849
|
const dim = (text) => theme.fg("dim", text);
|
|
55652
55850
|
const stats = this.bar.current();
|
|
@@ -55654,9 +55852,9 @@ var init_status_line = __esm({
|
|
|
55654
55852
|
const live2 = telemetry?.live;
|
|
55655
55853
|
const last = telemetry?.last;
|
|
55656
55854
|
const parts = [];
|
|
55657
|
-
const
|
|
55658
|
-
const
|
|
55659
|
-
if (text !== void 0) parts.push({ text, priority, zone
|
|
55855
|
+
const metric = (text, priority, reserve, extra = {}) => void parts.push({ text, priority, zone: "right", reserve, ...extra });
|
|
55856
|
+
const add3 = (zone, text, priority) => {
|
|
55857
|
+
if (text !== void 0) parts.push({ text, priority, zone });
|
|
55660
55858
|
};
|
|
55661
55859
|
const blue = (text) => theme.fg("accent", text);
|
|
55662
55860
|
const purple = (text) => theme.fg("tool", text);
|
|
@@ -55673,20 +55871,25 @@ var init_status_line = __esm({
|
|
|
55673
55871
|
}
|
|
55674
55872
|
}
|
|
55675
55873
|
const label2 = live2 !== void 0 ? theme.fg("accent", "tps:") : dim("tps:");
|
|
55676
|
-
|
|
55874
|
+
metric(
|
|
55677
55875
|
`${label2} ${tps === void 0 ? dim("—") : `${purple(formatRate(tps))}${dim(" tok/s")}`}`,
|
|
55678
55876
|
void 0,
|
|
55679
55877
|
RESERVE.tps
|
|
55680
55878
|
);
|
|
55681
55879
|
if (amount !== void 0) {
|
|
55682
|
-
|
|
55880
|
+
metric(amount, PRIORITY.amount, RESERVE.amount, { lead: ` ${theme.glyphs.dot} ` });
|
|
55683
55881
|
}
|
|
55684
55882
|
const stat16 = { group: "stats", lead: " " };
|
|
55685
55883
|
if (telemetry?.avgTps !== void 0) {
|
|
55686
|
-
|
|
55884
|
+
metric(
|
|
55885
|
+
`${dim("avg ")}${blue(formatRate(telemetry.avgTps))}`,
|
|
55886
|
+
PRIORITY.avg,
|
|
55887
|
+
RESERVE.avg,
|
|
55888
|
+
stat16
|
|
55889
|
+
);
|
|
55687
55890
|
}
|
|
55688
55891
|
if (last?.ttftMs !== void 0) {
|
|
55689
|
-
|
|
55892
|
+
metric(
|
|
55690
55893
|
`${dim("ttft ")}${purple(formatSeconds2(last.ttftMs))}`,
|
|
55691
55894
|
PRIORITY.ttft,
|
|
55692
55895
|
RESERVE.ttft,
|
|
@@ -55694,20 +55897,29 @@ var init_status_line = __esm({
|
|
|
55694
55897
|
);
|
|
55695
55898
|
}
|
|
55696
55899
|
const usage = usageItems(stats, this.bar.queued(), this.source, theme);
|
|
55697
|
-
right
|
|
55698
|
-
right
|
|
55699
|
-
right
|
|
55700
|
-
right(
|
|
55701
|
-
|
|
55702
|
-
|
|
55703
|
-
|
|
55704
|
-
|
|
55705
|
-
|
|
55900
|
+
add3("right", usage.tokens, PRIORITY.tokens);
|
|
55901
|
+
add3("right", usage.cache, PRIORITY.cache);
|
|
55902
|
+
add3("right", usage.rebill, PRIORITY.rebill);
|
|
55903
|
+
add3("right", dim(COLLAPSE_HINT), void 0);
|
|
55904
|
+
add3("left", usage.codemode, PRIORITY.codemode);
|
|
55905
|
+
add3("left", usage.sandbox, PRIORITY.sandbox);
|
|
55906
|
+
add3("left", usage.preset, PRIORITY.preset);
|
|
55907
|
+
const fallback = this.source.fallback?.();
|
|
55908
|
+
if (fallback !== void 0) {
|
|
55909
|
+
const arrow = theme.glyphs.ascii ? "-> " : "→ ";
|
|
55910
|
+
add3(
|
|
55911
|
+
"left",
|
|
55912
|
+
dim(arrow) + theme.fg("warning", abbreviateModel(fallback.to, width2)),
|
|
55913
|
+
PRIORITY.fallback
|
|
55914
|
+
);
|
|
55915
|
+
}
|
|
55916
|
+
add3("left", usage.queue, PRIORITY.queue);
|
|
55917
|
+
add3("left", usage.host, PRIORITY.host);
|
|
55706
55918
|
return parts;
|
|
55707
55919
|
}
|
|
55708
55920
|
render(width2) {
|
|
55709
55921
|
if (this.bar.layout() !== "full") return [];
|
|
55710
|
-
return [truncateToWidth(layoutRow(this.parts(), width2, this.theme, RATE_STYLE), width2)];
|
|
55922
|
+
return [truncateToWidth(layoutRow(this.parts(width2), width2, this.theme, RATE_STYLE), width2)];
|
|
55711
55923
|
}
|
|
55712
55924
|
invalidate() {
|
|
55713
55925
|
}
|
|
@@ -56008,6 +56220,27 @@ ${current3}`);
|
|
|
56008
56220
|
if (typeof answer === "boolean") settle(answer);
|
|
56009
56221
|
else void answer.then(settle);
|
|
56010
56222
|
};
|
|
56223
|
+
const sendKeys = (is) => {
|
|
56224
|
+
if (deps.interruptSend === void 0 || editor.isCompletionOpen) return false;
|
|
56225
|
+
const viaKey = is("app.message.interrupt");
|
|
56226
|
+
if (!deps.busy()) {
|
|
56227
|
+
if (!viaKey || editor.isEmpty()) return false;
|
|
56228
|
+
const text = editor.takeSubmission();
|
|
56229
|
+
if (text !== null) deps.submit(text, "enter");
|
|
56230
|
+
return true;
|
|
56231
|
+
}
|
|
56232
|
+
const interruptMode = deps.enterWhileRunning?.() === "interrupt";
|
|
56233
|
+
if (!viaKey && !(interruptMode && is("tui.editor.submit"))) return false;
|
|
56234
|
+
const command3 = editor.getExpandedText().trimStart().startsWith("/");
|
|
56235
|
+
if (command3 || viaKey === interruptMode) {
|
|
56236
|
+
if (!viaKey) return false;
|
|
56237
|
+
const text = editor.takeSubmission();
|
|
56238
|
+
if (text !== null) deps.submit(text, "enter");
|
|
56239
|
+
return true;
|
|
56240
|
+
}
|
|
56241
|
+
deps.interruptSend(editor.takeSubmission() ?? "");
|
|
56242
|
+
return true;
|
|
56243
|
+
};
|
|
56011
56244
|
const atLastLine = () => editor.cursor.line >= editor.getText().split("\n").length - 1;
|
|
56012
56245
|
const focusAgents = (agents, data2) => {
|
|
56013
56246
|
if (editor.isCompletionOpen || editor.isBrowsingHistory) return false;
|
|
@@ -56064,6 +56297,7 @@ ${current3}`);
|
|
|
56064
56297
|
return true;
|
|
56065
56298
|
}
|
|
56066
56299
|
ctrlCArmedAt = Number.NEGATIVE_INFINITY;
|
|
56300
|
+
if (sendKeys(is)) return true;
|
|
56067
56301
|
if (is("app.interrupt") && !editor.isCompletionOpen && deps.busy()) {
|
|
56068
56302
|
esc.reset();
|
|
56069
56303
|
interrupt();
|
|
@@ -56138,6 +56372,34 @@ var init_key_dispatch = __esm({
|
|
|
56138
56372
|
}
|
|
56139
56373
|
});
|
|
56140
56374
|
|
|
56375
|
+
// src/modes/interactive/interrupt-send.ts
|
|
56376
|
+
function interruptSender(deps) {
|
|
56377
|
+
return (text) => {
|
|
56378
|
+
const images = deps.takeImages();
|
|
56379
|
+
deps.showHint(msg().interactive.keys.interruptSent);
|
|
56380
|
+
const options = images.length > 0 ? { interrupt: true, images } : { interrupt: true };
|
|
56381
|
+
void deps.session().prompt(text, options).catch((error2) => {
|
|
56382
|
+
if (isAmaError(error2) && error2.code === "invalid_arguments")
|
|
56383
|
+
deps.showHint(msg().interactive.keys.nothingToSend);
|
|
56384
|
+
});
|
|
56385
|
+
};
|
|
56386
|
+
}
|
|
56387
|
+
function enterModeOf(runtime) {
|
|
56388
|
+
return runtime.config.ui?.enterWhileRunning === "interrupt" ? "interrupt" : "queue";
|
|
56389
|
+
}
|
|
56390
|
+
function interruptKeys(keys, mode) {
|
|
56391
|
+
const key = keyLabel(keys, "app.message.interrupt");
|
|
56392
|
+
return { key, now: () => mode() === "interrupt" ? "Enter" : key };
|
|
56393
|
+
}
|
|
56394
|
+
var init_interrupt_send = __esm({
|
|
56395
|
+
"src/modes/interactive/interrupt-send.ts"() {
|
|
56396
|
+
"use strict";
|
|
56397
|
+
init_errors();
|
|
56398
|
+
init_i18n();
|
|
56399
|
+
init_task_background();
|
|
56400
|
+
}
|
|
56401
|
+
});
|
|
56402
|
+
|
|
56141
56403
|
// src/modes/interactive/model-picker.ts
|
|
56142
56404
|
async function openModelPicker(host, options) {
|
|
56143
56405
|
const catalog = await loadModelCatalog(options.providers);
|
|
@@ -57500,10 +57762,7 @@ var init_run_indicator = __esm({
|
|
|
57500
57762
|
RunIndicator = class {
|
|
57501
57763
|
constructor(deps) {
|
|
57502
57764
|
this.deps = deps;
|
|
57503
|
-
deps.loader.onFrame(() =>
|
|
57504
|
-
if (this.busy && !this.approval && this.optionalHints().join("\n") !== this.hintKey)
|
|
57505
|
-
this.applyVerb();
|
|
57506
|
-
});
|
|
57765
|
+
deps.loader.onFrame(() => this.refreshHints());
|
|
57507
57766
|
}
|
|
57508
57767
|
deps;
|
|
57509
57768
|
running = false;
|
|
@@ -57517,12 +57776,24 @@ var init_run_indicator = __esm({
|
|
|
57517
57776
|
background = () => false;
|
|
57518
57777
|
/** [W7-C] 有停靠在 Agent 栏的审批。 */
|
|
57519
57778
|
docked = () => false;
|
|
57779
|
+
/** 输入框有字(显示 Enter / 专用键的提示)。 */
|
|
57780
|
+
draft = () => false;
|
|
57781
|
+
/** 运行中 Enter 的语义。 */
|
|
57782
|
+
enterMode = () => "queue";
|
|
57520
57783
|
hintKey = "";
|
|
57784
|
+
/** 可丢弃提示变了才换动词(每帧、输入框内容变化时调)。 */
|
|
57785
|
+
refreshHints() {
|
|
57786
|
+
if (this.busy && !this.approval && this.optionalHints().join("\n") !== this.hintKey)
|
|
57787
|
+
this.applyVerb();
|
|
57788
|
+
}
|
|
57521
57789
|
/** 可丢弃的按键提示(按丢弃的逆序排列)。 */
|
|
57522
57790
|
optionalHints() {
|
|
57523
57791
|
const down = this.deps.theme.glyphs.arrowDown;
|
|
57524
57792
|
const key = this.deps.backgroundKey;
|
|
57525
57793
|
const out = [];
|
|
57794
|
+
const send2 = this.deps.interruptKey;
|
|
57795
|
+
if (send2 !== void 0 && this.draft())
|
|
57796
|
+
out.push(msg().interactive.view.run.sendHint(this.enterMode(), send2));
|
|
57526
57797
|
if (key !== void 0 && this.background()) out.push(msg().agents.background.runHint(key));
|
|
57527
57798
|
if (this.docked()) out.push(msg().agents.approval.runHint(down));
|
|
57528
57799
|
else if (this.agents()) out.push(msg().agents.bar.runHint(down));
|
|
@@ -57643,11 +57914,16 @@ var init_run_indicator = __esm({
|
|
|
57643
57914
|
}
|
|
57644
57915
|
};
|
|
57645
57916
|
QueueView = class extends Text {
|
|
57646
|
-
|
|
57917
|
+
/**
|
|
57918
|
+
* @param nowKey 立即送出排队插话的键(专用键;interrupt 模式下是 Enter);undefined 不提示。
|
|
57919
|
+
*/
|
|
57920
|
+
constructor(theme, nowKey = () => void 0) {
|
|
57647
57921
|
super("");
|
|
57648
57922
|
this.theme = theme;
|
|
57923
|
+
this.nowKey = nowKey;
|
|
57649
57924
|
}
|
|
57650
57925
|
theme;
|
|
57926
|
+
nowKey;
|
|
57651
57927
|
setQueue(steering, followUp) {
|
|
57652
57928
|
const t = this.theme;
|
|
57653
57929
|
const row3 = (origin, text) => ` ${t.fg("dim", `${t.glyphs.queued} ${originLabel(origin)}`)} ${t.fg("muted", oneLine8(text))}`;
|
|
@@ -57665,7 +57941,10 @@ var init_run_indicator = __esm({
|
|
|
57665
57941
|
);
|
|
57666
57942
|
}
|
|
57667
57943
|
if (rows.length > 0) {
|
|
57668
|
-
|
|
57944
|
+
const run7 = msg().interactive.view.run;
|
|
57945
|
+
const now = steering.length > 0 ? this.nowKey() : void 0;
|
|
57946
|
+
const hint = now === void 0 ? run7.queueHint(t.glyphs.arrowUp) : run7.queueHintNow(t.glyphs.arrowUp, now);
|
|
57947
|
+
shown2.push(" " + t.fg("dim", hint));
|
|
57669
57948
|
}
|
|
57670
57949
|
this.setText(shown2.join("\n"));
|
|
57671
57950
|
}
|
|
@@ -57830,7 +58109,9 @@ function runInteractiveMode(runtime, context, options = {}) {
|
|
|
57830
58109
|
spinner: () => loader.frame,
|
|
57831
58110
|
subagent: (toolCallId2) => subagents.forToolCall(toolCallId2)
|
|
57832
58111
|
});
|
|
57833
|
-
const
|
|
58112
|
+
const enterMode = () => enterModeOf(runtime);
|
|
58113
|
+
const sendKeys = interruptKeys(keys, enterMode);
|
|
58114
|
+
const queueView = new QueueView(theme, sendKeys.now);
|
|
57834
58115
|
const loaderSlot = new Container();
|
|
57835
58116
|
const loader = new Loader(() => tui.requestRender(), {
|
|
57836
58117
|
theme,
|
|
@@ -57867,7 +58148,8 @@ function runInteractiveMode(runtime, context, options = {}) {
|
|
|
57867
58148
|
autocomplete: completion,
|
|
57868
58149
|
requestRender: () => tui.requestRender(),
|
|
57869
58150
|
...historyFile !== void 0 ? { historyFile } : {},
|
|
57870
|
-
onSubmit: (text) => submit(text, "enter")
|
|
58151
|
+
onSubmit: (text) => submit(text, "enter"),
|
|
58152
|
+
onChange: () => indicator.refreshHints()
|
|
57871
58153
|
});
|
|
57872
58154
|
tui.addChild(view);
|
|
57873
58155
|
tui.addChild(new Spacer());
|
|
@@ -57902,8 +58184,10 @@ function runInteractiveMode(runtime, context, options = {}) {
|
|
|
57902
58184
|
const backgroundKey = keyLabel(keys, "app.tasks.background");
|
|
57903
58185
|
const indicator = new RunIndicator({
|
|
57904
58186
|
...{ theme, loader, slot: loaderSlot, tools, render },
|
|
57905
|
-
...backgroundKey !== void 0 ? { backgroundKey } : {}
|
|
58187
|
+
...backgroundKey !== void 0 ? { backgroundKey } : {},
|
|
58188
|
+
...sendKeys.key !== void 0 ? { interruptKey: sendKeys.key } : {}
|
|
57906
58189
|
});
|
|
58190
|
+
Object.assign(indicator, { draft: () => !editor.isEmpty(), enterMode });
|
|
57907
58191
|
const setQueue = (steering, followUp) => {
|
|
57908
58192
|
status.setQueue(steering.length, followUp.length);
|
|
57909
58193
|
queueView.setQueue(steering, followUp);
|
|
@@ -58095,6 +58379,12 @@ function runInteractiveMode(runtime, context, options = {}) {
|
|
|
58095
58379
|
onPasteImage: () => void agentUi.paste(),
|
|
58096
58380
|
confirmMode,
|
|
58097
58381
|
submit: (text, via) => submit(text, via),
|
|
58382
|
+
enterWhileRunning: enterMode,
|
|
58383
|
+
interruptSend: interruptSender({
|
|
58384
|
+
session: () => session,
|
|
58385
|
+
takeImages: () => draftImages.splice(0),
|
|
58386
|
+
showHint
|
|
58387
|
+
}),
|
|
58098
58388
|
runCommand: (line2) => void runCommand2(line2),
|
|
58099
58389
|
exit: (code) => exit(code),
|
|
58100
58390
|
onInterrupted: (empty) => void rewind.afterInterrupt(empty),
|
|
@@ -58225,6 +58515,7 @@ var init_interactive_mode = __esm({
|
|
|
58225
58515
|
init_confirm_dialog();
|
|
58226
58516
|
init_config_ui();
|
|
58227
58517
|
init_key_dispatch();
|
|
58518
|
+
init_interrupt_send();
|
|
58228
58519
|
init_message_view();
|
|
58229
58520
|
init_pickers();
|
|
58230
58521
|
init_model_picker();
|
|
@@ -65078,19 +65369,19 @@ function redactedLookup(lookup) {
|
|
|
65078
65369
|
}
|
|
65079
65370
|
function axisPoints(trace) {
|
|
65080
65371
|
const t0 = trace.startedAt;
|
|
65081
|
-
const
|
|
65372
|
+
const windows = [];
|
|
65082
65373
|
for (const turn of trace.turns) {
|
|
65083
65374
|
const span = turnSpan(turn);
|
|
65084
|
-
if (span !== void 0)
|
|
65375
|
+
if (span !== void 0) windows.push([span.start - t0, span.end - t0]);
|
|
65085
65376
|
}
|
|
65086
65377
|
for (const aux of trace.aux)
|
|
65087
65378
|
if (aux.startedAt !== void 0)
|
|
65088
|
-
|
|
65089
|
-
|
|
65379
|
+
windows.push([aux.startedAt - t0, (aux.endedAt ?? aux.startedAt) - t0]);
|
|
65380
|
+
windows.sort((a, b) => a[0] - b[0] || a[1] - b[1]);
|
|
65090
65381
|
const points = [[0, 0]];
|
|
65091
65382
|
let raw = 0;
|
|
65092
65383
|
let mapped = 0;
|
|
65093
|
-
for (const [start, end] of
|
|
65384
|
+
for (const [start, end] of windows) {
|
|
65094
65385
|
if (end <= raw) continue;
|
|
65095
65386
|
const from = Math.max(start, raw);
|
|
65096
65387
|
if (from > raw) {
|