mocode-ai 1.2.2 → 1.2.3
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/dist/agent/core.js +14 -3
- package/dist/agent/spawn.js +1 -0
- package/dist/ui/intervention.js +2 -2
- package/dist/ui/layout.js +13 -12
- package/package.json +1 -1
package/dist/agent/core.js
CHANGED
|
@@ -337,9 +337,20 @@ export async function runAgentCore(opts) {
|
|
|
337
337
|
const modelStartedAt = Date.now();
|
|
338
338
|
const provider = safeProviderId(requestBaseURL);
|
|
339
339
|
emitTrace('model_start', { model: requestModel, provider });
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
340
|
+
// 动态注入(仅追加到 system 末尾,不触碰 staticBody 前缀 → 不破坏 prompt 缓存):
|
|
341
|
+
// - 开场分析:仅主线(step===0 且 !suppressOpeningAnalysis)注入——即"用户发一个任务后,
|
|
342
|
+
// agent 第一次模型调用"。子代理经 spawn.ts 传 suppressOpeningAnalysis:true 排除。
|
|
343
|
+
// - historyRebuilt:compact 恢复步;要求重新锚定目标。两者可叠加但互不串扰。
|
|
344
|
+
// .filter(Boolean) 保证空段不产生多余空行;后续 step 均为空串 → system 前缀稳定命中缓存。
|
|
345
|
+
// 安全保证:此段只拼进 requestHistory(新建对象),绝不回写 history[0],故不会跨 step/跨 turn 残留。
|
|
346
|
+
const dynamicSystemSuffix = [
|
|
347
|
+
(!opts.suppressOpeningAnalysis && step === 0)
|
|
348
|
+
? '## Opening analysis\nBegin your FIRST response of this turn with a brief analysis of the request and your planned approach (1-3 sentences, no filler), THEN start tool calls. This opening is the only place where pre-tool prose is expected; after it, work quietly with no narration between tool calls.'
|
|
349
|
+
: '',
|
|
350
|
+
historyRebuilt
|
|
351
|
+
? '## Post-compaction recovery\nContext was compacted before this request. Re-establish the current objective and unresolved work from retained evidence or the session note, avoid repeating completed investigation, and re-read exact file context before any dependent edit.'
|
|
352
|
+
: '',
|
|
353
|
+
].filter(Boolean).join('\n\n');
|
|
343
354
|
const systemMessage = history[0];
|
|
344
355
|
const requestHistory = dynamicSystemSuffix
|
|
345
356
|
&& systemMessage?.role === 'system'
|
package/dist/agent/spawn.js
CHANGED
|
@@ -225,6 +225,7 @@ export async function spawnAgent(opts) {
|
|
|
225
225
|
maxSteps,
|
|
226
226
|
toolsOverride,
|
|
227
227
|
contextState: localContextState,
|
|
228
|
+
suppressOpeningAnalysis: true, // 子代理不注入「开场分析」:仅主线面对用户的首次响应用
|
|
228
229
|
onToolOutcome: (tool, args) => {
|
|
229
230
|
if (tool === 'read_file' && typeof args.path === 'string')
|
|
230
231
|
readSet.add(args.path);
|
package/dist/ui/intervention.js
CHANGED
|
@@ -210,7 +210,7 @@ export async function promptIntervention(req) {
|
|
|
210
210
|
layout.resetScroll();
|
|
211
211
|
else
|
|
212
212
|
layout.repaintViewport();
|
|
213
|
-
// 恢复走时计时器(RUNNING 态):面板期间 stopTurnTimer 停了心跳,退出后恢复状态行
|
|
213
|
+
// 恢复走时计时器(RUNNING 态):面板期间 stopTurnTimer 停了心跳,退出后恢复状态行 80ms 刷新。
|
|
214
214
|
layout.startTurnTimerIfRunning();
|
|
215
215
|
}
|
|
216
216
|
function onKey(_str, key) {
|
|
@@ -339,7 +339,7 @@ export async function promptIntervention(req) {
|
|
|
339
339
|
return new Promise((res, rej) => {
|
|
340
340
|
resolve = res;
|
|
341
341
|
try {
|
|
342
|
-
// 进入面板:停 spinner(避免 onFrame 覆盖)+ 停走时计时器(避免 drawStatusBar
|
|
342
|
+
// 进入面板:停 spinner(避免 onFrame 覆盖)+ 停走时计时器(避免 drawStatusBar 80ms 心跳
|
|
343
343
|
// 把真光标拉到 runningCaretPos 覆盖 paintInput 的正确光标位)+ 禁鼠标框选(防拖拽 viewport 重画覆盖菜单)+ 回尾(若用户正滚动回看)
|
|
344
344
|
Spinner.pauseCurrent();
|
|
345
345
|
layout.stopTurnTimer();
|
package/dist/ui/layout.js
CHANGED
|
@@ -82,7 +82,7 @@ const SCROLL_LOCK_MS = 400; // 锁时长:覆盖 OS 缓冲残留 + 常规滚轮
|
|
|
82
82
|
let base = null;
|
|
83
83
|
// 运行态实时 token 用量(agent core 流式推送,轮末 repl 清 undefined)。
|
|
84
84
|
// composeModelLine 在 RUNNING 态把它画成 chip 放 context 进度条左侧;
|
|
85
|
-
// 不主动触发重画——RUNNING 态 turnTimer
|
|
85
|
+
// 不主动触发重画——RUNNING 态 turnTimer 80ms 心跳重画自然取最新值。
|
|
86
86
|
let liveUsage;
|
|
87
87
|
let statusText = '';
|
|
88
88
|
let spinnerFrame;
|
|
@@ -92,8 +92,8 @@ let turnTimer = null; // 走时刷新计时器(独立于 spinner):流式期间 s
|
|
|
92
92
|
* 驱动 paintInput setRegion(fh) 动态撑高脚栏;drawStatusBar 据此画 1/2 行 plan,
|
|
93
93
|
* 与 spinner/上线/输入/下线/model 行的 +1/+2/+3/+4/+5 偏移天然一致(contentBottom 自动重算)。 */
|
|
94
94
|
let planRows = 1;
|
|
95
|
-
let runningFrame = -1; // 运行态状态行 chip 心跳帧(
|
|
96
|
-
const RUNNING_FRAMES = ['
|
|
95
|
+
let runningFrame = -1; // 运行态状态行 chip 心跳帧(转圈帧 明灭);INPUT 态 -1 退回静态 ●
|
|
96
|
+
const RUNNING_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
97
97
|
// 运行态用户打字时暂停流式物理写:流式每个 token 要 cup 到 contentRow 写入,IME 候选窗逐光标移动跟踪会跟过去;
|
|
98
98
|
// 用户打字期间只喂缓冲、不物理写,光标留输入框;停手 USER_ACTIVE_PAUSE_MS 后 flush 重画缓冲内容。
|
|
99
99
|
let userActiveUntil = 0; // 打字活跃截止时刻(Date.now()+PAUSE);0=未活跃
|
|
@@ -1332,7 +1332,7 @@ function twoColumn(leftStr, leftW, rightStr, rightW, cols) {
|
|
|
1332
1332
|
* 示例:
|
|
1333
1333
|
* INPUT: ● 空闲
|
|
1334
1334
|
* 思考中: ⠹ 思考中… 0.5s
|
|
1335
|
-
* 运行心跳:
|
|
1335
|
+
* 运行心跳: ⠋ 生成中 0.5s
|
|
1336
1336
|
* 滚动回看: ● 空闲 历史 ↑3 (PgDn 回底) */
|
|
1337
1337
|
function composeSpinnerLine(status, cols) {
|
|
1338
1338
|
const spinning = mode === 'running' && runningFrame >= 0;
|
|
@@ -1361,10 +1361,11 @@ function composeSpinnerLine(status, cols) {
|
|
|
1361
1361
|
leadW = 1 + 1 + displayWidth(status.status) + (elapsed ? 1 + displayWidth(elapsed) : 0);
|
|
1362
1362
|
}
|
|
1363
1363
|
else if (spinning) {
|
|
1364
|
-
// 运行态心跳帧(流式输出中):帧 + 走时
|
|
1364
|
+
// 运行态心跳帧(流式输出中):帧 + 生成中 + 走时
|
|
1365
|
+
const label = '生成中';
|
|
1365
1366
|
const ePart = elapsed ? ` ${ui.dim}${elapsed}${ui.reset}` : '';
|
|
1366
|
-
lead = `${ui.bold}${ui.accent}${RUNNING_FRAMES[runningFrame]}${ui.reset}${ePart}`;
|
|
1367
|
-
leadW = 1 + (elapsed ? 1 + displayWidth(elapsed) : 0);
|
|
1367
|
+
lead = `${ui.bold}${ui.accent}${RUNNING_FRAMES[runningFrame]}${ui.reset} ${ui.dim}${label}${ui.reset}${ePart}`;
|
|
1368
|
+
leadW = 1 + 1 + displayWidth(label) + (elapsed ? 1 + displayWidth(elapsed) : 0);
|
|
1368
1369
|
}
|
|
1369
1370
|
else {
|
|
1370
1371
|
// INPUT 态:● + 状态文字(无走时)
|
|
@@ -1539,9 +1540,9 @@ export function setStatus(status, frame) {
|
|
|
1539
1540
|
drawStatusBar();
|
|
1540
1541
|
}
|
|
1541
1542
|
/**
|
|
1542
|
-
* 启走时刷新计时器:RUNNING 态每
|
|
1543
|
+
* 启走时刷新计时器:RUNNING 态每 80ms 重画状态行,使 composeStatus 重算 elapsed。
|
|
1543
1544
|
* 必要性:spinner 在首 token 到达即 stop,思考/正文流式期间状态行不再经 spinner 刷新;
|
|
1544
|
-
* 若走时只挂 spinner onFrame,流式那几十秒会冻住。此计时器独立续刷,与 spinner 80ms
|
|
1545
|
+
* 若走时只挂 spinner onFrame,流式那几十秒会冻住。此计时器独立续刷,与 spinner 80ms 同速,重叠幂等无妨。
|
|
1545
1546
|
* 非 TTY 不启(active=false 时 drawStatusBar 为 no-op)。
|
|
1546
1547
|
*/
|
|
1547
1548
|
function startTurnTimer() {
|
|
@@ -1552,10 +1553,10 @@ function startTurnTimer() {
|
|
|
1552
1553
|
turnTimer = setInterval(() => {
|
|
1553
1554
|
runningFrame = (runningFrame + 1) % RUNNING_FRAMES.length; // 推进心跳帧,让前导符跳动
|
|
1554
1555
|
drawStatusBar();
|
|
1555
|
-
},
|
|
1556
|
+
}, 80);
|
|
1556
1557
|
turnTimer.unref();
|
|
1557
1558
|
}
|
|
1558
|
-
/** 停走时计时器。enterInputMode / exitAltScreen 调;intervention 面板进入时也调(防 drawStatusBar
|
|
1559
|
+
/** 停走时计时器。enterInputMode / exitAltScreen 调;intervention 面板进入时也调(防 drawStatusBar 80ms 心跳把光标拉到 runningCaretPos,覆盖 paintInput 的正确光标位)。 */
|
|
1559
1560
|
export function stopTurnTimer() {
|
|
1560
1561
|
if (turnTimer) {
|
|
1561
1562
|
clearInterval(turnTimer);
|
|
@@ -1646,7 +1647,7 @@ export function clearLiveAtCursor() {
|
|
|
1646
1647
|
frameCol = 0;
|
|
1647
1648
|
}
|
|
1648
1649
|
/** 推送 / 清空运行态实时 token 用量(agent core 流式推送;repl 轮末清 undefined)。
|
|
1649
|
-
* 不触发重画:RUNNING 态 turnTimer
|
|
1650
|
+
* 不触发重画:RUNNING 态 turnTimer 80ms 心跳重画状态行,自然取到最新值。 */
|
|
1650
1651
|
export function setLiveUsage(u) {
|
|
1651
1652
|
liveUsage = u;
|
|
1652
1653
|
}
|