@zhushanwen/zcode-subagent-cli 0.4.4 → 0.6.0
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/{chunk-DLLNMF45.js → chunk-PWNJ5JYZ.js} +105 -278
- package/dist/index.cjs +105 -278
- package/dist/index.d.cts +17 -36
- package/dist/index.d.ts +17 -36
- package/dist/index.js +1 -1
- package/dist/main.cjs +105 -278
- package/dist/main.js +1 -1
- package/package.json +4 -3
package/dist/main.cjs
CHANGED
|
@@ -41,16 +41,6 @@ var ZCODE_APPSERVER_STDERR_TAIL_CHARS = 400;
|
|
|
41
41
|
var ZCODE_APPSERVER_STDERR_TAIL_BUFFER_CHARS = 2048;
|
|
42
42
|
var ZCODE_APPSERVER_TURN_READ_TIMEOUT_MS = 5e3;
|
|
43
43
|
var ZCODE_APPSERVER_TURN_CLOSE_TIMEOUT_MS = 1500;
|
|
44
|
-
var ZCODE_TURN_IDLE_TIMEOUT_ENV = "TAIJI_ZCODE_TURN_IDLE_TIMEOUT_MS";
|
|
45
|
-
var ZCODE_TURN_MAX_TIMEOUT_ENV = "TAIJI_ZCODE_TURN_MAX_TIMEOUT_MS";
|
|
46
|
-
var ZCODE_TURN_IDLE_TIMEOUT_MS = 18e5;
|
|
47
|
-
var ZCODE_TURN_MAX_TIMEOUT_MS = 36e5;
|
|
48
|
-
function parseZcodeTurnTimeoutEnv(raw) {
|
|
49
|
-
if (raw === void 0 || raw === "") return { state: "unset" };
|
|
50
|
-
const parsed = Number(raw);
|
|
51
|
-
if (!Number.isFinite(parsed)) return { state: "invalid" };
|
|
52
|
-
return { state: "valid", ms: parsed };
|
|
53
|
-
}
|
|
54
44
|
var ZCODE_APPSERVER_STOP_TIMEOUT_MS = 3e3;
|
|
55
45
|
var ZCODE_APPSERVER_ABORT_GRACE_MS = 3e3;
|
|
56
46
|
var ZCODE_APPSERVER_STOP_TIMEOUT_ENV = "TAIJI_ZCODE_TEST_STOP_TIMEOUT_MS";
|
|
@@ -380,6 +370,7 @@ const os = require('node:os');
|
|
|
380
370
|
|
|
381
371
|
const CLI_PATH = process.env.ZCODE_ENG_CLI_PATH;
|
|
382
372
|
const V2_PATH = process.env.ZCODE_ENG_V2_CONFIG || path.join(os.homedir(), '.zcode', 'v2', 'config.json');
|
|
373
|
+
const PROVIDER_CONFIG_PATH = process.env.ZCODE_ENG_PROVIDER_CONFIG || path.join(os.homedir(), '.zcode', 'v2', 'provider_config.json');
|
|
383
374
|
const CONFIG_PATH = path.join(os.homedir(), '.zcode', 'cli', 'config.json');
|
|
384
375
|
|
|
385
376
|
// \u5408\u5E76\u5F62\u6001\uFF1A\u771F\u5B9E cli config \u539F\u6837\uFF08model/plugins/mcp/subagents \u7B49 worker \u7EE7\u627F\u9762\u4E0D\u53D8\uFF09
|
|
@@ -388,6 +379,10 @@ const CONFIG_PATH = path.join(os.homedir(), '.zcode', 'cli', 'config.json');
|
|
|
388
379
|
// \u914D\u7F6E\uFF082026-08-25 \u4E8B\u6545\uFF1A\u6B8B\u7559\u65E7 key \u538B\u8FC7\u65B0\u51ED\u636E\u81F4 turn 0 401\uFF09\uFF0C\u6545\u4E0D\u53D6 real \u4F18\u5148\u3002
|
|
389
380
|
// model.main \u7F3A\u5931\u65F6\u53EA\u4ECE v2 \u900F\u4F20\uFF08v2 \u4E5F\u6CA1\u6709\u5219\u4E0D\u4F2A\u9020\u2014\u2014CLI \u7F3A\u7701\u89E3\u6790\u81EA\u4F1A\u843D\u5230\u6CE8\u518C\u8868
|
|
390
381
|
// \u53EF\u7528\u6A21\u578B\uFF1Bplan \u5BB6\u65CF id \u5DF2\u4E0D\u53EF\u7528\uFF0C\u4E0D\u518D\u515C\u5E95\u4F2A\u9020\uFF09\u3002
|
|
382
|
+
// [D3 \u987A\u5E26\u53D1\u73B0 6] provider_config.json\uFF08\u5F15\u64CE\u4FA7\u6A21\u578B\u6821\u9A8C\u6E90\uFF09\u8865\u6CE8\u5165\uFF1A\u4EC5\u5B58\u5728\u4E8E
|
|
383
|
+
// providerRules \u7684\u4E2A\u4EBA provider\uFF08v2 \u5B57\u5178\u672A\u7269\u5316\uFF09\u4E0D\u5728\u6CE8\u5165\u96C6 \u2192 app-server \u6CE8\u518C\u8868
|
|
384
|
+
// \u7F3A\u6761\u76EE\uFF0C\u663E\u5F0F\u6A21\u578B\u9996\u6D3E\u5373\u62A5\u300CProvider Registry \u4E2D\u4E0D\u5B58\u5728 Model\u300D\u3002\u4E3A\u5E26 apiKey+baseUrl
|
|
385
|
+
// \u4E14 v2/real \u5747\u7F3A\u5931\u7684 rule \u5408\u6210 cli-config \u6761\u76EE\uFF08\u5F62\u72B6\u7167\u6284\u73B0\u7F51\u4E2A\u4EBA\u6761\u76EE\uFF09\u3002
|
|
391
386
|
// \u8FD4\u56DE null = \u65E0\u53EF\u6CE8\u5165\u51ED\u636E\uFF08v2 \u65E0 provider \u6761\u76EE\uFF09\u2014\u2014\u4E0D patch\uFF0C\u8BA9\u539F\u751F\u62A5\u9519\u900F\u51FA\u3002
|
|
392
387
|
// \u8BFB\u6E90\u7ECF readOrig \u95F4\u63A5\u53D6\uFF1Apatch \u524D\u9996\u8C03 = fs.readFileSync \u672C\u4F53\uFF1Bpatch \u540E = \u539F\u51FD\u6570
|
|
393
388
|
// \uFF08\u9632 patch \u540E\u7684\u9012\u5F52\u81EA\u8C03\u7528\uFF09\u3002
|
|
@@ -405,6 +400,7 @@ function injectedConfigText() {
|
|
|
405
400
|
}
|
|
406
401
|
return null;
|
|
407
402
|
}
|
|
403
|
+
const realProviders = real.provider && typeof real.provider === 'object' ? real.provider : {};
|
|
408
404
|
const v2Providers = v2.provider && typeof v2.provider === 'object' ? v2.provider : {};
|
|
409
405
|
const hasKey = (entry) => entry && typeof entry === 'object'
|
|
410
406
|
&& entry.options && typeof entry.options.apiKey === 'string' && entry.options.apiKey !== '';
|
|
@@ -412,9 +408,60 @@ function injectedConfigText() {
|
|
|
412
408
|
for (const [id, entry] of Object.entries(v2Providers)) {
|
|
413
409
|
if (hasKey(entry)) injectable[id] = entry;
|
|
414
410
|
}
|
|
411
|
+
// provider_config.json \u8865\u6CE8\u5165\uFF08\u8BFB\u53D6\u5931\u8D25\u9759\u9ED8\u964D\u7EA7\u2014\u2014\u6821\u9A8C\u6E90\u7F3A\u5E2D\u65F6\u5F15\u64CE\u4FA7\u6821\u9A8C\u540C\u6837\u4E0D\u53EF
|
|
412
|
+
// \u7528\uFF0C\u6CE8\u5165\u9762\u7EF4\u6301 v2-only \u73B0\u72B6\uFF1BproviderRules \u7F3A\u5931\u4E0D\u6784\u6210\u51ED\u636E\u9519\u8BEF\uFF09\u3002
|
|
413
|
+
try {
|
|
414
|
+
const pc = JSON.parse(readOrig(PROVIDER_CONFIG_PATH, 'utf8'));
|
|
415
|
+
const pcCfg = pc && typeof pc.config === 'object' && pc.config ? pc.config : {};
|
|
416
|
+
const pcr = typeof pcCfg.providerConfigRules === 'object' && pcCfg.providerConfigRules ? pcCfg.providerConfigRules : {};
|
|
417
|
+
const rules = Array.isArray(pcr.providerRules) ? pcr.providerRules : [];
|
|
418
|
+
const mcr = typeof pcCfg.modelConfigRules === 'object' && pcCfg.modelConfigRules ? pcCfg.modelConfigRules : {};
|
|
419
|
+
const modelRules = Array.isArray(mcr.providerModelRules) ? mcr.providerModelRules : [];
|
|
420
|
+
const modelMeta = {};
|
|
421
|
+
for (const mr of modelRules) {
|
|
422
|
+
if (!mr || typeof mr !== 'object' || typeof mr.providerId !== 'string' || typeof mr.modelId !== 'string') continue;
|
|
423
|
+
(modelMeta[mr.providerId] = modelMeta[mr.providerId] || []).push(mr);
|
|
424
|
+
}
|
|
425
|
+
for (const rule of rules) {
|
|
426
|
+
if (!rule || typeof rule !== 'object') continue;
|
|
427
|
+
const id = typeof rule.providerId === 'string' ? rule.providerId : '';
|
|
428
|
+
const cfg = rule.config && typeof rule.config === 'object' ? rule.config : {};
|
|
429
|
+
const access = cfg.access && typeof cfg.access === 'object' ? cfg.access : {};
|
|
430
|
+
const api = cfg.api && typeof cfg.api === 'object' ? cfg.api : {};
|
|
431
|
+
// v2/real \u5DF2\u6709 \u2192 \u4E0D\u91CD\u590D\u5408\u6210\uFF08v2 \u6761\u76EE\u66F4\u5168\uFF0C\u6574\u6761\u4F18\u5148\u8BED\u4E49\u4E0D\u53D7\u5F71\u54CD\uFF09
|
|
432
|
+
if (!id || injectable[id] || realProviders[id]) continue;
|
|
433
|
+
// hasKey \u7EAA\u5F8B\u540C\u6B3E\uFF1A\u65E0 apiKey \u4E0D\u5408\u6210\uFF1B\u65E0 baseUrl\uFF08endpoint \u7531\u6A21\u677F\u63D0\u4F9B\u7684\u5F62\u6001\uFF09
|
|
434
|
+
// \u4E0D\u5408\u6210\u2014\u2014\u6B8B\u7F3A\u6761\u76EE\u6BD4\u4E0D\u6CE8\u5165\u66F4\u7CDF\uFF0C\u539F\u751F\u300C\u4E0D\u5B58\u5728 Model\u300D\u62A5\u9519\u7167\u65E7\u900F\u51FA
|
|
435
|
+
if (typeof access.apiKey !== 'string' || access.apiKey === '') continue;
|
|
436
|
+
if (typeof api.baseUrl !== 'string' || api.baseUrl === '') continue;
|
|
437
|
+
const order = Array.isArray(cfg.modelOrder) ? cfg.modelOrder
|
|
438
|
+
: (Array.isArray(cfg.personalModelIds) ? cfg.personalModelIds : []);
|
|
439
|
+
const models = {};
|
|
440
|
+
for (const mr of modelMeta[id] || []) {
|
|
441
|
+
const mrCfg = mr.config && typeof mr.config === 'object' ? mr.config : {};
|
|
442
|
+
if (mrCfg.enabled === false) continue; // \u7981\u7528\u6A21\u578B\u4E0D\u8FDB\u6CE8\u518C\u8868\uFF08GUI \u8BED\u4E49\u4E00\u81F4\uFF09
|
|
443
|
+
const props = mrCfg.properties && typeof mrCfg.properties === 'object' ? mrCfg.properties : {};
|
|
444
|
+
models[mr.modelId] = typeof props.contextWindow === 'number'
|
|
445
|
+
? { limit: { context: props.contextWindow } }
|
|
446
|
+
: {};
|
|
447
|
+
}
|
|
448
|
+
for (const mid of order) {
|
|
449
|
+
if (typeof mid === 'string' && mid !== '' && !(mid in models)) models[mid] = {};
|
|
450
|
+
}
|
|
451
|
+
injectable[id] = {
|
|
452
|
+
name: typeof rule.providerName === 'string' ? rule.providerName : id,
|
|
453
|
+
// provider_config.json \u4E0D\u643A\u5E26\u534F\u8BAE\u5F62\u6001\u2014\u2014standard-personal \u7EC4\u4EE5 openai-compatible
|
|
454
|
+
// \u4E3A\u591A\u6570\u5148\u4F8B\uFF1B\u9519\u914D\u65F6\u8BF7\u6C42\u671F\u534F\u8BAE\u9519\u8BEF\u53EF\u89C1\uFF08\u4E0D\u963B\u585E\u6CE8\u518C\u8868\u88C5\u8F7D\uFF09\uFF0C\u771F\u673A\u6F02\u79FB\u4FE1\u53F7\u660E\u786E
|
|
455
|
+
kind: 'openai-compatible',
|
|
456
|
+
options: { apiKey: access.apiKey, baseURL: api.baseUrl },
|
|
457
|
+
source: 'custom',
|
|
458
|
+
models: models,
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
} catch { /* provider_config \u7F3A\u5931/\u635F\u574F \u2192 \u8865\u6CE8\u5165\u9762\u9759\u9ED8\u964D\u7EA7\uFF08v2 \u6CE8\u5165\u4E0D\u53D7\u5F71\u54CD\uFF09 */ }
|
|
415
462
|
if (Object.keys(injectable).length === 0) return null;
|
|
416
463
|
const merged = { ...real };
|
|
417
|
-
merged.provider = { ...
|
|
464
|
+
merged.provider = { ...realProviders, ...injectable };
|
|
418
465
|
if ((!merged.model || typeof merged.model !== 'object' || !merged.model.main)
|
|
419
466
|
&& v2.model && typeof v2.model === 'object' && v2.model.main) {
|
|
420
467
|
merged.model = { ...(merged.model || {}), main: v2.model.main };
|
|
@@ -1376,66 +1423,6 @@ function extractResumeTotalTokens(resumeResult) {
|
|
|
1376
1423
|
}
|
|
1377
1424
|
return acc.has ? acc.total : void 0;
|
|
1378
1425
|
}
|
|
1379
|
-
var TurnTimeoutError = class extends Error {
|
|
1380
|
-
kind;
|
|
1381
|
-
elapsed;
|
|
1382
|
-
lastEventAt;
|
|
1383
|
-
thresholdMs;
|
|
1384
|
-
constructor(kind, parts) {
|
|
1385
|
-
super(
|
|
1386
|
-
kind === "idle" ? `zcode turn idle \u5224\u6B7B\uFF1A\u8FDE\u7EED ${parts.thresholdMs}ms \u672A\u89C2\u5BDF\u5230\u672C turn \u4EFB\u4F55\u4E8B\u4EF6\uFF08session/event \u4E0E v4/telemetry/event \u5747\u9759\u9ED8\uFF09\uFF0C\u7EC8\u6001\u672A\u5230\u8FBE\u3002` + (parts.lastEventAt === void 0 ? "\u672C\u8F6E\u81EA send \u8D77\u672A\u89C2\u5BDF\u5230\u4EFB\u4F55\u4E8B\u4EF6\uFF08\u8FDB\u7A0B\u5047\u6B7B/\u534F\u8BAE\u9759\u9ED8\u5F62\u6001\uFF09\u3002" : `\u6700\u540E\u4E8B\u4EF6\u65F6\u523B ${new Date(parts.lastEventAt).toISOString()}\u3002`) + "\u6062\u590D\u6307\u5F15\uFF1A\u76F4\u63A5\u91CD\u8DD1\u672C\u4EFB\u52A1\uFF1B\u82E5\u6301\u7EED\u51FA\u73B0\uFF0C\u68C0\u67E5 ZCode \u684C\u9762\u7AEF\u6A21\u578B\u8FDE\u901A\u6027\u6216\u6539\u7528 engine: pi\u3002" : `zcode turn \u603B\u4E0A\u754C\u5224\u6B7B\uFF1A${parts.thresholdMs}ms \u5185\u672A\u89C2\u5BDF\u5230\u7EC8\u6001\uFF08turn.terminal \u4E0E\u6536\u5C3E\u5E27\u5747\u672A\u5230\u8FBE\uFF1Bidle \u5224\u5B9A\u672A\u89E6\u53D1\u2014\u2014\u4E8B\u4EF6\u6D41\u4ECD\u6D3B\u8DC3\uFF0Cchatty-wedge \u5F62\u6001\uFF09\u3002` + (parts.lastEventAt === void 0 ? "" : `\u6700\u540E\u4E8B\u4EF6\u65F6\u523B ${new Date(parts.lastEventAt).toISOString()}\u3002`) + `\u6062\u590D\u6307\u5F15\uFF1A\u76F4\u63A5\u91CD\u8DD1\u672C\u4EFB\u52A1\uFF1B\u82E5\u672C\u4EFB\u52A1\u5C5E\u5408\u6CD5\u8D85\u957F\u4EFB\u52A1\uFF08\u9884\u671F\u8D85\u8FC7 ${parts.thresholdMs}ms \u603B\u4E0A\u754C\uFF09\uFF0C\u91CD\u8DD1\u524D\u8BBE ${ZCODE_TURN_MAX_TIMEOUT_ENV} \u4E3A\u66F4\u5927\u6BEB\u79D2\u503C\uFF0C\u6216\u8BBE 0 \u5173\u95ED\u603B\u4E0A\u754C\uFF08\u5173\u95ED\u540E chatty \u5F62\u6001\u4E0D\u518D\u81EA\u52A8\u56DE\u6536\uFF0C\u9759\u9ED8 wedged \u4ECD\u7531 idle \u5C42\u515C\u5E95\u2014\u2014\u81EA\u884C\u6743\u8861\uFF09\u3002`
|
|
1387
|
-
);
|
|
1388
|
-
this.name = "TurnTimeoutError";
|
|
1389
|
-
this.kind = kind;
|
|
1390
|
-
this.elapsed = parts.elapsed;
|
|
1391
|
-
this.lastEventAt = parts.lastEventAt;
|
|
1392
|
-
this.thresholdMs = parts.thresholdMs;
|
|
1393
|
-
}
|
|
1394
|
-
};
|
|
1395
|
-
function clearTurnTimers(turn) {
|
|
1396
|
-
if (turn.idleTimer !== void 0) {
|
|
1397
|
-
clearTimeout(turn.idleTimer);
|
|
1398
|
-
turn.idleTimer = void 0;
|
|
1399
|
-
}
|
|
1400
|
-
if (turn.ceilingTimer !== void 0) {
|
|
1401
|
-
clearTimeout(turn.ceilingTimer);
|
|
1402
|
-
turn.ceilingTimer = void 0;
|
|
1403
|
-
}
|
|
1404
|
-
}
|
|
1405
|
-
function armTurnTimer(onFire, ms) {
|
|
1406
|
-
const timer = setTimeout(onFire, ms);
|
|
1407
|
-
if (typeof timer.unref === "function") timer.unref();
|
|
1408
|
-
return timer;
|
|
1409
|
-
}
|
|
1410
|
-
function resolveTurnTimerMs(parts) {
|
|
1411
|
-
let value;
|
|
1412
|
-
let source;
|
|
1413
|
-
if (parts.explicit !== void 0) {
|
|
1414
|
-
value = parts.explicit;
|
|
1415
|
-
source = "\u663E\u5F0F\u4F20\u53C2";
|
|
1416
|
-
} else {
|
|
1417
|
-
const raw = process.env[parts.envName];
|
|
1418
|
-
const parsed = parseZcodeTurnTimeoutEnv(raw);
|
|
1419
|
-
if (parsed.state === "valid") {
|
|
1420
|
-
value = parsed.ms;
|
|
1421
|
-
source = `env ${parts.envName}=${raw}`;
|
|
1422
|
-
} else {
|
|
1423
|
-
if (parsed.state === "invalid") {
|
|
1424
|
-
logger2.warn(
|
|
1425
|
-
`[session-channel] ${parts.envName}="${raw}" \u975E\u6CD5\uFF08\u5E94\u4E3A\u6BEB\u79D2\u6570\u5B57\uFF09\u2014\u2014\u56DE\u843D\u9ED8\u8BA4 ${parts.fallbackMs}ms\uFF08${parts.label}\uFF09\u3002\u8BBE\u7F6E\u6B63\u6BEB\u79D2\u503C\u8986\u76D6\uFF0C\u6216 0 \u663E\u5F0F\u5173\u95ED`
|
|
1426
|
-
);
|
|
1427
|
-
}
|
|
1428
|
-
value = parts.fallbackMs;
|
|
1429
|
-
source = "\u9ED8\u8BA4\u503C";
|
|
1430
|
-
}
|
|
1431
|
-
}
|
|
1432
|
-
if (value <= 0) {
|
|
1433
|
-
logger2.warn(
|
|
1434
|
-
`[session-channel] zcode turn ${parts.label}\u5DF2\u5173\u95ED\uFF08${source}\uFF09\u2014\u2014${parts.offConsequence}\u3002\u8BBE\u6B63\u6BEB\u79D2\u503C\uFF08env ${parts.envName} \u6216\u663E\u5F0F\u4F20\u53C2\uFF09\u6062\u590D\u56DE\u6536\u5C42`
|
|
1435
|
-
);
|
|
1436
|
-
}
|
|
1437
|
-
return value;
|
|
1438
|
-
}
|
|
1439
1426
|
var SessionChannel = class {
|
|
1440
1427
|
conn;
|
|
1441
1428
|
/** sessionId → 在途 turn(终态落定后仍保留到 runTurn 收尾——收尾帧数据吸收窗口)。 */
|
|
@@ -1461,23 +1448,23 @@ var SessionChannel = class {
|
|
|
1461
1448
|
),
|
|
1462
1449
|
// 连接崩溃收割:进程死亡(崩溃/我方杀链)立即 fail 全部在途 turn——
|
|
1463
1450
|
// onClose 契约保证触发时连接层在途 request 已全部 reject,此处补齐
|
|
1464
|
-
// 「无在途 request 的 turn
|
|
1451
|
+
// 「无在途 request 的 turn」的收割(否则在途 turn 失去全部终局来源)
|
|
1465
1452
|
conn.onClose((reason) => this.failAllTurns(`app-server ${reason}`))
|
|
1466
1453
|
];
|
|
1467
1454
|
}
|
|
1468
1455
|
/**
|
|
1469
1456
|
* [P0-1 U5/D7] dispose 前收割 + 退订:「退订 = 不会再有事件」在结构上蕴含「在途
|
|
1470
1457
|
* turn 不应再等」——close 缺失/被吞没形态(onClose 收割主路径未触发)下,在途
|
|
1471
|
-
* turn 于退订前经既有 failAllTurns
|
|
1472
|
-
*
|
|
1473
|
-
*
|
|
1474
|
-
*
|
|
1475
|
-
*
|
|
1458
|
+
* turn 于退订前经既有 failAllTurns 收敛为明确失败(设计 §3.4 退化路径闭合;
|
|
1459
|
+
* race 窗口在引擎 shutdownRuntimeAndDisposeChannel,量级与 awaitConnFinalized
|
|
1460
|
+
* 同源 ZCODE_APPSERVER_HARVEST_GRACE_MS)。幂等:与 onClose 收割先到者赢
|
|
1461
|
+
* (turn.fail 的 settled 守卫——已落定 turn 不改写),activeTurns 已空则 no-op。
|
|
1462
|
+
* 不影响连接自身生命周期(R4)。
|
|
1476
1463
|
*/
|
|
1477
1464
|
dispose() {
|
|
1478
1465
|
this.disposed = true;
|
|
1479
1466
|
this.failAllTurns(
|
|
1480
|
-
"zcode session channel \u5DF2 dispose\uFF1A\u8FDE\u63A5 close \u4E8B\u4EF6\u672A\u5728\u6536\u5272\u7A97\u53E3\u5185\u5230\u8FBE\uFF0C\u5728\u9014 turn \u4E8E\u9000\u8BA2\u524D\u6536\u5272\u4E3A\u660E\u786E\u5931\u8D25\
|
|
1467
|
+
"zcode session channel \u5DF2 dispose\uFF1A\u8FDE\u63A5 close \u4E8B\u4EF6\u672A\u5728\u6536\u5272\u7A97\u53E3\u5185\u5230\u8FBE\uFF0C\u5728\u9014 turn \u4E8E\u9000\u8BA2\u524D\u6536\u5272\u4E3A\u660E\u786E\u5931\u8D25\u3002\u6062\u590D\u6307\u5F15\uFF1A\u76F4\u63A5\u91CD\u8DD1\u672C\u4EFB\u52A1\u3002"
|
|
1481
1468
|
);
|
|
1482
1469
|
for (const off of this.offHandlers.splice(0)) off();
|
|
1483
1470
|
}
|
|
@@ -1607,7 +1594,6 @@ var SessionChannel = class {
|
|
|
1607
1594
|
...opened.turn.lastTerminalError !== void 0 ? { lastTerminalError: opened.turn.lastTerminalError } : {}
|
|
1608
1595
|
};
|
|
1609
1596
|
} finally {
|
|
1610
|
-
opened.stopTimers();
|
|
1611
1597
|
this.activeTurns.delete(sessionId);
|
|
1612
1598
|
await this.closeSession(sessionId);
|
|
1613
1599
|
}
|
|
@@ -1628,7 +1614,7 @@ var SessionChannel = class {
|
|
|
1628
1614
|
onTextDelta: opts.onTextDelta,
|
|
1629
1615
|
onThinkingDelta: opts.onThinkingDelta,
|
|
1630
1616
|
// [PR3] tool 执行期活性回调(SessionTurnCallbacks.onActivity 注释——宿主侧
|
|
1631
|
-
//
|
|
1617
|
+
// 的工具执行期刷新面)
|
|
1632
1618
|
onActivity: opts.onActivity
|
|
1633
1619
|
},
|
|
1634
1620
|
settled: false,
|
|
@@ -1638,83 +1624,25 @@ var SessionChannel = class {
|
|
|
1638
1624
|
terminal: void 0,
|
|
1639
1625
|
lastTerminalStatus: void 0,
|
|
1640
1626
|
lastTerminalError: void 0,
|
|
1641
|
-
|
|
1642
|
-
ceilingMs: 0,
|
|
1643
|
-
startedAt: Date.now(),
|
|
1644
|
-
lastEventAt: void 0,
|
|
1645
|
-
idleTimer: void 0,
|
|
1646
|
-
ceilingTimer: void 0,
|
|
1647
|
-
// 装配占位:下方 timer 创建后重绑(settle/fail 需要清理两 timer)
|
|
1627
|
+
// 装配占位:下方重绑(settle/fail 闭包引用 turn 本体)
|
|
1648
1628
|
settle: () => {
|
|
1649
1629
|
},
|
|
1650
1630
|
fail: () => {
|
|
1651
|
-
},
|
|
1652
|
-
fireTimeout: () => {
|
|
1653
1631
|
}
|
|
1654
1632
|
};
|
|
1655
|
-
turn.idleMs = resolveTurnTimerMs({
|
|
1656
|
-
explicit: opts.idleTimeoutMs,
|
|
1657
|
-
envName: ZCODE_TURN_IDLE_TIMEOUT_ENV,
|
|
1658
|
-
fallbackMs: ZCODE_TURN_IDLE_TIMEOUT_MS,
|
|
1659
|
-
label: "idle \u4E3B\u5224\u5B9A",
|
|
1660
|
-
offConsequence: "\u9759\u9ED8 wedged\uFF08\u65E0\u4E8B\u4EF6\uFF09\u5F62\u6001\u5C06\u65E0\u81EA\u52A8\u56DE\u6536\uFF0C\u4EFB\u52A1\u53EF\u80FD\u6302\u5230\u5BBF\u4E3B\u8FDB\u7A0B\u9000\u51FA"
|
|
1661
|
-
});
|
|
1662
|
-
turn.ceilingMs = resolveTurnTimerMs({
|
|
1663
|
-
explicit: opts.turnTimeoutMs,
|
|
1664
|
-
envName: ZCODE_TURN_MAX_TIMEOUT_ENV,
|
|
1665
|
-
fallbackMs: ZCODE_TURN_MAX_TIMEOUT_MS,
|
|
1666
|
-
label: "\u603B\u4E0A\u754C",
|
|
1667
|
-
offConsequence: "chatty-wedge\uFF08\u6709\u4E8B\u4EF6\u65E0\u7EC8\u6001\uFF09\u5F62\u6001\u5C06\u65E0\u81EA\u52A8\u56DE\u6536\uFF0C\u4EC5\u5269 idle \u9759\u9ED8\u5224\u5B9A\u515C\u5E95"
|
|
1668
|
-
});
|
|
1669
|
-
const fireTimeout = (kind) => {
|
|
1670
|
-
if (turn.settled) return;
|
|
1671
|
-
turn.settled = true;
|
|
1672
|
-
clearTurnTimers(turn);
|
|
1673
|
-
this.activeTurns.delete(sessionId);
|
|
1674
|
-
rejectDone(
|
|
1675
|
-
new TurnTimeoutError(kind, {
|
|
1676
|
-
thresholdMs: kind === "idle" ? turn.idleMs : turn.ceilingMs,
|
|
1677
|
-
elapsed: Date.now() - turn.startedAt,
|
|
1678
|
-
lastEventAt: turn.lastEventAt
|
|
1679
|
-
})
|
|
1680
|
-
);
|
|
1681
|
-
};
|
|
1682
|
-
turn.fireTimeout = fireTimeout;
|
|
1683
|
-
if (turn.idleMs > 0) {
|
|
1684
|
-
turn.idleTimer = armTurnTimer(() => turn.fireTimeout("idle"), turn.idleMs);
|
|
1685
|
-
}
|
|
1686
|
-
if (turn.ceilingMs > 0) {
|
|
1687
|
-
turn.ceilingTimer = armTurnTimer(
|
|
1688
|
-
() => turn.fireTimeout("ceiling"),
|
|
1689
|
-
turn.ceilingMs
|
|
1690
|
-
);
|
|
1691
|
-
}
|
|
1692
1633
|
turn.settle = (t) => {
|
|
1693
1634
|
if (turn.settled) return;
|
|
1694
1635
|
turn.settled = true;
|
|
1695
1636
|
turn.terminal = t;
|
|
1696
|
-
clearTurnTimers(turn);
|
|
1697
1637
|
resolveDone(t);
|
|
1698
1638
|
};
|
|
1699
1639
|
turn.fail = (err) => {
|
|
1700
1640
|
if (turn.settled) return;
|
|
1701
1641
|
turn.settled = true;
|
|
1702
|
-
clearTurnTimers(turn);
|
|
1703
1642
|
rejectDone(err);
|
|
1704
1643
|
};
|
|
1705
1644
|
this.activeTurns.set(sessionId, turn);
|
|
1706
|
-
return { turn, done
|
|
1707
|
-
}
|
|
1708
|
-
/**
|
|
1709
|
-
* idle 主判定的事件刷新(P0-1 D1):本 turn 任何事件到达即重置 idle 倒数——
|
|
1710
|
-
* 活跃事件流零误杀的结构保证。总上界不受影响(固定倒数)。已落定 turn 无
|
|
1711
|
-
* timer 可刷新(只剩 lastEventAt 记账)。
|
|
1712
|
-
*/
|
|
1713
|
-
refreshIdle(turn) {
|
|
1714
|
-
turn.lastEventAt = Date.now();
|
|
1715
|
-
if (turn.settled || turn.idleTimer === void 0) return;
|
|
1716
|
-
clearTimeout(turn.idleTimer);
|
|
1717
|
-
turn.idleTimer = armTurnTimer(() => turn.fireTimeout("idle"), turn.idleMs);
|
|
1645
|
+
return { turn, done };
|
|
1718
1646
|
}
|
|
1719
1647
|
lookupTurn(sessionId) {
|
|
1720
1648
|
if (sessionId !== void 0) return this.activeTurns.get(sessionId);
|
|
@@ -1744,7 +1672,6 @@ var SessionChannel = class {
|
|
|
1744
1672
|
if (turn === void 0) return;
|
|
1745
1673
|
const payload = isRecord3(params) && isRecord3(params.payload) ? params.payload : void 0;
|
|
1746
1674
|
if (payload === void 0) return;
|
|
1747
|
-
this.refreshIdle(turn);
|
|
1748
1675
|
if (this.applyFinalFrame(turn, payload)) return;
|
|
1749
1676
|
if (!this.applyStreamDelta(turn, payload) && !turn.settled) {
|
|
1750
1677
|
turn.callbacks.onActivity?.();
|
|
@@ -1861,7 +1788,6 @@ var SessionChannel = class {
|
|
|
1861
1788
|
applyStreamChunkTelemetry(params) {
|
|
1862
1789
|
const turn = this.lookupTurn(extractPushSessionId(params));
|
|
1863
1790
|
if (turn === void 0 || turn.settled) return;
|
|
1864
|
-
this.refreshIdle(turn);
|
|
1865
1791
|
for (const key of ["chunk", "text", "content"]) {
|
|
1866
1792
|
const v = params[key];
|
|
1867
1793
|
if (typeof v === "string" && v !== "") {
|
|
@@ -2102,7 +2028,10 @@ var ZcodeEngine = class {
|
|
|
2102
2028
|
// --mode build/edit/plan/yolo 原生权限档位
|
|
2103
2029
|
permissionMode: "native",
|
|
2104
2030
|
// [D3-④] 无 turn_end 语义,轮数上限不可兑现(预检 gate 据此同步拒绝)
|
|
2105
|
-
maxTurns: false
|
|
2031
|
+
maxTurns: false,
|
|
2032
|
+
// [subagent-model-switch] zcode 引擎不在模型切换设计范围(协议面引擎中立预留,
|
|
2033
|
+
// 后续另立项接入)——setModel 通路未接通,unsupported 如实声明
|
|
2034
|
+
setModel: "unsupported"
|
|
2106
2035
|
};
|
|
2107
2036
|
}
|
|
2108
2037
|
/** 探针(D7):二进制存在 + 版本解析(zcode 无公开契约,版本漂移的入口信号)。 */
|
|
@@ -2217,30 +2146,19 @@ var ZcodeEngine = class {
|
|
|
2217
2146
|
* 只在最终轮终态后合成(不变量 2/5)。
|
|
2218
2147
|
*/
|
|
2219
2148
|
async runAppServerAttemptsWithRetry(task, ctx, modelRef, cwd, basePrompt, schema, usageAcc) {
|
|
2220
|
-
const attemptStartedAt = Date.now();
|
|
2221
2149
|
let final = await this.attemptAppServerTurn(task, ctx, modelRef, cwd, basePrompt);
|
|
2222
2150
|
accumulateUsage(usageAcc, final);
|
|
2223
2151
|
if (final.kind === "run-failed" && final.transient !== void 0 && ctx.signal?.aborted !== true && !this.disposed) {
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
// 预算继承传递点(D2 内部传参面):显式预算 → 剩余值;无显式预算 → 缺省
|
|
2235
|
-
// (channel 侧走同一 env/默认,与首轮行为一致)
|
|
2236
|
-
...budget.state === "inherit" ? { turnTimeoutMs: budget.remainingMs } : {},
|
|
2237
|
-
// 重试事实进文案:「已自动重试一次」句仅对真实发生的重试生效(未重试形态
|
|
2238
|
-
// 不含——与行为一致,§5.2 F-1/F-4)
|
|
2239
|
-
retried: true
|
|
2240
|
-
});
|
|
2241
|
-
accumulateUsage(usageAcc, retry);
|
|
2242
|
-
final = retry;
|
|
2243
|
-
}
|
|
2152
|
+
logger4.warn(
|
|
2153
|
+
`[zcode-engine] \u672B\u6B21 attempt \u77AC\u65F6\u5931\u8D25\uFF08${final.transient}\uFF09\u2014\u2014\u6B62\u635F\u94FE\u5DF2\u7EC8\u5C40\uFF0C\u65B0\u4F1A\u8BDD\u81EA\u52A8\u91CD\u8BD5\u4E00\u6B21`
|
|
2154
|
+
);
|
|
2155
|
+
const retry = await this.attemptAppServerTurn(task, ctx, modelRef, cwd, basePrompt, {
|
|
2156
|
+
// 重试事实进文案:「已自动重试一次」句仅对真实发生的重试生效(未重试形态
|
|
2157
|
+
// 不含——与行为一致,§5.2 F-1/F-4)
|
|
2158
|
+
retried: true
|
|
2159
|
+
});
|
|
2160
|
+
accumulateUsage(usageAcc, retry);
|
|
2161
|
+
final = retry;
|
|
2244
2162
|
}
|
|
2245
2163
|
if (final.kind === "parsed" && final.schemaResult !== void 0 && !final.schemaResult.ok && schema !== void 0) {
|
|
2246
2164
|
const retryPrompt = appendSchemaRetryDirective(basePrompt, final.schemaResult.error);
|
|
@@ -2272,9 +2190,7 @@ var ZcodeEngine = class {
|
|
|
2272
2190
|
* 单轮常驻执行:runTurn 组合面 + D3 abort 链 + 事件前移(text_delta 实时流出;
|
|
2273
2191
|
* 终态数据经 read 兜底收口后才 resolve——不变量 1/2)。
|
|
2274
2192
|
*
|
|
2275
|
-
* @param opts
|
|
2276
|
-
* 向重试轮传剩余值;缺省不传(channel 走 env→默认,首轮行为)。
|
|
2277
|
-
* retried:瞬时重试轮标记——失败文案补「已自动重试一次」句(F-1/F-4)。
|
|
2193
|
+
* @param opts retried:瞬时重试轮标记——失败文案补「已自动重试一次」句(F-1/F-4)。
|
|
2278
2194
|
*/
|
|
2279
2195
|
async attemptAppServerTurn(task, ctx, modelRef, cwd, prompt, opts = {}) {
|
|
2280
2196
|
const rt = this.ensureAppServerRuntime();
|
|
@@ -2304,12 +2220,10 @@ var ZcodeEngine = class {
|
|
|
2304
2220
|
ctx.onHandleReady?.({
|
|
2305
2221
|
sessionRef: { dbPath: zcodeSessionDbPath(this.deps.engineDataDir()), sessionId }
|
|
2306
2222
|
});
|
|
2307
|
-
}
|
|
2308
|
-
// 显式总上界传参(D2/U4:缺省缺席——channel 侧 resolveTurnTimerMs 走 env→默认)
|
|
2309
|
-
...opts.turnTimeoutMs !== void 0 ? { turnTimeoutMs: opts.turnTimeoutMs } : {}
|
|
2223
|
+
}
|
|
2310
2224
|
});
|
|
2311
2225
|
const onAbort = () => {
|
|
2312
|
-
void this.appServerAbortChain(rt, turn, () => currentSessionId, sessionCreated
|
|
2226
|
+
void this.appServerAbortChain(rt, turn, () => currentSessionId, sessionCreated);
|
|
2313
2227
|
};
|
|
2314
2228
|
if (ctx.signal !== void 0) {
|
|
2315
2229
|
if (ctx.signal.aborted) onAbort();
|
|
@@ -2335,32 +2249,16 @@ var ZcodeEngine = class {
|
|
|
2335
2249
|
/**
|
|
2336
2250
|
* [attemptAppServerTurn 拆分] 失败分流(catch 半边):
|
|
2337
2251
|
* - signal 已 aborted → 中止终态收口;
|
|
2338
|
-
* - [P0-1
|
|
2339
|
-
* 再挂在 turn 落定上(race 恒真,killChain 结构性不可达的 v1 击穿点),改以
|
|
2340
|
-
* stop 应答三态裁决。await 链终局(非 fire-and-forget):outcome 止损文案与
|
|
2341
|
-
* 重试时序(D6,u-z4)都依赖链终局信号——止损完成前不合成终态。timeout 类
|
|
2342
|
-
* (idle/ceiling 都算)是 D6 明文的可重试形态——结构化标记
|
|
2343
|
-
* (TurnTimeoutError 类型化判据,不经字符串匹配,D4 同精神);
|
|
2344
|
-
* - [P0-1 U4] 连接崩溃收割形态(failAllTurns 的错误,D6 第二可重试形态)判据:
|
|
2252
|
+
* - [P0-1 U4] 连接崩溃收割形态(failAllTurns 的错误,D6 可重试形态)判据:
|
|
2345
2253
|
* 非 RPC error(服务端无明确应答——有应答即精确错误归类,非瞬时崩溃面)且
|
|
2346
2254
|
* conn 不存活。时序可靠性:catch 时刻紧随 onClose 收割,连接重建仅由
|
|
2347
2255
|
* conn.request 惰性触发——本链路中 runTurn finally 的 closeSession 对死连接
|
|
2348
|
-
* 短路(channel 侧 !alive 守卫)、stop 只属 abort
|
|
2349
|
-
*
|
|
2256
|
+
* 短路(channel 侧 !alive 守卫)、stop 只属 abort 链(已被 signal.aborted
|
|
2257
|
+
* 短路)——此刻无 request 可重建,判据可靠;
|
|
2350
2258
|
* - 其余 → 精确错误终态。
|
|
2351
2259
|
*/
|
|
2352
2260
|
async classifyAppServerTurnFailure(err, ctx, args) {
|
|
2353
2261
|
if (ctx.signal?.aborted === true) return abortedAppServerAttempt(ctx);
|
|
2354
|
-
if (err instanceof TurnTimeoutError) {
|
|
2355
|
-
const stopPath = await this.appServerAbortChain(
|
|
2356
|
-
args.rt,
|
|
2357
|
-
args.turn,
|
|
2358
|
-
args.currentSessionId,
|
|
2359
|
-
args.sessionCreated,
|
|
2360
|
-
{ escalateOn: "stop-outcome" }
|
|
2361
|
-
);
|
|
2362
|
-
return timeoutAppServerAttempt(err, args.currentSessionId(), stopPath, { retried: args.retried });
|
|
2363
|
-
}
|
|
2364
2262
|
if (!isAppServerRpcError(err) && !args.rt.conn.alive) {
|
|
2365
2263
|
return failedAppServerAttempt(err, args.currentSessionId(), { retried: args.retried, transient: "conn-closed" });
|
|
2366
2264
|
}
|
|
@@ -2371,8 +2269,8 @@ var ZcodeEngine = class {
|
|
|
2371
2269
|
* shutdown resolve 于 `exit` 事件,而 finalize 挂 `close`(stdio 排空)——两者之间的
|
|
2372
2270
|
* 事件窗口内 conn.child 仍非 null,紧接的下一任务 request 会复用垂死进程(写入成功
|
|
2373
2271
|
* 但必败,走崩溃路径)而非触发重建。与 shutdownRuntimeAndDisposeChannel 的
|
|
2374
|
-
* HARVEST_GRACE 同款 race 形态(close
|
|
2375
|
-
*
|
|
2272
|
+
* HARVEST_GRACE 同款 race 形态(close 永不到达不挂死)。abort 链的 await 终局
|
|
2273
|
+
* 语义因此是「进程收割确认完成」而非「SIGTERM 已发出」。
|
|
2376
2274
|
*/
|
|
2377
2275
|
async awaitConnFinalized(rt) {
|
|
2378
2276
|
if (!rt.conn.alive) return;
|
|
@@ -2388,25 +2286,14 @@ var ZcodeEngine = class {
|
|
|
2388
2286
|
});
|
|
2389
2287
|
}
|
|
2390
2288
|
/**
|
|
2391
|
-
* D3 abort
|
|
2392
|
-
*
|
|
2393
|
-
*
|
|
2394
|
-
*
|
|
2395
|
-
*
|
|
2396
|
-
*
|
|
2397
|
-
* (带上限)再发 stop——否则 stop 永远发不出,直接连坐杀共享进程。
|
|
2398
|
-
* - **超时入口**(`escalateOn: "stop-outcome"`,channel 判死后由 catch await 链终局):
|
|
2399
|
-
* turn 已 reject,对它 race 恒真不可用(v1 击穿点)——升级判据改挂在 **stop 应答
|
|
2400
|
-
* 三态**:①成功应答 → 服务端接受停 turn,止损确认,链终止;②协议性 error 应答
|
|
2401
|
-
* (有 error 帧即控制面活的证据,多因 runTurn finally 的 closeSession 先行关会话,
|
|
2402
|
-
* 健康形态竞态)→ 链终止**不升级**(止损由 close 回收 + 服务端自治承担;把
|
|
2403
|
-
* 「stop 报错」一律升级会误杀健康共享进程并连坐并发任务);③超时/写入失败/进程
|
|
2404
|
-
* 死等连接级失败(控制面死)→ killChain 升级。判据实现依据:error 应答帧 reject
|
|
2405
|
-
* 携带 number code(isAppServerRpcError);连接级失败是无 code 的新 Error
|
|
2406
|
-
* (connection.request 三态 reject 形态)。返回值即止损路径(超时入口的 outcome
|
|
2407
|
-
* 文案素材——D3 强制可观测面)。
|
|
2289
|
+
* D3 abort 链执行体(用户取消入口,fire-and-forget——与 turn promise 并行推进):
|
|
2290
|
+
* stop 帧(超时 ZCODE_APPSERVER_STOP_TIMEOUT_MS)→ grace 窗口内 turn 落定即止
|
|
2291
|
+
* (不杀共享进程)→ 超窗 killChain(conn.shutdown 全序:SIGTERM→grace→SIGKILL)。
|
|
2292
|
+
* turn 的最终落定由 attempt 主路径 await 收口,本链不直接产出终态。abort 与 create
|
|
2293
|
+
* 竞态(signal 先到、session 未建立):等会话建立(带上限)再发 stop——否则 stop
|
|
2294
|
+
* 永远发不出,直接连坐杀共享进程。
|
|
2408
2295
|
*/
|
|
2409
|
-
async appServerAbortChain(rt, turn, getSessionId, sessionCreated
|
|
2296
|
+
async appServerAbortChain(rt, turn, getSessionId, sessionCreated) {
|
|
2410
2297
|
const graceRaceThenKill = async () => {
|
|
2411
2298
|
const settled = await Promise.race([
|
|
2412
2299
|
turn.then(
|
|
@@ -2415,49 +2302,31 @@ var ZcodeEngine = class {
|
|
|
2415
2302
|
),
|
|
2416
2303
|
delayResolved(abortGraceMs(), false)
|
|
2417
2304
|
]);
|
|
2418
|
-
if (settled) return
|
|
2305
|
+
if (settled) return;
|
|
2419
2306
|
logger4.warn(
|
|
2420
2307
|
`[zcode-engine] abort grace \u7A97\u53E3\u5185\u672A\u89C1\u7EC8\u6001\u2014\u2014killChain \u6536\u5272\u5171\u4EAB\u8FDB\u7A0B\uFF08\u63A5\u53D7\u8FDE\u5750\uFF0C\u5728\u9014\u4EFB\u52A1\u8D70\u5D29\u6E83\u8DEF\u5F84\uFF09`
|
|
2421
2308
|
);
|
|
2422
2309
|
await rt.conn.shutdown({ graceMs: ZCODE_KILL_GRACE_MS });
|
|
2423
2310
|
await this.awaitConnFinalized(rt);
|
|
2424
|
-
return "escalated-kill";
|
|
2425
2311
|
};
|
|
2426
2312
|
let sessionId = getSessionId();
|
|
2427
2313
|
if (sessionId === void 0) {
|
|
2428
2314
|
await Promise.race([sessionCreated, delayResolved(stopTimeoutMs(), void 0)]);
|
|
2429
2315
|
sessionId = getSessionId();
|
|
2430
2316
|
if (sessionId === void 0) {
|
|
2431
|
-
if (entry.escalateOn === "stop-outcome") return "no-session";
|
|
2432
2317
|
return graceRaceThenKill();
|
|
2433
2318
|
}
|
|
2434
2319
|
}
|
|
2435
2320
|
if (!rt.conn.alive) {
|
|
2436
|
-
if (entry.escalateOn === "stop-outcome") return "stop-unreachable-killed";
|
|
2437
2321
|
return graceRaceThenKill();
|
|
2438
2322
|
}
|
|
2439
2323
|
try {
|
|
2440
2324
|
await rt.conn.request("session/stop", { sessionId }, { timeoutMs: stopTimeoutMs() });
|
|
2441
2325
|
} catch (err) {
|
|
2442
|
-
if (entry.escalateOn === "stop-outcome") {
|
|
2443
|
-
if (isAppServerRpcError(err)) {
|
|
2444
|
-
logger4.debug(
|
|
2445
|
-
`[zcode-engine] session/stop \u62A5\u534F\u8BAE\u6027 error\uFF08${errMessage3(err)}\uFF09\u2014\u2014\u4F1A\u8BDD\u5DF2\u56DE\u6536\uFF0C\u63A7\u5236\u9762\u5B58\u6D3B\uFF0C\u4E0D\u5347\u7EA7\u6740\u94FE`
|
|
2446
|
-
);
|
|
2447
|
-
return "stop-rejected";
|
|
2448
|
-
}
|
|
2449
|
-
logger4.warn(
|
|
2450
|
-
`[zcode-engine] session/stop \u65E0\u5E94\u7B54\uFF08${errMessage3(err)}\uFF09\u2014\u2014\u5347\u7EA7 killChain \u6536\u5272\u5171\u4EAB\u8FDB\u7A0B\uFF08\u8D85\u65F6\u5165\u53E3\uFF0C\u63A5\u53D7\u8FDE\u5750\uFF09`
|
|
2451
|
-
);
|
|
2452
|
-
await rt.conn.shutdown({ graceMs: ZCODE_KILL_GRACE_MS });
|
|
2453
|
-
await this.awaitConnFinalized(rt);
|
|
2454
|
-
return "stop-unreachable-killed";
|
|
2455
|
-
}
|
|
2456
2326
|
logger4.debug(
|
|
2457
2327
|
`[zcode-engine] session/stop \u5931\u8D25\uFF08${errMessage3(err)}\uFF09\u2014\u2014grace \u540E\u8D70 killChain \u515C\u5E95`
|
|
2458
2328
|
);
|
|
2459
2329
|
}
|
|
2460
|
-
if (entry.escalateOn === "stop-outcome") return "stop-acked";
|
|
2461
2330
|
return graceRaceThenKill();
|
|
2462
2331
|
}
|
|
2463
2332
|
// ── 常驻运行时管理(D1/D6)──────────────────────
|
|
@@ -2479,6 +2348,7 @@ var ZcodeEngine = class {
|
|
|
2479
2348
|
const env = buildAppServerEnv(this.deps.processEnv ?? process.env);
|
|
2480
2349
|
env.ZCODE_ENG_CLI_PATH = cliPath;
|
|
2481
2350
|
env.ZCODE_ENG_V2_CONFIG = this.deps.sources?.v2ConfigPath ?? defaultV2ConfigPath();
|
|
2351
|
+
env.ZCODE_ENG_PROVIDER_CONFIG = this.deps.sources?.personalProviderConfigPath ?? defaultPersonalProviderConfigPath();
|
|
2482
2352
|
const sessionDbPath = zcodeSessionDbPath(engineDataDir);
|
|
2483
2353
|
env.ZCODE_SESSION_DB_PATH = sessionDbPath;
|
|
2484
2354
|
delete env.ZCODE_SESSION_DB;
|
|
@@ -2511,15 +2381,15 @@ var ZcodeEngine = class {
|
|
|
2511
2381
|
* [R5 修复 R4 既有竞态] shutdown → 等崩溃收割实际发生 → channel 退订。killChain 在
|
|
2512
2382
|
* `exit` 事件 resolve,而连接 finalize(onClose → channel 的 failAllTurns)挂
|
|
2513
2383
|
* `close` 事件——两者之间有一个事件循环窗口:shutdown resolve 后立即退订,在途
|
|
2514
|
-
* turn
|
|
2384
|
+
* turn 会错过收割而失去终局来源。退订前等 onClose 触发(本方法先于
|
|
2515
2385
|
* shutdown 订阅;channel 的订阅在构造期更早——其 failAllTurns 先于本 promise
|
|
2516
2386
|
* resolve 执行);ZCODE_APPSERVER_HARVEST_GRACE_MS 兜底防 `close` 永不到达时挂死。
|
|
2517
2387
|
* [P0-1 U5/D7] grace race 输掉(close 迟到/永不到达——stdio 被孙进程持有排空不
|
|
2518
2388
|
* 尽等病态形态)时,channel.dispose() 内置的 dispose 收割(failAllTurns 先于退订,
|
|
2519
|
-
* SessionChannel.dispose)兜底在途 turn
|
|
2520
|
-
*
|
|
2521
|
-
*
|
|
2522
|
-
*
|
|
2389
|
+
* SessionChannel.dispose)兜底在途 turn——在途 turn 收敛为「grace 窗口内明确失败」
|
|
2390
|
+
* (设计 §3.4 退化路径闭合);race 窗口与 awaitConnFinalized 同源同量级
|
|
2391
|
+
* (ZCODE_APPSERVER_HARVEST_GRACE_MS)。正常 close 先到时 onClose 收割先行,
|
|
2392
|
+
* dispose 收割幂等 no-op(零回归)。
|
|
2523
2393
|
*/
|
|
2524
2394
|
async shutdownRuntimeAndDisposeChannel(rt) {
|
|
2525
2395
|
const harvested = new Promise((resolve2) => {
|
|
@@ -2824,16 +2694,6 @@ ${omissionNote}${kept.join("\n")}
|
|
|
2824
2694
|
function buildResumeUnavailableNoticeSegment() {
|
|
2825
2695
|
return "[\u4F1A\u8BDD\u5EF6\u7EED\u63D0\u793A] \u672C\u6D88\u606F\u662F\u540C\u4E00\u4EFB\u52A1\u7684\u5EF6\u7EED\u4F1A\u8BDD\uFF0C\u4F46\u4E0A\u4E00\u4F1A\u8BDD\u7684\u5386\u53F2\u8BB0\u5F55\u4E0D\u53EF\u6062\u590D\uFF08\u539F\u59CB\u4F1A\u8BDD\u5DF2\u5931\u6548\uFF09\u3002\n\u6CA1\u6709\u66F4\u65E9\u7684\u5BF9\u8BDD\u4E0A\u4E0B\u6587\u53EF\u5F15\u7528\u2014\u2014\u8BF7\u57FA\u4E8E\u4E0B\u65B9\u6700\u65B0\u6D88\u606F\u72EC\u7ACB\u5224\u65AD\u5E76\u7EE7\u7EED\u63A8\u8FDB\u4EFB\u52A1\u3002\n\n";
|
|
2826
2696
|
}
|
|
2827
|
-
var ZCODE_TURN_RETRY_MIN_BUDGET_MS = 3e5;
|
|
2828
|
-
function resolveTransientRetryBudget(totalBudgetMs, consumedMs) {
|
|
2829
|
-
if (totalBudgetMs === void 0) return { state: "unbounded" };
|
|
2830
|
-
const remainingMs = totalBudgetMs - consumedMs;
|
|
2831
|
-
return remainingMs >= ZCODE_TURN_RETRY_MIN_BUDGET_MS ? { state: "inherit", remainingMs } : { state: "depleted" };
|
|
2832
|
-
}
|
|
2833
|
-
function explicitTurnBudgetMs() {
|
|
2834
|
-
const parsed = parseZcodeTurnTimeoutEnv(process.env[ZCODE_TURN_MAX_TIMEOUT_ENV]);
|
|
2835
|
-
return parsed.state === "valid" && parsed.ms > 0 ? parsed.ms : void 0;
|
|
2836
|
-
}
|
|
2837
2697
|
function isPlainObject(v) {
|
|
2838
2698
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
2839
2699
|
}
|
|
@@ -2979,8 +2839,7 @@ function failedAppServerAttempt(err, currentSessionId, opts = {}) {
|
|
|
2979
2839
|
kind: "run-failed",
|
|
2980
2840
|
output: syntheticAppServerOutput(null),
|
|
2981
2841
|
message: buildAppServerRunFailedMessage(err, currentSessionId, opts.retried === true),
|
|
2982
|
-
// [P0-1 U4/D6]
|
|
2983
|
-
// timeoutAppServerAttempt,此处只承载 conn-closed)
|
|
2842
|
+
// [P0-1 U4/D6] 瞬时失败形态标记(重试判定判据,conn-closed 连接崩溃形态)
|
|
2984
2843
|
...opts.transient !== void 0 ? { transient: opts.transient } : {},
|
|
2985
2844
|
// 错误规格表 -32004 行「按任务失败上报(含会话 id)」:create 成功后运行中失败
|
|
2986
2845
|
// (-32004/-32010 等)时留痕会话 id——经 applyRunFailedOutcome 落 outcome.sessionId
|
|
@@ -2988,38 +2847,6 @@ function failedAppServerAttempt(err, currentSessionId, opts = {}) {
|
|
|
2988
2847
|
...currentSessionId !== void 0 ? { sessionId: currentSessionId } : {}
|
|
2989
2848
|
};
|
|
2990
2849
|
}
|
|
2991
|
-
function timeoutAppServerAttempt(err, currentSessionId, stopPath, opts = {}) {
|
|
2992
|
-
return {
|
|
2993
|
-
kind: "run-failed",
|
|
2994
|
-
output: syntheticAppServerOutput(null),
|
|
2995
|
-
message: buildAppServerTimeoutMessage(err, currentSessionId, stopPath, opts.retried === true),
|
|
2996
|
-
transient: "timeout",
|
|
2997
|
-
...currentSessionId !== void 0 ? { sessionId: currentSessionId } : {}
|
|
2998
|
-
};
|
|
2999
|
-
}
|
|
3000
|
-
function stopPathText(stopPath) {
|
|
3001
|
-
switch (stopPath) {
|
|
3002
|
-
case "stop-acked":
|
|
3003
|
-
return "session/stop \u5DF2\u9001\u8FBE\uFF08\u670D\u52A1\u7AEF\u63A5\u53D7\u505C turn\uFF09";
|
|
3004
|
-
case "stop-rejected":
|
|
3005
|
-
return "session/stop \u62A5\u534F\u8BAE\u6027 error\uFF08\u4F1A\u8BDD\u5DF2\u88AB\u56DE\u6536\uFF0C\u63A7\u5236\u9762\u5B58\u6D3B\u2014\u2014\u6B62\u635F\u7531\u4F1A\u8BDD\u56DE\u6536\u627F\u62C5\uFF0C\u4E0D\u5347\u7EA7\u6740\u94FE\uFF09";
|
|
3006
|
-
case "stop-unreachable-killed":
|
|
3007
|
-
return `session/stop \u65E0\u5E94\u7B54\u5DF2\u5347\u7EA7\u6740\u94FE\uFF08SIGTERM\u2192${ZCODE_KILL_GRACE_MS}ms\u2192SIGKILL \u6536\u5272\u5171\u4EAB\u8FDB\u7A0B\uFF09`;
|
|
3008
|
-
case "no-session":
|
|
3009
|
-
return "\u4F1A\u8BDD\u672A\u5EFA\u7ACB\uFF08\u4EFB\u52A1\u672A\u5F00\u59CB\u6267\u884C\uFF0C\u65E0\u5728\u9014\u6D88\u8017\uFF09";
|
|
3010
|
-
default:
|
|
3011
|
-
return "grace \u7A97\u53E3\u5185\u7EC8\u6001\u843D\u5B9A\u6216\u5DF2\u8D70\u6740\u94FE";
|
|
3012
|
-
}
|
|
3013
|
-
}
|
|
3014
|
-
function buildAppServerTimeoutMessage(err, sessionId, stopPath, retried = false) {
|
|
3015
|
-
const sid = sessionId !== void 0 ? `\uFF08\u4F1A\u8BDD ${sessionId}\uFF09` : "";
|
|
3016
|
-
const lastEventText = err.lastEventAt !== void 0 ? `\uFF0C\u6700\u540E\u4E8B\u4EF6 ${new Date(err.lastEventAt).toISOString()}` : "\uFF0C\u6574\u8F6E\u672A\u89C2\u5BDF\u5230\u4EFB\u4F55\u4E8B\u4EF6\uFF08\u8FDB\u7A0B\u5047\u6B7B/\u534F\u8BAE\u9759\u9ED8\u5F62\u6001\uFF09";
|
|
3017
|
-
const head = err.kind === "idle" ? `engine_timeout: zcode turn \u8FDE\u7EED\u9759\u9ED8 ${err.thresholdMs}ms\uFF08idle \u5224\u5B9A${lastEventText}\uFF0C\u603B\u8017\u65F6 ${err.elapsed}ms\uFF09${sid}\u3002` : `engine_timeout: zcode turn \u603B\u4E0A\u754C ${err.thresholdMs}ms \u5185\u672A\u89C2\u5BDF\u5230\u7EC8\u6001\uFF08chatty-wedge \u5224\u5B9A\u2014\u2014\u4E8B\u4EF6\u6D41\u4ECD\u6D3B\u8DC3\u800C\u7EC8\u6001\u672A\u5230\u8FBE\uFF0C\u603B\u8017\u65F6 ${err.elapsed}ms\uFF09${sid}\u3002`;
|
|
3018
|
-
const selfHelp = err.kind === "ceiling" ? `\u82E5\u672C\u4EFB\u52A1\u5C5E\u5408\u6CD5\u8D85\u957F\u4EFB\u52A1\uFF08\u9884\u671F\u8D85\u8FC7 ${err.thresholdMs}ms\uFF09\uFF0C\u91CD\u8DD1\u524D\u8BBE ${ZCODE_TURN_MAX_TIMEOUT_ENV} \u4E3A\u66F4\u5927\u6BEB\u79D2\u503C\u6216 0 \u5173\u95ED\u603B\u4E0A\u754C\uFF08\u5173\u95ED\u540E chatty \u5F62\u6001\u4E0D\u518D\u81EA\u52A8\u56DE\u6536\uFF0C\u9759\u9ED8 wedged \u4ECD\u7531 idle \u5C42\u515C\u5E95\u2014\u2014\u81EA\u884C\u6743\u8861\uFF09\u3002` : "";
|
|
3019
|
-
const rerunGuide = retried ? `\u{1F449} \u6062\u590D\u6307\u5F15\uFF1A\u76F4\u63A5\u91CD\u8DD1\u672C\u4EFB\u52A1\uFF08\u77AC\u65F6\u6545\u969C\u5DF2\u81EA\u52A8\u91CD\u8BD5\u4E00\u6B21\u4ECD\u8D85\u65F6\uFF1B\u91CD\u8BD5\u5728\u6B62\u635F\u94FE\u7EC8\u5C40\u540E\u542F\u52A8\uFF0C\u65E0\u65B0\u65E7\u4EFB\u52A1\u53CC\u8DD1\u7A97\uFF09\uFF1B` : `\u{1F449} \u6062\u590D\u6307\u5F15\uFF1A\u76F4\u63A5\u91CD\u8DD1\u672C\u4EFB\u52A1\uFF1B`;
|
|
3020
|
-
return `${head}\u6B62\u635F\u8DEF\u5F84\uFF1A${stopPathText(stopPath)}\u3002
|
|
3021
|
-
${rerunGuide}${selfHelp}\u82E5\u6301\u7EED\u51FA\u73B0\uFF0C\u68C0\u67E5 ZCode \u684C\u9762\u7AEF\u6A21\u578B\u8FDE\u901A\u6027\u6216\u6539\u7528 engine: pi\u3002`;
|
|
3022
|
-
}
|
|
3023
2850
|
function isHostTimeoutAbort(ctx) {
|
|
3024
2851
|
return ctx.signal?.aborted === true && ctx.signal.reason === import_subagent_engine_sdk11.HOST_TIMEOUT_ABORT_REASON;
|
|
3025
2852
|
}
|