@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
|
@@ -280,6 +280,7 @@ function buildBaseSchema() {
|
|
|
280
280
|
logo: oneOf(["auto", "off"]),
|
|
281
281
|
animation: bool(),
|
|
282
282
|
restoreOnCancel: bool(),
|
|
283
|
+
enterWhileRunning: oneOf(["queue", "interrupt"]),
|
|
283
284
|
statusLine: oneOf(STATUS_LINE_MODES),
|
|
284
285
|
language: oneOf(LANGUAGE_SETTINGS),
|
|
285
286
|
replyLanguage: str(),
|
package/dist/config/key-docs.js
CHANGED
|
@@ -23,7 +23,14 @@ const IMPLICIT_DEFAULTS = {
|
|
|
23
23
|
codemode: { inlineBudget: DEFAULT_INLINE_BUDGET, requireStrict: false },
|
|
24
24
|
cache: { ...DEFAULT_CACHE_CONFIG },
|
|
25
25
|
request: { idleTimeoutMs: DEFAULT_IDLE_TIMEOUT_MS },
|
|
26
|
-
ui: {
|
|
26
|
+
ui: {
|
|
27
|
+
compact: false,
|
|
28
|
+
logo: "auto",
|
|
29
|
+
animation: true,
|
|
30
|
+
restoreOnCancel: true,
|
|
31
|
+
enterWhileRunning: "queue",
|
|
32
|
+
language: "auto",
|
|
33
|
+
},
|
|
27
34
|
// [W6-C0] 第六波键的缺省(行为由各批次实现)
|
|
28
35
|
memory: {
|
|
29
36
|
enabled: false,
|
package/dist/config/schema.js
CHANGED
|
@@ -260,6 +260,7 @@ export function validateConfig(value) {
|
|
|
260
260
|
"logo",
|
|
261
261
|
"animation",
|
|
262
262
|
"restoreOnCancel",
|
|
263
|
+
"enterWhileRunning",
|
|
263
264
|
...W5_UI_KEYS,
|
|
264
265
|
...W6_UI_KEYS,
|
|
265
266
|
], (s, p) => {
|
|
@@ -273,6 +274,7 @@ export function validateConfig(value) {
|
|
|
273
274
|
c.oneOf(s, "logo", p, ["auto", "off"]);
|
|
274
275
|
c.boolean(s, "animation", p);
|
|
275
276
|
c.boolean(s, "restoreOnCancel", p);
|
|
277
|
+
c.oneOf(s, "enterWhileRunning", p, ["queue", "interrupt"]);
|
|
276
278
|
checkUiW5(c, s, p);
|
|
277
279
|
checkUiW6(c, s, p);
|
|
278
280
|
});
|
|
@@ -34,6 +34,7 @@ const ROWS = [
|
|
|
34
34
|
row("ui.logo", "ui", "restart", "any"),
|
|
35
35
|
row("ui.statusLine", "ui", "now", "any"),
|
|
36
36
|
row("ui.restoreOnCancel", "ui", "nextSession", "any"),
|
|
37
|
+
row("ui.enterWhileRunning", "ui", "now", "any"),
|
|
37
38
|
row("ui.quietStartup", "ui", "restart", "any"),
|
|
38
39
|
row("ui.ascii", "ui", "restart", "any", { envOverride: "AMA_ASCII" }),
|
|
39
40
|
row("ui.language", "ui", "restart", "any", { envOverride: "AMA_LANG" }),
|
package/dist/config/types.d.ts
CHANGED
|
@@ -151,6 +151,8 @@ export interface UiConfig extends UiConfigW6 {
|
|
|
151
151
|
animation?: boolean;
|
|
152
152
|
/** 运行中 Esc 中断、本回合还没有任何输出时撤回该回合并回填原消息,缺省 true。 */
|
|
153
153
|
restoreOnCancel?: boolean;
|
|
154
|
+
/** 运行中按 Enter:queue(缺省)排队插话,interrupt 打断并立即发送(与 `app.message.interrupt` 互换)。 */
|
|
155
|
+
enterWhileRunning?: "queue" | "interrupt";
|
|
154
156
|
/** [W5-C0] 底部信息行(W5-A):缺省独立终端 full、嵌入宿主(有 profile)compact。 */
|
|
155
157
|
statusLine?: StatusLineMode;
|
|
156
158
|
}
|
package/dist/drivers/runner.js
CHANGED
|
@@ -135,6 +135,16 @@ export class ProcessRunner {
|
|
|
135
135
|
return this.deps;
|
|
136
136
|
}
|
|
137
137
|
}
|
|
138
|
+
/**
|
|
139
|
+
* 能中断单个回合、进程留着接着用的驱动(ACP `session/cancel`、Claude stream-json interrupt、Codex
|
|
140
|
+
* `turn/interrupt`);oneshot 每回合一个进程(中断 = 杀进程),宿主驱动不归 ama 管——这两种「打断并发送」退回排队。
|
|
141
|
+
*/
|
|
142
|
+
const TURN_INTERRUPT = new Set([
|
|
143
|
+
"acp",
|
|
144
|
+
"acp-adapter",
|
|
145
|
+
"claude-stream",
|
|
146
|
+
"codex-app-server",
|
|
147
|
+
]);
|
|
138
148
|
class ProcessHandle {
|
|
139
149
|
runner;
|
|
140
150
|
chosen;
|
|
@@ -209,8 +219,25 @@ class ProcessHandle {
|
|
|
209
219
|
}
|
|
210
220
|
this.chain = this.chain.then(() => this.runTurn(text));
|
|
211
221
|
}
|
|
212
|
-
|
|
213
|
-
|
|
222
|
+
/** 跟到链尾:回合进行中被 `interrupt` 接上的下一回合也算在这次运行里。 */
|
|
223
|
+
async wait() {
|
|
224
|
+
for (;;) {
|
|
225
|
+
const chain = this.chain;
|
|
226
|
+
const result = await chain;
|
|
227
|
+
if (chain === this.chain)
|
|
228
|
+
return result;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
/** 子 Agent 视图的「打断并发送」:中断当前回合,紧接着以 `text` 开下一回合。 */
|
|
232
|
+
async interrupt(text) {
|
|
233
|
+
const session = this.session;
|
|
234
|
+
if (this.stopped || !this.busy || session === undefined)
|
|
235
|
+
return false;
|
|
236
|
+
if (!TURN_INTERRUPT.has(this.chosen.driver.kind))
|
|
237
|
+
return false;
|
|
238
|
+
this.chain = this.chain.then(() => this.runTurn(text));
|
|
239
|
+
await session.cancel();
|
|
240
|
+
return true;
|
|
214
241
|
}
|
|
215
242
|
async stop() {
|
|
216
243
|
if (this.stopped)
|
package/dist/i18n/catalog.d.ts
CHANGED
|
@@ -497,6 +497,8 @@ declare const en: {
|
|
|
497
497
|
clearedCtrlC: string;
|
|
498
498
|
ctrlCAgain: string;
|
|
499
499
|
interrupted: string;
|
|
500
|
+
interruptSent: string;
|
|
501
|
+
nothingToSend: string;
|
|
500
502
|
toolsExpanded: string;
|
|
501
503
|
toolsCollapsed: string;
|
|
502
504
|
};
|
|
@@ -585,6 +587,7 @@ declare const en: {
|
|
|
585
587
|
host: string;
|
|
586
588
|
task: string;
|
|
587
589
|
plan: string;
|
|
590
|
+
interrupt: string;
|
|
588
591
|
};
|
|
589
592
|
planHandoff: string;
|
|
590
593
|
thinkingStreaming: (glyph: string, ellipsis: string) => string;
|
|
@@ -613,6 +616,8 @@ declare const en: {
|
|
|
613
616
|
thinking: string;
|
|
614
617
|
queueMore: (ellipsis: string, n: number) => string;
|
|
615
618
|
queueHint: (arrow: string) => string;
|
|
619
|
+
queueHintNow: (arrow: string, key: string) => string;
|
|
620
|
+
sendHint: (mode: "queue" | "interrupt", key: string) => string;
|
|
616
621
|
};
|
|
617
622
|
tool: {
|
|
618
623
|
interrupted: string;
|
|
@@ -1084,6 +1089,8 @@ declare const en: {
|
|
|
1084
1089
|
tasks: string;
|
|
1085
1090
|
agents: string;
|
|
1086
1091
|
paste: string;
|
|
1092
|
+
interruptArgs: string;
|
|
1093
|
+
interrupt: string;
|
|
1087
1094
|
exit: string;
|
|
1088
1095
|
config: string;
|
|
1089
1096
|
traceArgs: string;
|
|
@@ -1101,6 +1108,8 @@ declare const en: {
|
|
|
1101
1108
|
cacheUsage: string;
|
|
1102
1109
|
taskStopped: (id: string) => string;
|
|
1103
1110
|
tasksUsage: string;
|
|
1111
|
+
interruptUsage: string;
|
|
1112
|
+
interruptSent: (text: string) => string;
|
|
1104
1113
|
newSession: (id: string) => string;
|
|
1105
1114
|
resumed: (id: string, messages: number) => string;
|
|
1106
1115
|
forked: (id: string) => string;
|
|
@@ -1335,6 +1344,7 @@ declare const en: {
|
|
|
1335
1344
|
"ui.logo": string;
|
|
1336
1345
|
"ui.animation": string;
|
|
1337
1346
|
"ui.restoreOnCancel": string;
|
|
1347
|
+
"ui.enterWhileRunning": string;
|
|
1338
1348
|
"ui.statusLine": string;
|
|
1339
1349
|
"ui.language": string;
|
|
1340
1350
|
"ui.replyLanguage": string;
|
|
@@ -1781,6 +1791,8 @@ declare const en: {
|
|
|
1781
1791
|
steered: (taskId: string) => string;
|
|
1782
1792
|
queued: (taskId: string) => string;
|
|
1783
1793
|
resumed: (taskId: string) => string;
|
|
1794
|
+
interrupted: (taskId: string) => string;
|
|
1795
|
+
queuedNoInterrupt: (taskId: string) => string;
|
|
1784
1796
|
sendFailed: (message: string) => string;
|
|
1785
1797
|
stopped: (taskId: string) => string;
|
|
1786
1798
|
commandsHere: string;
|
|
@@ -2087,6 +2099,7 @@ declare const en: {
|
|
|
2087
2099
|
"ui.logo": string;
|
|
2088
2100
|
"ui.statusLine": string;
|
|
2089
2101
|
"ui.restoreOnCancel": string;
|
|
2102
|
+
"ui.enterWhileRunning": string;
|
|
2090
2103
|
"ui.quietStartup": string;
|
|
2091
2104
|
"ui.ascii": string;
|
|
2092
2105
|
"ui.language": string;
|
|
@@ -63,6 +63,8 @@ export declare const en: {
|
|
|
63
63
|
steered: (taskId: string) => string;
|
|
64
64
|
queued: (taskId: string) => string;
|
|
65
65
|
resumed: (taskId: string) => string;
|
|
66
|
+
interrupted: (taskId: string) => string;
|
|
67
|
+
queuedNoInterrupt: (taskId: string) => string;
|
|
66
68
|
sendFailed: (message: string) => string;
|
|
67
69
|
stopped: (taskId: string) => string;
|
|
68
70
|
commandsHere: string;
|
|
@@ -125,6 +127,8 @@ export declare const zh: {
|
|
|
125
127
|
steered: (taskId: string) => string;
|
|
126
128
|
queued: (taskId: string) => string;
|
|
127
129
|
resumed: (taskId: string) => string;
|
|
130
|
+
interrupted: (taskId: string) => string;
|
|
131
|
+
queuedNoInterrupt: (taskId: string) => string;
|
|
128
132
|
sendFailed: (message: string) => string;
|
|
129
133
|
stopped: (taskId: string) => string;
|
|
130
134
|
commandsHere: string;
|
|
@@ -64,6 +64,8 @@ export const en = {
|
|
|
64
64
|
steered: (taskId) => `Sent to ${taskId}; delivered when its current turn ends`,
|
|
65
65
|
queued: (taskId) => `Queued for ${taskId}; sent when its current run ends`,
|
|
66
66
|
resumed: (taskId) => `Sent to ${taskId}; it continues in the background`,
|
|
67
|
+
interrupted: (taskId) => `Interrupted ${taskId}; your message starts its next turn now`,
|
|
68
|
+
queuedNoInterrupt: (taskId) => `${taskId} cannot be interrupted here; queued, sent when its current run ends`,
|
|
67
69
|
sendFailed: (message) => `Could not send: ${message}`,
|
|
68
70
|
stopped: (taskId) => `Stopped ${taskId}`,
|
|
69
71
|
commandsHere: "Only /tasks stop and /tasks bg work here; press Esc to go back for other commands",
|
|
@@ -126,6 +128,8 @@ export const zh = {
|
|
|
126
128
|
steered: (taskId) => `已发给 ${taskId},本轮结束后送达`,
|
|
127
129
|
queued: (taskId) => `已排队,${taskId} 本次运行结束后发送`,
|
|
128
130
|
resumed: (taskId) => `已发给 ${taskId},在后台继续`,
|
|
131
|
+
interrupted: (taskId) => `已打断 ${taskId},这条消息立即开始新一轮`,
|
|
132
|
+
queuedNoInterrupt: (taskId) => `${taskId} 不支持打断,已排队,本次运行结束后发送`,
|
|
129
133
|
sendFailed: (message) => `发送失败:${message}`,
|
|
130
134
|
stopped: (taskId) => `已停止 ${taskId}`,
|
|
131
135
|
commandsHere: "这里只能用 /tasks stop 与 /tasks bg;其它命令按 Esc 返回后输入",
|
|
@@ -55,6 +55,7 @@ export declare const en: {
|
|
|
55
55
|
"ui.logo": string;
|
|
56
56
|
"ui.animation": string;
|
|
57
57
|
"ui.restoreOnCancel": string;
|
|
58
|
+
"ui.enterWhileRunning": string;
|
|
58
59
|
"ui.statusLine": string;
|
|
59
60
|
"ui.language": string;
|
|
60
61
|
"ui.replyLanguage": string;
|
|
@@ -202,6 +203,7 @@ export declare const zh: {
|
|
|
202
203
|
"ui.logo": string;
|
|
203
204
|
"ui.animation": string;
|
|
204
205
|
"ui.restoreOnCancel": string;
|
|
206
|
+
"ui.enterWhileRunning": string;
|
|
205
207
|
"ui.statusLine": string;
|
|
206
208
|
"ui.language": string;
|
|
207
209
|
"ui.replyLanguage": string;
|
|
@@ -102,6 +102,7 @@ const keysEn = {
|
|
|
102
102
|
"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",
|
|
103
103
|
"ui.animation": "false: the spinner stays still while running and redraws only when seconds change; the startup logo does not animate",
|
|
104
104
|
"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",
|
|
105
|
+
"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",
|
|
105
106
|
"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)",
|
|
106
107
|
"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",
|
|
107
108
|
"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)",
|
|
@@ -224,6 +225,7 @@ const keysZh = {
|
|
|
224
225
|
"ui.logo": "启动头的 AMA 字符画:auto 在终端宽 48 列以上时画,off 只显示信息行",
|
|
225
226
|
"ui.animation": "false:运行中 spinner 静止,只在秒数变化时重绘;启动字符画不播放动画",
|
|
226
227
|
"ui.restoreOnCancel": "运行中 Esc 中断、本回合还没有任何回复或工具调用时,撤回该回合并把原消息放回输入框",
|
|
228
|
+
"ui.enterWhileRunning": "运行中按 Enter:queue(缺省)排队插话,等下一个投递点送达;interrupt 打断当前回合并立即发送。app.message.interrupt 键(缺省 Ctrl+X)做另一种",
|
|
227
229
|
"ui.statusLine": "底部信息行:full 两行(速率行 + 状态行),compact 一行;运行时 Ctrl+G 或 /statusline 切换(第五波 W5-A 起生效)",
|
|
228
230
|
"ui.language": "界面语言:auto 按 LC_ALL / LC_MESSAGES / LANG 判断(zh* 为中文,其余英文),zh,en;AMA_LANG、--lang 覆盖;只影响界面,发给模型的文本固定英文",
|
|
229
231
|
"ui.replyLanguage": "模型回复语言(如 Chinese):会话开始在 rules 节末尾追加一句英文规则;不设时零字节变化;只认用户级(第六波起生效)",
|
|
@@ -55,6 +55,7 @@ export declare const en: {
|
|
|
55
55
|
"ui.logo": string;
|
|
56
56
|
"ui.animation": string;
|
|
57
57
|
"ui.restoreOnCancel": string;
|
|
58
|
+
"ui.enterWhileRunning": string;
|
|
58
59
|
"ui.statusLine": string;
|
|
59
60
|
"ui.language": string;
|
|
60
61
|
"ui.replyLanguage": string;
|
|
@@ -314,6 +315,7 @@ export declare const zh: {
|
|
|
314
315
|
"ui.logo": string;
|
|
315
316
|
"ui.animation": string;
|
|
316
317
|
"ui.restoreOnCancel": string;
|
|
318
|
+
"ui.enterWhileRunning": string;
|
|
317
319
|
"ui.statusLine": string;
|
|
318
320
|
"ui.language": string;
|
|
319
321
|
"ui.replyLanguage": string;
|
|
@@ -19,6 +19,7 @@ export declare const en: {
|
|
|
19
19
|
host: string;
|
|
20
20
|
task: string;
|
|
21
21
|
plan: string;
|
|
22
|
+
interrupt: string;
|
|
22
23
|
};
|
|
23
24
|
planHandoff: string;
|
|
24
25
|
thinkingStreaming: (glyph: string, ellipsis: string) => string;
|
|
@@ -47,6 +48,10 @@ export declare const en: {
|
|
|
47
48
|
thinking: string;
|
|
48
49
|
queueMore: (ellipsis: string, n: number) => string;
|
|
49
50
|
queueHint: (arrow: string) => string;
|
|
51
|
+
/** 有排队的插话时(`key` = 立即送出它们的键:专用键,或 interrupt 模式下的 Enter)。 */
|
|
52
|
+
queueHintNow: (arrow: string, key: string) => string;
|
|
53
|
+
/** 输入框有字时:Enter 与专用键各做什么(`ui.enterWhileRunning`)。 */
|
|
54
|
+
sendHint: (mode: "queue" | "interrupt", key: string) => string;
|
|
50
55
|
};
|
|
51
56
|
tool: {
|
|
52
57
|
interrupted: string;
|
|
@@ -85,6 +90,7 @@ export declare const zh: {
|
|
|
85
90
|
host: string;
|
|
86
91
|
task: string;
|
|
87
92
|
plan: string;
|
|
93
|
+
interrupt: string;
|
|
88
94
|
};
|
|
89
95
|
planHandoff: string;
|
|
90
96
|
thinkingStreaming: (glyph: string, ellipsis: string) => string;
|
|
@@ -113,6 +119,8 @@ export declare const zh: {
|
|
|
113
119
|
thinking: string;
|
|
114
120
|
queueMore: (ellipsis: string, n: number) => string;
|
|
115
121
|
queueHint: (arrow: string) => string;
|
|
122
|
+
queueHintNow: (arrow: string, key: string) => string;
|
|
123
|
+
sendHint: (mode: "interrupt" | "queue", key: string) => string;
|
|
116
124
|
};
|
|
117
125
|
tool: {
|
|
118
126
|
interrupted: string;
|
|
@@ -20,6 +20,7 @@ export const en = {
|
|
|
20
20
|
host: "host",
|
|
21
21
|
task: "subagent notice",
|
|
22
22
|
plan: "plan",
|
|
23
|
+
interrupt: "interrupt",
|
|
23
24
|
},
|
|
24
25
|
planHandoff: "Start executing the approved plan",
|
|
25
26
|
thinkingStreaming: (glyph, ellipsis) => `${glyph} Thinking${ellipsis}`,
|
|
@@ -48,6 +49,12 @@ export const en = {
|
|
|
48
49
|
thinking: "Thinking",
|
|
49
50
|
queueMore: (ellipsis, n) => `${ellipsis} ${n} more`,
|
|
50
51
|
queueHint: (arrow) => `Alt+${arrow} take back · Esc refill and interrupt`,
|
|
52
|
+
/** 有排队的插话时(`key` = 立即送出它们的键:专用键,或 interrupt 模式下的 Enter)。 */
|
|
53
|
+
queueHintNow: (arrow, key) => `Alt+${arrow} take back · ${key} send now · Esc refill and interrupt`,
|
|
54
|
+
/** 输入框有字时:Enter 与专用键各做什么(`ui.enterWhileRunning`)。 */
|
|
55
|
+
sendHint: (mode, key) => mode === "queue"
|
|
56
|
+
? `Enter queue · ${key} interrupt & send`
|
|
57
|
+
: `Enter interrupt & send · ${key} queue`,
|
|
51
58
|
},
|
|
52
59
|
tool: {
|
|
53
60
|
interrupted: "interrupted",
|
|
@@ -86,6 +93,7 @@ export const zh = {
|
|
|
86
93
|
host: "宿主",
|
|
87
94
|
task: "子 Agent 通知",
|
|
88
95
|
plan: "计划",
|
|
96
|
+
interrupt: "打断",
|
|
89
97
|
},
|
|
90
98
|
planHandoff: "按批准的计划开始执行",
|
|
91
99
|
thinkingStreaming: (glyph, ellipsis) => `${glyph} 思考中${ellipsis}`,
|
|
@@ -114,6 +122,8 @@ export const zh = {
|
|
|
114
122
|
thinking: "思考中",
|
|
115
123
|
queueMore: (ellipsis, n) => `${ellipsis} 另 ${n} 条`,
|
|
116
124
|
queueHint: (arrow) => `Alt+${arrow} 取回 · Esc 回填并中断`,
|
|
125
|
+
queueHintNow: (arrow, key) => `Alt+${arrow} 取回 · ${key} 立即发送 · Esc 回填并中断`,
|
|
126
|
+
sendHint: (mode, key) => mode === "queue" ? `Enter 排队 · ${key} 打断并发送` : `Enter 打断并发送 · ${key} 排队`,
|
|
117
127
|
},
|
|
118
128
|
tool: {
|
|
119
129
|
interrupted: "已中断",
|
|
@@ -49,6 +49,8 @@ export declare const en: {
|
|
|
49
49
|
clearedCtrlC: string;
|
|
50
50
|
ctrlCAgain: string;
|
|
51
51
|
interrupted: string;
|
|
52
|
+
interruptSent: string;
|
|
53
|
+
nothingToSend: string;
|
|
52
54
|
toolsExpanded: string;
|
|
53
55
|
toolsCollapsed: string;
|
|
54
56
|
};
|
|
@@ -140,6 +142,7 @@ export declare const en: {
|
|
|
140
142
|
host: string;
|
|
141
143
|
task: string;
|
|
142
144
|
plan: string;
|
|
145
|
+
interrupt: string;
|
|
143
146
|
};
|
|
144
147
|
planHandoff: string;
|
|
145
148
|
thinkingStreaming: (glyph: string, ellipsis: string) => string;
|
|
@@ -168,6 +171,8 @@ export declare const en: {
|
|
|
168
171
|
thinking: string;
|
|
169
172
|
queueMore: (ellipsis: string, n: number) => string;
|
|
170
173
|
queueHint: (arrow: string) => string;
|
|
174
|
+
queueHintNow: (arrow: string, key: string) => string;
|
|
175
|
+
sendHint: (mode: "queue" | "interrupt", key: string) => string;
|
|
171
176
|
};
|
|
172
177
|
tool: {
|
|
173
178
|
interrupted: string;
|
|
@@ -292,6 +297,8 @@ export declare const zh: {
|
|
|
292
297
|
clearedCtrlC: string;
|
|
293
298
|
ctrlCAgain: string;
|
|
294
299
|
interrupted: string;
|
|
300
|
+
interruptSent: string;
|
|
301
|
+
nothingToSend: string;
|
|
295
302
|
toolsExpanded: string;
|
|
296
303
|
toolsCollapsed: string;
|
|
297
304
|
};
|
|
@@ -380,6 +387,7 @@ export declare const zh: {
|
|
|
380
387
|
host: string;
|
|
381
388
|
task: string;
|
|
382
389
|
plan: string;
|
|
390
|
+
interrupt: string;
|
|
383
391
|
};
|
|
384
392
|
planHandoff: string;
|
|
385
393
|
thinkingStreaming: (glyph: string, ellipsis: string) => string;
|
|
@@ -408,6 +416,8 @@ export declare const zh: {
|
|
|
408
416
|
thinking: string;
|
|
409
417
|
queueMore: (ellipsis: string, n: number) => string;
|
|
410
418
|
queueHint: (arrow: string) => string;
|
|
419
|
+
queueHintNow: (arrow: string, key: string) => string;
|
|
420
|
+
sendHint: (mode: "interrupt" | "queue", key: string) => string;
|
|
411
421
|
};
|
|
412
422
|
tool: {
|
|
413
423
|
interrupted: string;
|
|
@@ -20,6 +20,7 @@ export const en = {
|
|
|
20
20
|
keyHints: [
|
|
21
21
|
"Enter send (while running = steer) Alt+Enter queue after this turn Shift+Enter / Ctrl+J newline",
|
|
22
22
|
"Esc interrupt (queued messages go back to the editor) Alt+↑ take back the last queued message",
|
|
23
|
+
"Ctrl+X (while running) interrupt the current turn and send the input now, queued steers first; ui.enterWhileRunning: interrupt swaps it with Enter",
|
|
23
24
|
"Idle Esc Esc: empty input = rewind (/rewind), with text = clear (↑ to restore)",
|
|
24
25
|
"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",
|
|
25
26
|
"Approval: 1–3 or ↑↓ Enter to choose, y allow a allow for this session n / Esc deny v full input",
|
|
@@ -62,6 +63,8 @@ export const en = {
|
|
|
62
63
|
clearedCtrlC: "Input cleared · press Ctrl+C again to quit",
|
|
63
64
|
ctrlCAgain: "Press Ctrl+C again to quit",
|
|
64
65
|
interrupted: "Interrupted",
|
|
66
|
+
interruptSent: "Interrupted · sending now",
|
|
67
|
+
nothingToSend: "Nothing to send",
|
|
65
68
|
toolsExpanded: "Tool output: expanded",
|
|
66
69
|
toolsCollapsed: "Tool output: collapsed",
|
|
67
70
|
},
|
|
@@ -152,6 +155,7 @@ export const zh = {
|
|
|
152
155
|
keyHints: [
|
|
153
156
|
"Enter 发送(运行中 = 插话) Alt+Enter 排到本轮之后 Shift+Enter / Ctrl+J 换行",
|
|
154
157
|
"Esc 中断(排队消息回填编辑器) Alt+↑ 取回最后一条排队消息",
|
|
158
|
+
"Ctrl+X(运行中)打断当前回合并立即发送输入(排队的插话在前);ui.enterWhileRunning: interrupt 时与 Enter 互换",
|
|
155
159
|
"空闲时 Esc Esc:输入框为空 = 回滚(/rewind),有字 = 清空(↑ 取回)",
|
|
156
160
|
"Shift+Tab / Tab(输入为空时)切换权限模式(进入 Bypass 前确认) Ctrl+L 模型 Ctrl+T 思考级别 Ctrl+O 展开工具输出与思考",
|
|
157
161
|
"审批:1–3 或 ↑↓ Enter 选择,y 允许 a 本会话允许同类 n / Esc 拒绝 v 完整输入",
|
|
@@ -192,6 +196,8 @@ export const zh = {
|
|
|
192
196
|
clearedCtrlC: "已清空输入 · 再按 Ctrl+C 退出",
|
|
193
197
|
ctrlCAgain: "再按一次 Ctrl+C 退出",
|
|
194
198
|
interrupted: "已中断",
|
|
199
|
+
interruptSent: "已打断,立即发送",
|
|
200
|
+
nothingToSend: "没有可发送的内容",
|
|
195
201
|
toolsExpanded: "工具输出:展开",
|
|
196
202
|
toolsCollapsed: "工具输出:折叠",
|
|
197
203
|
},
|
|
@@ -36,6 +36,8 @@ export declare const en: {
|
|
|
36
36
|
tasks: string;
|
|
37
37
|
agents: string;
|
|
38
38
|
paste: string;
|
|
39
|
+
interruptArgs: string;
|
|
40
|
+
interrupt: string;
|
|
39
41
|
exit: string;
|
|
40
42
|
config: string;
|
|
41
43
|
traceArgs: string;
|
|
@@ -54,6 +56,8 @@ export declare const en: {
|
|
|
54
56
|
cacheUsage: string;
|
|
55
57
|
taskStopped: (id: string) => string;
|
|
56
58
|
tasksUsage: string;
|
|
59
|
+
interruptUsage: string;
|
|
60
|
+
interruptSent: (text: string) => string;
|
|
57
61
|
newSession: (id: string) => string;
|
|
58
62
|
resumed: (id: string, messages: number) => string;
|
|
59
63
|
forked: (id: string) => string;
|
|
@@ -228,6 +232,8 @@ export declare const zh: {
|
|
|
228
232
|
tasks: string;
|
|
229
233
|
agents: string;
|
|
230
234
|
paste: string;
|
|
235
|
+
interruptArgs: string;
|
|
236
|
+
interrupt: string;
|
|
231
237
|
exit: string;
|
|
232
238
|
config: string;
|
|
233
239
|
traceArgs: string;
|
|
@@ -245,6 +251,8 @@ export declare const zh: {
|
|
|
245
251
|
cacheUsage: string;
|
|
246
252
|
taskStopped: (id: string) => string;
|
|
247
253
|
tasksUsage: string;
|
|
254
|
+
interruptUsage: string;
|
|
255
|
+
interruptSent: (text: string) => string;
|
|
248
256
|
newSession: (id: string) => string;
|
|
249
257
|
resumed: (id: string, messages: number) => string;
|
|
250
258
|
forked: (id: string) => string;
|
|
@@ -36,6 +36,8 @@ export const en = {
|
|
|
36
36
|
tasks: "Sub-agent tasks: status, output, stop, background",
|
|
37
37
|
agents: "Sub-agent types and external agents (installed, version)",
|
|
38
38
|
paste: "Paste an image from the clipboard (Ctrl+V)",
|
|
39
|
+
interruptArgs: "<text>",
|
|
40
|
+
interrupt: "Interrupt the current turn and send this now, queued steers first (Ctrl+X)",
|
|
39
41
|
exit: "Exit",
|
|
40
42
|
config: "Settings panel; key=value sets one item directly (user level)",
|
|
41
43
|
traceArgs: "[task id]",
|
|
@@ -54,6 +56,8 @@ export const en = {
|
|
|
54
56
|
cacheUsage: "usage: /cache [warm off|streaming|idle | fingerprint]",
|
|
55
57
|
taskStopped: (id) => `Stopped ${id}`,
|
|
56
58
|
tasksUsage: "usage: /tasks [id] | /tasks stop <id> | /tasks bg [id]",
|
|
59
|
+
interruptUsage: "usage: /interrupt <text>",
|
|
60
|
+
interruptSent: (text) => `Interrupted; sending now: ${text}`,
|
|
57
61
|
newSession: (id) => `New session ${id}`,
|
|
58
62
|
resumed: (id, messages) => `Resumed session ${id} (${plural(messages, "message")})`,
|
|
59
63
|
forked: (id) => `Forked to new session ${id}`,
|
|
@@ -279,6 +283,8 @@ export const zh = {
|
|
|
279
283
|
tasks: "子 Agent 任务:状态、输出、停止、转后台",
|
|
280
284
|
agents: "子 Agent 类型与外部 Agent(安装状态、版本)",
|
|
281
285
|
paste: "粘贴剪贴板里的图片(Ctrl+V)",
|
|
286
|
+
interruptArgs: "<文本>",
|
|
287
|
+
interrupt: "打断当前回合并立即发送这段文字,排队的插话在前(Ctrl+X)",
|
|
282
288
|
exit: "退出",
|
|
283
289
|
config: "设置面板;key=value 直接设一项(用户级)",
|
|
284
290
|
traceArgs: "[任务 id]",
|
|
@@ -296,6 +302,8 @@ export const zh = {
|
|
|
296
302
|
cacheUsage: "用法:/cache [warm off|streaming|idle | fingerprint]",
|
|
297
303
|
taskStopped: (id) => `已停止 ${id}`,
|
|
298
304
|
tasksUsage: "用法:/tasks [id] | /tasks stop <id> | /tasks bg [id]",
|
|
305
|
+
interruptUsage: "用法:/interrupt <文本>",
|
|
306
|
+
interruptSent: (text) => `已打断,立即发送:${text}`,
|
|
299
307
|
newSession: (id) => `已新建会话 ${id}`,
|
|
300
308
|
resumed: (id, messages) => `已恢复会话 ${id}(${messages} 条消息)`,
|
|
301
309
|
forked: (id) => `已分叉到新会话 ${id}`,
|
|
@@ -28,6 +28,7 @@ export declare const en: {
|
|
|
28
28
|
"ui.logo": string;
|
|
29
29
|
"ui.statusLine": string;
|
|
30
30
|
"ui.restoreOnCancel": string;
|
|
31
|
+
"ui.enterWhileRunning": string;
|
|
31
32
|
"ui.quietStartup": string;
|
|
32
33
|
"ui.ascii": string;
|
|
33
34
|
"ui.language": string;
|
|
@@ -205,6 +206,7 @@ export declare const zh: {
|
|
|
205
206
|
"ui.logo": string;
|
|
206
207
|
"ui.statusLine": string;
|
|
207
208
|
"ui.restoreOnCancel": string;
|
|
209
|
+
"ui.enterWhileRunning": string;
|
|
208
210
|
"ui.quietStartup": string;
|
|
209
211
|
"ui.ascii": string;
|
|
210
212
|
"ui.language": string;
|
|
@@ -28,6 +28,7 @@ export const en = {
|
|
|
28
28
|
"ui.logo": "Startup logo",
|
|
29
29
|
"ui.statusLine": "Status line",
|
|
30
30
|
"ui.restoreOnCancel": "Restore on cancel",
|
|
31
|
+
"ui.enterWhileRunning": "Enter while running",
|
|
31
32
|
"ui.quietStartup": "Startup screen",
|
|
32
33
|
"ui.ascii": "ASCII glyphs",
|
|
33
34
|
"ui.language": "Interface language",
|
|
@@ -199,6 +200,7 @@ export const zh = {
|
|
|
199
200
|
"ui.logo": "启动字符画",
|
|
200
201
|
"ui.statusLine": "底部信息行",
|
|
201
202
|
"ui.restoreOnCancel": "中断后放回原消息",
|
|
203
|
+
"ui.enterWhileRunning": "运行中按 Enter",
|
|
202
204
|
"ui.quietStartup": "启动画面",
|
|
203
205
|
"ui.ascii": "ASCII 字形",
|
|
204
206
|
"ui.language": "界面语言",
|
|
@@ -67,6 +67,7 @@ export const BUILTIN_COMMANDS = [
|
|
|
67
67
|
command("tasks", "tasks", "[id] | stop <id> | bg [id]"),
|
|
68
68
|
command("agents", "agents"),
|
|
69
69
|
command("paste", "paste"),
|
|
70
|
+
command("interrupt", "interrupt", { key: "interruptArgs" }),
|
|
70
71
|
command("exit", "exit"),
|
|
71
72
|
// [W6-C0] 第六波(W6-S / W6-T1 / W6-M 实现)
|
|
72
73
|
command("config", "config", "[key=value]"),
|
|
@@ -246,6 +247,16 @@ export async function runSlashCommand(line, ctx) {
|
|
|
246
247
|
return planCommand(session, args, ctx);
|
|
247
248
|
case "tasks":
|
|
248
249
|
return { kind: "handled", message: await tasksCommand(session, args) };
|
|
250
|
+
case "interrupt": {
|
|
251
|
+
// 打断并立即发送:运行中中止当前回合、以「排队的插话 + 本条」开新回合;空闲时就是普通提示
|
|
252
|
+
if (args === "")
|
|
253
|
+
throw new AmaError("invalid_arguments", msg().report.command.interruptUsage);
|
|
254
|
+
const { isStreaming, isCompacting } = session.state;
|
|
255
|
+
if (!isStreaming && !isCompacting)
|
|
256
|
+
return { kind: "prompt", text: args };
|
|
257
|
+
void session.prompt(args, { interrupt: true }).catch(() => undefined);
|
|
258
|
+
return { kind: "handled", message: msg().report.command.interruptSent(args) };
|
|
259
|
+
}
|
|
249
260
|
case "agents":
|
|
250
261
|
return { kind: "handled", message: describeAgents(session.state.sessionId) };
|
|
251
262
|
case "paste": {
|
|
@@ -376,6 +376,7 @@ export class AgentUi {
|
|
|
376
376
|
close: () => this.closeView(),
|
|
377
377
|
stop: (id) => stopTask(this.deps.session().state.sessionId, id),
|
|
378
378
|
background: (id) => this.deps.session().backgroundTask(id, "user"),
|
|
379
|
+
enterMode: () => this.deps.area?.ui().enterWhileRunning === "interrupt" ? "interrupt" : "queue",
|
|
379
380
|
messages: {
|
|
380
381
|
...(ui.showThinking !== undefined ? { showThinking: ui.showThinking } : {}),
|
|
381
382
|
...(ui.markdown !== undefined ? { markdown: ui.markdown } : {}),
|
|
@@ -18,6 +18,8 @@
|
|
|
18
18
|
* 所查看的任务在等审批时标题显示「等待审批」,审批框照常以覆盖层弹在视图上面。
|
|
19
19
|
* [W7-C] `Ctrl+B`(`app.tasks.background`)转后台正在看的任务(只对前台任务有效,否则落回编辑器);
|
|
20
20
|
* 视图里另认 `/tasks bg [id]`。
|
|
21
|
+
* [打断并发送] `Ctrl+X`(`app.message.interrupt`)= 打断该子 Agent 当前回合并立即发送(`registry.message` 的
|
|
22
|
+
* interrupt);外部 Agent 的驱动不能中断回合时退回排队并提示。`ui.enterWhileRunning: "interrupt"` 时与 Enter 互换。
|
|
21
23
|
*/
|
|
22
24
|
import { type Component, type Focusable, type Keybindings, type Theme } from "../../tui.js";
|
|
23
25
|
import { type TaskSource } from "./agent-bar.js";
|
|
@@ -43,6 +45,8 @@ export interface AgentViewDeps {
|
|
|
43
45
|
background?(taskId: string): string[];
|
|
44
46
|
/** 消息区的显示选项(思考块、Markdown、紧凑)。 */
|
|
45
47
|
messages?: Omit<MessageViewOptions, "theme">;
|
|
48
|
+
/** `ui.enterWhileRunning`:`interrupt` 时 Enter 打断并发送、专用键排队。 */
|
|
49
|
+
enterMode?(): "queue" | "interrupt";
|
|
46
50
|
}
|
|
47
51
|
export declare class AgentView implements Component, Focusable {
|
|
48
52
|
private taskId;
|
|
@@ -67,6 +71,7 @@ export declare class AgentView implements Component, Focusable {
|
|
|
67
71
|
/** 每秒:运行中的工具重画耗时。 */
|
|
68
72
|
tick(): void;
|
|
69
73
|
private switchTo;
|
|
74
|
+
private enterInterrupts;
|
|
70
75
|
private submit;
|
|
71
76
|
handleInput(data: string): void;
|
|
72
77
|
private scroll;
|
|
@@ -18,6 +18,8 @@
|
|
|
18
18
|
* 所查看的任务在等审批时标题显示「等待审批」,审批框照常以覆盖层弹在视图上面。
|
|
19
19
|
* [W7-C] `Ctrl+B`(`app.tasks.background`)转后台正在看的任务(只对前台任务有效,否则落回编辑器);
|
|
20
20
|
* 视图里另认 `/tasks bg [id]`。
|
|
21
|
+
* [打断并发送] `Ctrl+X`(`app.message.interrupt`)= 打断该子 Agent 当前回合并立即发送(`registry.message` 的
|
|
22
|
+
* interrupt);外部 Agent 的驱动不能中断回合时退回排队并提示。`ui.enterWhileRunning: "interrupt"` 时与 Enter 互换。
|
|
21
23
|
*/
|
|
22
24
|
import { msg } from "../../i18n/index.js";
|
|
23
25
|
import { Editor, isPrintableText, parseKey, truncateToWidth, visibleWidth, } from "../../tui.js";
|
|
@@ -47,7 +49,7 @@ export class AgentView {
|
|
|
47
49
|
maxVisibleLines: 4,
|
|
48
50
|
placeholder: msg().agents.view.placeholder(taskId),
|
|
49
51
|
requestRender: () => deps.render(),
|
|
50
|
-
onSubmit: (text) => void this.submit(text),
|
|
52
|
+
onSubmit: (text) => void this.submit(text, this.enterInterrupts()),
|
|
51
53
|
});
|
|
52
54
|
this.attach();
|
|
53
55
|
}
|
|
@@ -137,7 +139,10 @@ export class AgentView {
|
|
|
137
139
|
this.attach();
|
|
138
140
|
this.deps.onSwitch?.(next);
|
|
139
141
|
}
|
|
140
|
-
|
|
142
|
+
enterInterrupts() {
|
|
143
|
+
return this.deps.enterMode?.() === "interrupt";
|
|
144
|
+
}
|
|
145
|
+
async submit(text, interrupt = false) {
|
|
141
146
|
const m = msg().agents.view;
|
|
142
147
|
const trimmed = text.trim();
|
|
143
148
|
if (trimmed === "")
|
|
@@ -167,7 +172,7 @@ export class AgentView {
|
|
|
167
172
|
try {
|
|
168
173
|
if (registry === undefined)
|
|
169
174
|
throw new Error(m.unknown(taskId));
|
|
170
|
-
const reply = await registry.message(taskId, text);
|
|
175
|
+
const reply = await registry.message(taskId, text, interrupt);
|
|
171
176
|
this.flash = m[reply](taskId);
|
|
172
177
|
}
|
|
173
178
|
catch (error) {
|
|
@@ -188,6 +193,12 @@ export class AgentView {
|
|
|
188
193
|
return;
|
|
189
194
|
}
|
|
190
195
|
}
|
|
196
|
+
if (keys.matches(data, "app.message.interrupt") && !this.editor.isCompletionOpen) {
|
|
197
|
+
const text = this.editor.takeSubmission();
|
|
198
|
+
if (text !== null)
|
|
199
|
+
void this.submit(text, !this.enterInterrupts());
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
191
202
|
if (keys.matches(data, "tui.select.cancel") && !this.editor.isCompletionOpen) {
|
|
192
203
|
if (!empty)
|
|
193
204
|
this.editor.clear();
|