@zhushanwen/zcode-subagent-cli 0.2.0 → 0.3.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-36VY2TNC.js → chunk-DMHXNYG2.js} +395 -91
- package/dist/index.cjs +416 -113
- package/dist/index.d.cts +27 -29
- package/dist/index.d.ts +27 -29
- package/dist/index.js +1 -1
- package/dist/main.cjs +419 -116
- package/dist/main.js +1 -1
- package/package.json +3 -3
package/dist/main.cjs
CHANGED
|
@@ -23,10 +23,10 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
23
23
|
));
|
|
24
24
|
|
|
25
25
|
// src/main.ts
|
|
26
|
-
var
|
|
26
|
+
var import_subagent_engine_sdk14 = require("@zhushanwen/subagent-engine-sdk");
|
|
27
27
|
|
|
28
28
|
// src/server.ts
|
|
29
|
-
var
|
|
29
|
+
var import_subagent_engine_sdk13 = require("@zhushanwen/subagent-engine-sdk");
|
|
30
30
|
|
|
31
31
|
// src/constants.ts
|
|
32
32
|
var ZCODE_ENGINE_ID = "zcode";
|
|
@@ -52,21 +52,26 @@ function parseZcodeTurnTimeoutEnv(raw) {
|
|
|
52
52
|
if (!Number.isFinite(parsed)) return { state: "invalid" };
|
|
53
53
|
return { state: "valid", ms: parsed };
|
|
54
54
|
}
|
|
55
|
-
var ZCODE_SHARED_POOL_KEY = "shared";
|
|
56
55
|
var ZCODE_APPSERVER_STOP_TIMEOUT_MS = 3e3;
|
|
57
56
|
var ZCODE_APPSERVER_ABORT_GRACE_MS = 3e3;
|
|
58
57
|
var ZCODE_APPSERVER_ERR_MODEL_CONFIG_MISSING = -32603;
|
|
59
58
|
var ZCODE_APPSERVER_ERR_BUSY_SESSION = -32010;
|
|
60
59
|
var ZCODE_APPSERVER_HARVEST_GRACE_MS = 1e3;
|
|
60
|
+
function isFailedTerminalStatus(status) {
|
|
61
|
+
return status === "failed" || status === "error";
|
|
62
|
+
}
|
|
63
|
+
var ZCODE_RESUME_HISTORY_TOKEN_BUDGET = 24e3;
|
|
64
|
+
var ZCODE_RESUME_CHARS_PER_TOKEN = 4;
|
|
65
|
+
var ZCODE_SESSION_SWEEP_DEFER_MS = 50;
|
|
61
66
|
|
|
62
67
|
// src/registration.ts
|
|
63
|
-
var
|
|
68
|
+
var import_subagent_engine_sdk11 = require("@zhushanwen/subagent-engine-sdk");
|
|
64
69
|
|
|
65
70
|
// src/zcode-engine.ts
|
|
66
|
-
var
|
|
71
|
+
var fs6 = __toESM(require("fs"), 1);
|
|
67
72
|
var path4 = __toESM(require("path"), 1);
|
|
68
|
-
var import_subagent_engine_sdk8 = require("@zhushanwen/subagent-engine-sdk");
|
|
69
73
|
var import_subagent_engine_sdk9 = require("@zhushanwen/subagent-engine-sdk");
|
|
74
|
+
var import_subagent_engine_sdk10 = require("@zhushanwen/subagent-engine-sdk");
|
|
70
75
|
|
|
71
76
|
// src/journal-io.ts
|
|
72
77
|
var import_subagent_engine_sdk = require("@zhushanwen/subagent-engine-sdk");
|
|
@@ -778,7 +783,7 @@ var AppServerConnection = class {
|
|
|
778
783
|
}
|
|
779
784
|
const timeoutMs = opts?.timeoutMs ?? this.requestTimeoutMs;
|
|
780
785
|
const id = ++this.reqSeq;
|
|
781
|
-
return new Promise((
|
|
786
|
+
return new Promise((resolve2, reject) => {
|
|
782
787
|
const timer = setTimeout(() => {
|
|
783
788
|
this.pending.delete(id);
|
|
784
789
|
reject(new Error(`\u8BF7\u6C42 ${method} \u8D85\u65F6\uFF08${timeoutMs}ms\uFF09`));
|
|
@@ -786,7 +791,7 @@ var AppServerConnection = class {
|
|
|
786
791
|
this.pending.set(id, {
|
|
787
792
|
// 泛型 T 是调用方对线上 unknown 结果的视图声明,连接层不做运行时校验
|
|
788
793
|
// (协议层保持透明,结构校验归会话层/消费方)。
|
|
789
|
-
resolve,
|
|
794
|
+
resolve: resolve2,
|
|
790
795
|
reject,
|
|
791
796
|
timer,
|
|
792
797
|
method
|
|
@@ -1137,6 +1142,46 @@ function extractReadUsage(readResult) {
|
|
|
1137
1142
|
}
|
|
1138
1143
|
return isRecord3(readResult.usage) ? readResult.usage : void 0;
|
|
1139
1144
|
}
|
|
1145
|
+
function extractResumeHistory(resumeResult) {
|
|
1146
|
+
if (!isRecord3(resumeResult) || !Array.isArray(resumeResult.messages)) return [];
|
|
1147
|
+
const turns = [];
|
|
1148
|
+
for (const m of resumeResult.messages) {
|
|
1149
|
+
if (!isRecord3(m)) continue;
|
|
1150
|
+
const role = messageRole(m);
|
|
1151
|
+
if (role !== "user" && role !== "assistant") continue;
|
|
1152
|
+
const text = partsToText(m.parts) ?? contentToText(m.content);
|
|
1153
|
+
if (text === void 0 || text === "") continue;
|
|
1154
|
+
turns.push({ role, text });
|
|
1155
|
+
}
|
|
1156
|
+
return turns;
|
|
1157
|
+
}
|
|
1158
|
+
function accumulateTokenFields(source, keys, acc) {
|
|
1159
|
+
for (const key of keys) {
|
|
1160
|
+
const raw = source[key];
|
|
1161
|
+
const v = typeof raw === "number" ? raw : Number(raw);
|
|
1162
|
+
if (Number.isFinite(v) && v > 0) {
|
|
1163
|
+
acc.total += v;
|
|
1164
|
+
acc.has = true;
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
function accumulateStepFinishTokens(parts, acc) {
|
|
1169
|
+
for (const p of parts) {
|
|
1170
|
+
if (!isRecord3(p) || p.type !== "step-finish" || !isRecord3(p.tokens)) continue;
|
|
1171
|
+
const t = p.tokens;
|
|
1172
|
+
accumulateTokenFields(t, ["input", "output"], acc);
|
|
1173
|
+
if (isRecord3(t.cache)) accumulateTokenFields(t.cache, ["read", "write"], acc);
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
function extractResumeTotalTokens(resumeResult) {
|
|
1177
|
+
if (!isRecord3(resumeResult) || !Array.isArray(resumeResult.messages)) return void 0;
|
|
1178
|
+
const acc = { total: 0, has: false };
|
|
1179
|
+
for (const m of resumeResult.messages) {
|
|
1180
|
+
if (!isRecord3(m) || messageRole(m) !== "assistant" || !Array.isArray(m.parts)) continue;
|
|
1181
|
+
accumulateStepFinishTokens(m.parts, acc);
|
|
1182
|
+
}
|
|
1183
|
+
return acc.has ? acc.total : void 0;
|
|
1184
|
+
}
|
|
1140
1185
|
var TurnTimeoutError = class extends Error {
|
|
1141
1186
|
kind;
|
|
1142
1187
|
elapsed;
|
|
@@ -1297,6 +1342,17 @@ var SessionChannel = class {
|
|
|
1297
1342
|
);
|
|
1298
1343
|
}
|
|
1299
1344
|
}
|
|
1345
|
+
/**
|
|
1346
|
+
* session/resume 读通道([U6 / §3.2.6 要点 3,P-1 探针实证]):应答自带完整
|
|
1347
|
+
* 双向 messages 历史(user/assistant 全量、tokens、parts)——zcode 续聊选型的
|
|
1348
|
+
* 历史来源(读通道成立;原地 resume 续写被 -32031 卡死,写通道不可用)。错误
|
|
1349
|
+
* 原样上抛(调用方决定降级形态——引擎侧 warn 后无历史前缀开新会话)。
|
|
1350
|
+
* 经 conn.request 惰性启动连接(resume 是 run 的**首个**请求——调用时点连接
|
|
1351
|
+
* 可能尚未启动,与 readBestEffort 的「已死跳过」判据不同场景,不做 alive 守卫)。
|
|
1352
|
+
*/
|
|
1353
|
+
async resumeSession(sessionId) {
|
|
1354
|
+
return this.conn.request("session/resume", { sessionId }, { timeoutMs: ZCODE_APPSERVER_TURN_READ_TIMEOUT_MS });
|
|
1355
|
+
}
|
|
1300
1356
|
/**
|
|
1301
1357
|
* session/close(A.2 ⑦,D4 用后即毁——回收引擎驻留内存,SQLite 持久化保留)。
|
|
1302
1358
|
* best-effort:失败只 warn 不抛(会话已终态,close 失败只泄漏一个驻留会话,
|
|
@@ -1373,7 +1429,13 @@ var SessionChannel = class {
|
|
|
1373
1429
|
});
|
|
1374
1430
|
const turn = {
|
|
1375
1431
|
sessionId,
|
|
1376
|
-
callbacks: {
|
|
1432
|
+
callbacks: {
|
|
1433
|
+
onTextDelta: opts.onTextDelta,
|
|
1434
|
+
onThinkingDelta: opts.onThinkingDelta,
|
|
1435
|
+
// [PR3] tool 执行期活性回调(SessionTurnCallbacks.onActivity 注释——宿主侧
|
|
1436
|
+
// 无进展守护的工具执行期刷新面)
|
|
1437
|
+
onActivity: opts.onActivity
|
|
1438
|
+
},
|
|
1377
1439
|
settled: false,
|
|
1378
1440
|
deltas: [],
|
|
1379
1441
|
finalText: void 0,
|
|
@@ -1489,7 +1551,9 @@ var SessionChannel = class {
|
|
|
1489
1551
|
if (payload === void 0) return;
|
|
1490
1552
|
this.refreshIdle(turn);
|
|
1491
1553
|
if (this.applyFinalFrame(turn, payload)) return;
|
|
1492
|
-
this.applyStreamDelta(turn, payload)
|
|
1554
|
+
if (!this.applyStreamDelta(turn, payload) && !turn.settled) {
|
|
1555
|
+
turn.callbacks.onActivity?.();
|
|
1556
|
+
}
|
|
1493
1557
|
}
|
|
1494
1558
|
/**
|
|
1495
1559
|
* 收尾帧判定与吸收(A.2 ⑤ 两种形态:payload.response / stopReason+content 变体)。
|
|
@@ -1513,9 +1577,12 @@ var SessionChannel = class {
|
|
|
1513
1577
|
/** 增量 delta 分发:非空 delta 入账 + 回调;终态后迟到丢弃(不变量 2)。
|
|
1514
1578
|
* kind 区分两通道(F2):reasoning_delta 只走 thinking 回调(不入 deltas 账本
|
|
1515
1579
|
* ——deltas 是 response 兜底聚合,推理文本不是答案正文);text_delta / kind
|
|
1516
|
-
* 缺席走 text 路径。
|
|
1580
|
+
* 缺席走 text 路径。
|
|
1581
|
+
* 返回值([PR3]):帧被 delta 路径消费(thinking 或 text,回调若注册则已触发)
|
|
1582
|
+
* → true;无 delta / 空 delta / 终态后迟到丢弃 → false(handleSessionEvent 据
|
|
1583
|
+
* 此分流 onActivity——delta 帧已是宿主可见进展,不双发活性信号)。 */
|
|
1517
1584
|
applyStreamDelta(turn, payload) {
|
|
1518
|
-
if (typeof payload.delta !== "string" || payload.delta === "") return;
|
|
1585
|
+
if (typeof payload.delta !== "string" || payload.delta === "") return false;
|
|
1519
1586
|
if (turn.settled) {
|
|
1520
1587
|
logger2.warn(
|
|
1521
1588
|
`\u7EC8\u6001\u540E\u8FDF\u5230\u7684 delta \u4E22\u5F03\uFF08\u4F1A\u8BDD ${turn.sessionId}\uFF0C\u4E0D\u53D8\u91CF 2\uFF1Aresolve \u540E\u4E0D\u518D\u53D1\u4E8B\u4EF6\uFF09: ${payload.delta.slice(
|
|
@@ -1523,14 +1590,15 @@ var SessionChannel = class {
|
|
|
1523
1590
|
DELTA_LOG_CHARS
|
|
1524
1591
|
)}`
|
|
1525
1592
|
);
|
|
1526
|
-
return;
|
|
1593
|
+
return false;
|
|
1527
1594
|
}
|
|
1528
1595
|
if (payload.kind === "reasoning_delta") {
|
|
1529
1596
|
turn.callbacks.onThinkingDelta?.(payload.delta);
|
|
1530
|
-
return;
|
|
1597
|
+
return true;
|
|
1531
1598
|
}
|
|
1532
1599
|
turn.deltas.push(payload.delta);
|
|
1533
1600
|
turn.callbacks.onTextDelta?.(payload.delta);
|
|
1601
|
+
return true;
|
|
1534
1602
|
}
|
|
1535
1603
|
handleTelemetry(params) {
|
|
1536
1604
|
if (!isRecord3(params)) return;
|
|
@@ -1550,13 +1618,38 @@ var SessionChannel = class {
|
|
|
1550
1618
|
turn.lastTerminalStatus = status;
|
|
1551
1619
|
this.recordTerminalError(turn, params);
|
|
1552
1620
|
if (turn.settled) {
|
|
1553
|
-
|
|
1554
|
-
`\u6743\u5A01\u7EC8\u6001\u665A\u4E8E\u843D\u5B9A\u7ED3\u679C\u5230\u8FBE\uFF08\u4F1A\u8BDD ${turn.sessionId}\uFF0C\u5DF2\u843D\u5B9A source=${turn.terminal?.source}\uFF09\uFF1Aturn.terminal status="${status}" \u4EC5\u8BB0\u5F55\u4E0D\u6539\u5199\uFF08P0-1 D5\u2460\uFF09`
|
|
1555
|
-
);
|
|
1621
|
+
this.logLateTerminal(turn, status);
|
|
1556
1622
|
return;
|
|
1557
1623
|
}
|
|
1558
1624
|
turn.settle({ status, source: "turn.terminal" });
|
|
1559
1625
|
}
|
|
1626
|
+
/**
|
|
1627
|
+
* 已落定 turn 的迟到权威终态分级日志(P-Z2 后续:常态迟到降噪)。真机实证该
|
|
1628
|
+
* 形态的唯一可达路径是 success 终态常态迟到(final-frame 先落定 + 权威
|
|
1629
|
+
* turn.terminal 迟到)——即每个成功任务必经;原无条件 warn 经 SDK cli-entry
|
|
1630
|
+
* 的 stderr 兜底 → runtime [rpc:stderr] 全量 console.error 链路,每个成功任务
|
|
1631
|
+
* 产一条零异常区分度的 ERROR 级日志。按权威 status 分级(落定语义不动——
|
|
1632
|
+
* lastTerminalStatus/lastTerminalError 的入账在上游无条件路径完成):
|
|
1633
|
+
* - "success":常态迟到,零日志;
|
|
1634
|
+
* - "interrupted":用户中断形态,debug(stderr 兜底对 debug no-op——对齐
|
|
1635
|
+
* SDK logger CONSOLE_SINK 语义,host/log 反向请求侧仍可观测);
|
|
1636
|
+
* - 失败类(isFailedTerminalStatus,与引擎失败分流同口径)与 unknown/未识别
|
|
1637
|
+
* status:保守 warn(原样 status 已写入文案)——假成功识破的防御面,理论
|
|
1638
|
+
* 不可达但保留,宁可误报不静默。
|
|
1639
|
+
*/
|
|
1640
|
+
logLateTerminal(turn, status) {
|
|
1641
|
+
if (status === "success") return;
|
|
1642
|
+
const message = `\u6743\u5A01\u7EC8\u6001\u665A\u4E8E\u843D\u5B9A\u7ED3\u679C\u5230\u8FBE\uFF08\u4F1A\u8BDD ${turn.sessionId}\uFF0C\u5DF2\u843D\u5B9A source=${turn.terminal?.source}\uFF09\uFF1Aturn.terminal status="${status}" \u4EC5\u8BB0\u5F55\u4E0D\u6539\u5199\uFF08P0-1 D5\u2460\uFF09`;
|
|
1643
|
+
if (isFailedTerminalStatus(status)) {
|
|
1644
|
+
logger2.warn(message);
|
|
1645
|
+
return;
|
|
1646
|
+
}
|
|
1647
|
+
if (status === "interrupted") {
|
|
1648
|
+
logger2.debug(message);
|
|
1649
|
+
return;
|
|
1650
|
+
}
|
|
1651
|
+
logger2.warn(message);
|
|
1652
|
+
}
|
|
1560
1653
|
/** terminal 帧专属错误信息入账(⛔P-Z2 实证:真实 failed 终态的 errorCode/errorMessage
|
|
1561
1654
|
* 只在 terminal 帧携带,read/delta 拿不到——先到/迟到都记录,消费层合成失败
|
|
1562
1655
|
* 文案时优先采信)。二者均缺失时不挂 lastTerminalError 字段。 */
|
|
@@ -1606,8 +1699,166 @@ var SessionChannel = class {
|
|
|
1606
1699
|
}
|
|
1607
1700
|
};
|
|
1608
1701
|
|
|
1609
|
-
// src/
|
|
1702
|
+
// src/session-db-maintenance.ts
|
|
1703
|
+
var fs5 = __toESM(require("fs"), 1);
|
|
1704
|
+
var import_subagent_engine_sdk8 = require("@zhushanwen/subagent-engine-sdk");
|
|
1610
1705
|
var logger3 = (0, import_subagent_engine_sdk8.getLogger)("subagents");
|
|
1706
|
+
var ZCODE_SESSION_TTL_MS = 2592e6;
|
|
1707
|
+
var ZCODE_SESSION_SWEEP_INTERVAL_MS = 864e5;
|
|
1708
|
+
var SWEEP_BUSY_TIMEOUT_MS = 5e3;
|
|
1709
|
+
var SESSION_CHILD_TABLES = [
|
|
1710
|
+
"message",
|
|
1711
|
+
"todo",
|
|
1712
|
+
"session_entry",
|
|
1713
|
+
"session_input",
|
|
1714
|
+
"session_target",
|
|
1715
|
+
"model_usage",
|
|
1716
|
+
"turn_usage",
|
|
1717
|
+
"tool_usage"
|
|
1718
|
+
];
|
|
1719
|
+
function loadDatabaseSyncCtor() {
|
|
1720
|
+
const getBuiltin = process.getBuiltinModule;
|
|
1721
|
+
if (typeof getBuiltin !== "function") return void 0;
|
|
1722
|
+
const mod = getBuiltin("node:sqlite");
|
|
1723
|
+
return typeof mod?.DatabaseSync === "function" ? mod.DatabaseSync : void 0;
|
|
1724
|
+
}
|
|
1725
|
+
function sessionLastActivity(row) {
|
|
1726
|
+
for (const v of [row.time_updated, row.time_created]) {
|
|
1727
|
+
if (typeof v === "number" && Number.isFinite(v)) return v;
|
|
1728
|
+
}
|
|
1729
|
+
return null;
|
|
1730
|
+
}
|
|
1731
|
+
function collectExpiredSessions(db, cutoff, keep) {
|
|
1732
|
+
const rows = db.prepare("SELECT id, time_updated, time_created FROM session").all();
|
|
1733
|
+
const expired = [];
|
|
1734
|
+
let keptActive = 0;
|
|
1735
|
+
for (const row of rows) {
|
|
1736
|
+
if (typeof row.id !== "string" || row.id === "") continue;
|
|
1737
|
+
const last = sessionLastActivity(row);
|
|
1738
|
+
if (last === null || last >= cutoff) continue;
|
|
1739
|
+
if (keep.has(row.id)) {
|
|
1740
|
+
keptActive++;
|
|
1741
|
+
continue;
|
|
1742
|
+
}
|
|
1743
|
+
expired.push(row.id);
|
|
1744
|
+
}
|
|
1745
|
+
return { expired, keptActive };
|
|
1746
|
+
}
|
|
1747
|
+
function ensureForeignKeysOn(db) {
|
|
1748
|
+
db.exec("PRAGMA foreign_keys = ON");
|
|
1749
|
+
const fkOn = db.prepare("PRAGMA foreign_keys").get();
|
|
1750
|
+
if (fkOn?.foreign_keys !== 1) {
|
|
1751
|
+
throw new Error("PRAGMA foreign_keys=ON \u672A\u751F\u6548\u2014\u2014\u4E2D\u6B62\u5220\u9664\uFF08\u9632\u5B64\u513F\u884C\uFF09\uFF0C\u672C\u8F6E sweep \u653E\u5F03");
|
|
1752
|
+
}
|
|
1753
|
+
}
|
|
1754
|
+
function listPresentTables(db) {
|
|
1755
|
+
return new Set(
|
|
1756
|
+
db.prepare("SELECT name FROM sqlite_master WHERE type = 'table'").all().map((r) => typeof r.name === "string" ? r.name : "")
|
|
1757
|
+
);
|
|
1758
|
+
}
|
|
1759
|
+
var DELETE_BATCH_SIZE = 500;
|
|
1760
|
+
function chunkIds(ids, size) {
|
|
1761
|
+
const batches = [];
|
|
1762
|
+
for (let i = 0; i < ids.length; i += size) batches.push(ids.slice(i, i + size));
|
|
1763
|
+
return batches;
|
|
1764
|
+
}
|
|
1765
|
+
function deleteExpiredSessionsInTx(db, expired, present) {
|
|
1766
|
+
db.exec("BEGIN");
|
|
1767
|
+
try {
|
|
1768
|
+
let swept = 0;
|
|
1769
|
+
for (const batch of chunkIds(expired, DELETE_BATCH_SIZE)) {
|
|
1770
|
+
const ph = batch.map(() => "?").join(", ");
|
|
1771
|
+
for (const table of SESSION_CHILD_TABLES) {
|
|
1772
|
+
if (present.has(table)) db.prepare(`DELETE FROM ${table} WHERE session_id IN (${ph})`).run(...batch);
|
|
1773
|
+
}
|
|
1774
|
+
if (present.has("session_task_link")) {
|
|
1775
|
+
db.prepare(`DELETE FROM session_task_link WHERE child_session_id IN (${ph})`).run(...batch);
|
|
1776
|
+
db.prepare(`UPDATE session_task_link SET parent_session_id = NULL WHERE parent_session_id IN (${ph})`).run(...batch);
|
|
1777
|
+
}
|
|
1778
|
+
if (present.has("workflow_run")) {
|
|
1779
|
+
db.prepare(`UPDATE workflow_run SET parent_session_id = NULL WHERE parent_session_id IN (${ph})`).run(...batch);
|
|
1780
|
+
}
|
|
1781
|
+
if (present.has("workflow_activity")) {
|
|
1782
|
+
db.prepare(`UPDATE workflow_activity SET child_session_id = NULL WHERE child_session_id IN (${ph})`).run(...batch);
|
|
1783
|
+
}
|
|
1784
|
+
if (present.has("input_history")) {
|
|
1785
|
+
db.prepare(`DELETE FROM input_history WHERE session_id IN (${ph})`).run(...batch);
|
|
1786
|
+
}
|
|
1787
|
+
const res = db.prepare(`DELETE FROM session WHERE id IN (${ph})`).run(...batch);
|
|
1788
|
+
swept += res.changes ?? batch.length;
|
|
1789
|
+
}
|
|
1790
|
+
db.exec("COMMIT");
|
|
1791
|
+
return swept;
|
|
1792
|
+
} catch (err) {
|
|
1793
|
+
try {
|
|
1794
|
+
db.exec("ROLLBACK");
|
|
1795
|
+
} catch (rollbackErr) {
|
|
1796
|
+
void rollbackErr;
|
|
1797
|
+
}
|
|
1798
|
+
throw err;
|
|
1799
|
+
}
|
|
1800
|
+
}
|
|
1801
|
+
function sweepExpiredZcodeSessions(dbPath, opts = {}) {
|
|
1802
|
+
const noOp = { swept: 0, keptActive: 0 };
|
|
1803
|
+
if (!fs5.existsSync(dbPath)) return noOp;
|
|
1804
|
+
const Ctor = loadDatabaseSyncCtor();
|
|
1805
|
+
if (Ctor === void 0) {
|
|
1806
|
+
logger3.warn("[zcode-ttl] node:sqlite \u4E0D\u53EF\u7528\uFF08\u9700 Node \u226522.3 \u7684 process.getBuiltinModule\uFF09\u2014\u2014\u672C\u8F6E sweep \u8DF3\u8FC7");
|
|
1807
|
+
return noOp;
|
|
1808
|
+
}
|
|
1809
|
+
const now = opts.nowMs ?? Date.now();
|
|
1810
|
+
const ttl = opts.ttlMs ?? ZCODE_SESSION_TTL_MS;
|
|
1811
|
+
const cutoff = now - ttl;
|
|
1812
|
+
const keep = opts.keepSessionIds ?? /* @__PURE__ */ new Set();
|
|
1813
|
+
let db;
|
|
1814
|
+
try {
|
|
1815
|
+
db = new Ctor(dbPath);
|
|
1816
|
+
db.exec(`PRAGMA busy_timeout = ${SWEEP_BUSY_TIMEOUT_MS}`);
|
|
1817
|
+
const { expired, keptActive } = collectExpiredSessions(db, cutoff, keep);
|
|
1818
|
+
if (expired.length === 0) {
|
|
1819
|
+
db.close();
|
|
1820
|
+
return { swept: 0, keptActive };
|
|
1821
|
+
}
|
|
1822
|
+
ensureForeignKeysOn(db);
|
|
1823
|
+
const present = listPresentTables(db);
|
|
1824
|
+
const swept = deleteExpiredSessionsInTx(db, expired, present);
|
|
1825
|
+
logger3.debug(`[zcode-ttl] \u9694\u79BB\u5E93\u8D85\u7A97\u6761\u76EE\u5DF2\u6E05\uFF1A${swept} \u6761\uFF08TTL ${ttl}ms\uFF0C\u8C41\u514D\u6D3B\u8DC3 ${keptActive}\uFF09`, { dbPath });
|
|
1826
|
+
try {
|
|
1827
|
+
db.prepare("PRAGMA wal_checkpoint(PASSIVE)").get();
|
|
1828
|
+
} catch (err) {
|
|
1829
|
+
void err;
|
|
1830
|
+
}
|
|
1831
|
+
return { swept, keptActive };
|
|
1832
|
+
} catch (err) {
|
|
1833
|
+
logger3.warn(
|
|
1834
|
+
`[zcode-ttl] sweep \u5931\u8D25\uFF08\u8F85\u52A9\u8D44\u6E90\u9762\uFF0C\u4E0D\u5F71\u54CD run \u4E3B\u94FE\u8DEF\uFF1B\u4E0B\u4E2A\u8282\u6D41\u7A97\u91CD\u8BD5\uFF09: ${err instanceof Error ? err.message : String(err)}`,
|
|
1835
|
+
{ dbPath }
|
|
1836
|
+
);
|
|
1837
|
+
return noOp;
|
|
1838
|
+
} finally {
|
|
1839
|
+
try {
|
|
1840
|
+
db?.close();
|
|
1841
|
+
} catch (err) {
|
|
1842
|
+
void err;
|
|
1843
|
+
}
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1846
|
+
var sweepThrottle = /* @__PURE__ */ new Map();
|
|
1847
|
+
function maybeSweepExpiredZcodeSessions(dbPath, opts = {}) {
|
|
1848
|
+
const now = Date.now();
|
|
1849
|
+
const last = sweepThrottle.get(dbPath);
|
|
1850
|
+
if (!opts.force && last !== void 0 && now - last < ZCODE_SESSION_SWEEP_INTERVAL_MS) {
|
|
1851
|
+
return { swept: 0, keptActive: 0 };
|
|
1852
|
+
}
|
|
1853
|
+
const result = sweepExpiredZcodeSessions(dbPath, {
|
|
1854
|
+
...opts.keepSessionIds !== void 0 ? { keepSessionIds: opts.keepSessionIds } : {}
|
|
1855
|
+
});
|
|
1856
|
+
sweepThrottle.set(dbPath, now);
|
|
1857
|
+
return result;
|
|
1858
|
+
}
|
|
1859
|
+
|
|
1860
|
+
// src/zcode-engine.ts
|
|
1861
|
+
var logger4 = (0, import_subagent_engine_sdk9.getLogger)("subagents");
|
|
1611
1862
|
var PROBE_VERSION_TIMEOUT_MS = 15e3;
|
|
1612
1863
|
var COMMON_THOUGHT_LEVELS = ["low", "high", "max"];
|
|
1613
1864
|
var ZcodeEngine = class {
|
|
@@ -1634,8 +1885,11 @@ var ZcodeEngine = class {
|
|
|
1634
1885
|
schemaEnforcement: "emulated",
|
|
1635
1886
|
// send-while-running 恒 -32010 硬错误(旧实测)——app-server 常驻化不改变此判据
|
|
1636
1887
|
steer: "unsupported",
|
|
1637
|
-
//
|
|
1638
|
-
|
|
1888
|
+
// [U6 / §3.2.6 要点 4] "cold" = 冷恢复会话:session/resume 读通道取结构化
|
|
1889
|
+
// 历史 + session/create 新会话注入首轮(无热 steering——interrupt 维持
|
|
1890
|
+
// kill-only 如实声明)。P-1 探针:原地 resume 续写被 -32031 卡死,热会话
|
|
1891
|
+
// 通道不可用,声明不越级。
|
|
1892
|
+
conversation: "cold",
|
|
1639
1893
|
// 无 --append-system-prompt flag(实测拒收)——persona 只能拼进 prompt
|
|
1640
1894
|
personaInjection: "prompt",
|
|
1641
1895
|
// app-server 推送流实时流出(session/event payload.delta → text_delta)
|
|
@@ -1679,7 +1933,7 @@ var ZcodeEngine = class {
|
|
|
1679
1933
|
}
|
|
1680
1934
|
/** check 1:二进制存在性(isFile 才算——同名目录不是可执行入口)。 */
|
|
1681
1935
|
probeBinaryCheck(cliPath) {
|
|
1682
|
-
const binaryOk =
|
|
1936
|
+
const binaryOk = fs6.existsSync(cliPath) && fs6.statSync(cliPath).isFile();
|
|
1683
1937
|
return {
|
|
1684
1938
|
name: "binary",
|
|
1685
1939
|
ok: binaryOk,
|
|
@@ -1717,8 +1971,8 @@ var ZcodeEngine = class {
|
|
|
1717
1971
|
/**
|
|
1718
1972
|
* 常驻路径主编排:模型解析(v2 单源校验)→ 惰性连接 + runTurn(事件时序前移:
|
|
1719
1973
|
* text_delta 流式、终态后 message_end/turn_end)→ schema 仿真重试 → outcome/handle。
|
|
1720
|
-
*
|
|
1721
|
-
*
|
|
1974
|
+
* onHandleReady 在 create 应答后(§3.4 不变量 3;原 onPoolResolved prepare 期
|
|
1975
|
+
* 声明已随 [池抽象降级 2026-09-13] poolKey 协议面退役删除)。
|
|
1722
1976
|
*/
|
|
1723
1977
|
async runViaAppServer(task, ctx) {
|
|
1724
1978
|
const startedAt = Date.now();
|
|
@@ -1728,10 +1982,10 @@ var ZcodeEngine = class {
|
|
|
1728
1982
|
const modelRef = resolveZcodeModelRef(task.model, this.deps.sources);
|
|
1729
1983
|
this.warnIgnoredCtxModel(task, ctx, modelRef);
|
|
1730
1984
|
this.warnThoughtLevelUncommon(task, ctx);
|
|
1731
|
-
ctx.onPoolResolved?.(ZCODE_SHARED_POOL_KEY);
|
|
1732
1985
|
const cwd = task.cwd ?? process.cwd();
|
|
1733
1986
|
const schema = isPlainObject(task.schema) ? task.schema : void 0;
|
|
1734
|
-
const
|
|
1987
|
+
const resumePrefix = await this.buildResumeHistoryPrefix(ctx);
|
|
1988
|
+
const basePrompt = resumePrefix === void 0 ? this.buildPrompt(task, schema) : resumePrefix + this.buildPrompt(task, schema);
|
|
1735
1989
|
const usageAcc = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, has: false };
|
|
1736
1990
|
const final = await this.runAppServerAttemptsWithRetry(task, ctx, modelRef, cwd, basePrompt, schema, usageAcc);
|
|
1737
1991
|
const outcome = this.finalizeOutcome(task, ctx, final, usageAcc, startedAt);
|
|
@@ -1739,7 +1993,6 @@ var ZcodeEngine = class {
|
|
|
1739
1993
|
}
|
|
1740
1994
|
/** pre-aborted 短路收口:合成中止 outcome + 'shared' 锚定 handle。 */
|
|
1741
1995
|
abortedAppServerRun(task, ctx, startedAt) {
|
|
1742
|
-
ctx.onPoolResolved?.(ZCODE_SHARED_POOL_KEY);
|
|
1743
1996
|
const outcome = this.finalizeOutcome(
|
|
1744
1997
|
task,
|
|
1745
1998
|
ctx,
|
|
@@ -1773,11 +2026,11 @@ var ZcodeEngine = class {
|
|
|
1773
2026
|
if (final.kind === "run-failed" && final.transient !== void 0 && ctx.signal?.aborted !== true && !this.disposed) {
|
|
1774
2027
|
const budget = resolveTransientRetryBudget(explicitTurnBudgetMs(), Date.now() - attemptStartedAt);
|
|
1775
2028
|
if (budget.state === "depleted") {
|
|
1776
|
-
|
|
2029
|
+
logger4.warn(
|
|
1777
2030
|
`[zcode-engine] \u672B\u6B21 attempt \u77AC\u65F6\u5931\u8D25\uFF08${final.transient}\uFF09\u2014\u2014\u663E\u5F0F\u603B\u4E0A\u754C\u9884\u7B97\u5269\u4F59\u4E0D\u8DB3 ${ZCODE_TURN_RETRY_MIN_BUDGET_MS}ms\uFF0C\u4E0D\u91CD\u8BD5\u76F4\u63A5\u7EC8\u6001\u5316\uFF08\u9884\u7B97\u7EE7\u627F\uFF1A\u91CD\u8BD5\u4E0D\u91CD\u7F6E\u603B\u9884\u7B97\uFF09`
|
|
1778
2031
|
);
|
|
1779
2032
|
} else {
|
|
1780
|
-
|
|
2033
|
+
logger4.warn(
|
|
1781
2034
|
`[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` + (budget.state === "inherit" ? `\uFF08\u9884\u7B97\u7EE7\u627F\uFF1A\u91CD\u8BD5\u8F6E\u603B\u4E0A\u754C=\u5269\u4F59 ${budget.remainingMs}ms\uFF0C\u4E0D\u91CD\u7F6E\u603B\u9884\u7B97\uFF09` : "\uFF08\u65E0\u663E\u5F0F\u603B\u4E0A\u754C\u9884\u7B97\uFF0C\u91CD\u8BD5\u8F6E\u8D70 env/\u9ED8\u8BA4\u4E0A\u754C\uFF09")
|
|
1782
2035
|
);
|
|
1783
2036
|
const retry = await this.attemptAppServerTurn(task, ctx, modelRef, cwd, basePrompt, {
|
|
@@ -1813,7 +2066,6 @@ var ZcodeEngine = class {
|
|
|
1813
2066
|
dbPath: zcodeSessionDbPath(this.deps.engineDataDir()),
|
|
1814
2067
|
...outcome.sessionId !== void 0 ? { sessionId: outcome.sessionId } : {}
|
|
1815
2068
|
},
|
|
1816
|
-
poolKey: ZCODE_SHARED_POOL_KEY,
|
|
1817
2069
|
...this.probeCache?.engineVersion !== void 0 && this.probeCache.engineVersion !== "" ? { engineVersion: this.probeCache.engineVersion } : {},
|
|
1818
2070
|
adapterVersion: ZCODE_ADAPTER_VERSION
|
|
1819
2071
|
}
|
|
@@ -1833,8 +2085,8 @@ var ZcodeEngine = class {
|
|
|
1833
2085
|
const createParams = buildAppServerCreateParams(task, providerId, modelId, cwd);
|
|
1834
2086
|
let currentSessionId;
|
|
1835
2087
|
let signalSessionCreated;
|
|
1836
|
-
const sessionCreated = new Promise((
|
|
1837
|
-
signalSessionCreated =
|
|
2088
|
+
const sessionCreated = new Promise((resolve2) => {
|
|
2089
|
+
signalSessionCreated = resolve2;
|
|
1838
2090
|
});
|
|
1839
2091
|
const turn = rt.channel.runTurn(createParams, prompt, {
|
|
1840
2092
|
// 事件时序前移:payload.delta → text_delta 实时流出(stream 粒度,D5);
|
|
@@ -1842,13 +2094,17 @@ var ZcodeEngine = class {
|
|
|
1842
2094
|
// 不变量 3a 的拼接比对不含 reasoning)
|
|
1843
2095
|
onTextDelta: (delta) => ctx.onEvent?.({ type: "text_delta", delta }),
|
|
1844
2096
|
onThinkingDelta: (delta) => ctx.onEvent?.({ type: "thinking_delta", delta }),
|
|
2097
|
+
// [PR3] 工具执行期活性:非终态非增量的 session/event 帧(tool.updated progress
|
|
2098
|
+
// 等,真机探针实证每 ~1s 一帧)→ activity 事件(零载荷纯活性信号——宿主无进展
|
|
2099
|
+
// 守护对任何事件类型刷新;reducer no-op、不落 journal)。zcode 引擎
|
|
2100
|
+
// conversation:"unsupported",run 域是唯一发射面(无 chat 域接线)。
|
|
2101
|
+
onActivity: () => ctx.onEvent?.({ type: "activity" }),
|
|
1845
2102
|
onSessionCreated: (sessionId) => {
|
|
1846
2103
|
currentSessionId = sessionId;
|
|
1847
2104
|
rt.activeSessions.add(sessionId);
|
|
1848
2105
|
signalSessionCreated?.();
|
|
1849
2106
|
ctx.onHandleReady?.({
|
|
1850
|
-
sessionRef: { dbPath: zcodeSessionDbPath(this.deps.engineDataDir()), sessionId }
|
|
1851
|
-
poolKey: ZCODE_SHARED_POOL_KEY
|
|
2107
|
+
sessionRef: { dbPath: zcodeSessionDbPath(this.deps.engineDataDir()), sessionId }
|
|
1852
2108
|
});
|
|
1853
2109
|
},
|
|
1854
2110
|
// 显式总上界传参(D2/U4:缺省缺席——channel 侧 resolveTurnTimerMs 走 env→默认)
|
|
@@ -1896,14 +2152,14 @@ var ZcodeEngine = class {
|
|
|
1896
2152
|
*/
|
|
1897
2153
|
async awaitConnFinalized(rt) {
|
|
1898
2154
|
if (!rt.conn.alive) return;
|
|
1899
|
-
await new Promise((
|
|
2155
|
+
await new Promise((resolve2) => {
|
|
1900
2156
|
const timer = setTimeout(() => finish(), ZCODE_APPSERVER_HARVEST_GRACE_MS);
|
|
1901
2157
|
if (typeof timer.unref === "function") timer.unref();
|
|
1902
2158
|
const off = rt.conn.onClose(() => finish());
|
|
1903
2159
|
function finish() {
|
|
1904
2160
|
clearTimeout(timer);
|
|
1905
2161
|
off();
|
|
1906
|
-
|
|
2162
|
+
resolve2();
|
|
1907
2163
|
}
|
|
1908
2164
|
});
|
|
1909
2165
|
}
|
|
@@ -1937,7 +2193,7 @@ var ZcodeEngine = class {
|
|
|
1937
2193
|
delayResolved(ZCODE_APPSERVER_ABORT_GRACE_MS, false)
|
|
1938
2194
|
]);
|
|
1939
2195
|
if (settled) return "settled-in-grace";
|
|
1940
|
-
|
|
2196
|
+
logger4.warn(
|
|
1941
2197
|
`[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`
|
|
1942
2198
|
);
|
|
1943
2199
|
await rt.conn.shutdown({ graceMs: ZCODE_KILL_GRACE_MS });
|
|
@@ -1962,19 +2218,19 @@ var ZcodeEngine = class {
|
|
|
1962
2218
|
} catch (err) {
|
|
1963
2219
|
if (entry.escalateOn === "stop-outcome") {
|
|
1964
2220
|
if (isAppServerRpcError(err)) {
|
|
1965
|
-
|
|
2221
|
+
logger4.debug(
|
|
1966
2222
|
`[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`
|
|
1967
2223
|
);
|
|
1968
2224
|
return "stop-rejected";
|
|
1969
2225
|
}
|
|
1970
|
-
|
|
2226
|
+
logger4.warn(
|
|
1971
2227
|
`[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`
|
|
1972
2228
|
);
|
|
1973
2229
|
await rt.conn.shutdown({ graceMs: ZCODE_KILL_GRACE_MS });
|
|
1974
2230
|
await this.awaitConnFinalized(rt);
|
|
1975
2231
|
return "stop-unreachable-killed";
|
|
1976
2232
|
}
|
|
1977
|
-
|
|
2233
|
+
logger4.debug(
|
|
1978
2234
|
`[zcode-engine] session/stop \u5931\u8D25\uFF08${errMessage3(err)}\uFF09\u2014\u2014grace \u540E\u8D70 killChain \u515C\u5E95`
|
|
1979
2235
|
);
|
|
1980
2236
|
}
|
|
@@ -2003,7 +2259,7 @@ var ZcodeEngine = class {
|
|
|
2003
2259
|
const sessionDbPath = zcodeSessionDbPath(engineDataDir);
|
|
2004
2260
|
env.ZCODE_SESSION_DB_PATH = sessionDbPath;
|
|
2005
2261
|
delete env.ZCODE_SESSION_DB;
|
|
2006
|
-
|
|
2262
|
+
fs6.mkdirSync(path4.dirname(sessionDbPath), { recursive: true });
|
|
2007
2263
|
const conn = new AppServerConnection({
|
|
2008
2264
|
cliPath,
|
|
2009
2265
|
dataDir: engineDataDir,
|
|
@@ -2021,6 +2277,11 @@ var ZcodeEngine = class {
|
|
|
2021
2277
|
activeSessions: /* @__PURE__ */ new Set()
|
|
2022
2278
|
};
|
|
2023
2279
|
this.appserverRuntime = rt;
|
|
2280
|
+
const sweepDbPath = sessionDbPath;
|
|
2281
|
+
const sweepTimer = setTimeout(() => {
|
|
2282
|
+
maybeSweepExpiredZcodeSessions(sweepDbPath, { keepSessionIds: this.appserverRuntime?.activeSessions });
|
|
2283
|
+
}, ZCODE_SESSION_SWEEP_DEFER_MS);
|
|
2284
|
+
if (typeof sweepTimer.unref === "function") sweepTimer.unref();
|
|
2024
2285
|
return rt;
|
|
2025
2286
|
}
|
|
2026
2287
|
/**
|
|
@@ -2038,10 +2299,10 @@ var ZcodeEngine = class {
|
|
|
2038
2299
|
* 先到时 onClose 收割先行,dispose 收割幂等 no-op(零回归)。
|
|
2039
2300
|
*/
|
|
2040
2301
|
async shutdownRuntimeAndDisposeChannel(rt) {
|
|
2041
|
-
const harvested = new Promise((
|
|
2302
|
+
const harvested = new Promise((resolve2) => {
|
|
2042
2303
|
const off = rt.conn.onClose(() => {
|
|
2043
2304
|
off();
|
|
2044
|
-
|
|
2305
|
+
resolve2();
|
|
2045
2306
|
});
|
|
2046
2307
|
});
|
|
2047
2308
|
await rt.conn.shutdown({ graceMs: ZCODE_KILL_GRACE_MS });
|
|
@@ -2068,17 +2329,6 @@ var ZcodeEngine = class {
|
|
|
2068
2329
|
}
|
|
2069
2330
|
await this.shutdownRuntimeAndDisposeChannel(rt);
|
|
2070
2331
|
}
|
|
2071
|
-
/**
|
|
2072
|
-
* [u7a D5] 引擎在途只读快照:activeSessions 非空才算在途——poolKey 'shared' 的
|
|
2073
|
-
* app-server **空闲常驻进程恒活,禁止按进程存在判定**(进程在 ≠ 在途,否则推迟
|
|
2074
|
-
* 判定恒真、30min 上限从兜底变常态路径,设计 §3.3 D5 显式排除)。计数权威 =
|
|
2075
|
-
* activeSessions(attempt 入 create 应答后 add / finally settle 后 delete,与
|
|
2076
|
-
* dispose 的 close 帧目标集同一状态源,无双记账)。运行时未初始化(从未 run /
|
|
2077
|
-
* 已 dispose)→ 恒 0。
|
|
2078
|
-
*/
|
|
2079
|
-
inFlightSnapshot() {
|
|
2080
|
-
return { inFlight: this.appserverRuntime?.activeSessions.size ?? 0 };
|
|
2081
|
-
}
|
|
2082
2332
|
/** 终态合成(extension-conventions 函数 80 行上限,从 run 提取):aborted / run-failed / parsed 三分支。 */
|
|
2083
2333
|
finalizeOutcome(task, ctx, final, usageAcc, startedAt) {
|
|
2084
2334
|
const outcome = {
|
|
@@ -2105,7 +2355,7 @@ var ZcodeEngine = class {
|
|
|
2105
2355
|
/** abort 合成终态:exitCode=null(record 正常收尾,不留僵尸)。 */
|
|
2106
2356
|
applyAbortedOutcome(outcome, task, ctx, final, emit) {
|
|
2107
2357
|
outcome.exitCode = null;
|
|
2108
|
-
outcome.error = isHostTimeoutAbort(ctx) ? (0,
|
|
2358
|
+
outcome.error = isHostTimeoutAbort(ctx) ? (0, import_subagent_engine_sdk10.synthesizeTimeoutOutcome)(task, final.output.stdoutText, ZCODE_ENGINE_ID).error ?? (0, import_subagent_engine_sdk10.engineTimeoutDetail)(final.output.stdoutText) : final.abortMessage ?? `engine_run_failed: zcode \u4EFB\u52A1\u88AB\u4E2D\u6B62\uFF08app-server abort \u94FE\u6536\u53E3\uFF0C\u5BBF\u4E3B\u5408\u6210\u7EC8\u6001\uFF09\u3002\u8F93\u51FA\u5C3E\u90E8: ${final.output.stdoutText.slice(-ZCODE_ERROR_TAIL_CHARS)}`;
|
|
2109
2359
|
emit({ type: "error", message: outcome.error });
|
|
2110
2360
|
}
|
|
2111
2361
|
/**
|
|
@@ -2147,17 +2397,6 @@ var ZcodeEngine = class {
|
|
|
2147
2397
|
}
|
|
2148
2398
|
for (const ev of synthesizeCoarseEvents(payload.response, payload.usage)) emit(ev);
|
|
2149
2399
|
}
|
|
2150
|
-
/**
|
|
2151
|
-
* D1 可选面:zcode 首期不支持 conversation(capabilities 声明)——同步拒绝、
|
|
2152
|
-
* 不创建进程,文案给可操作建议(A11)。
|
|
2153
|
-
*/
|
|
2154
|
-
async interact(_handle, _action) {
|
|
2155
|
-
return {
|
|
2156
|
-
ok: false,
|
|
2157
|
-
code: "engine_capability_unsupported",
|
|
2158
|
-
message: "zcode \u5F15\u64CE\u4E0D\u652F\u6301 conversation \u4EA4\u4E92\u63A7\u5236\u9762\uFF08capabilities.conversation = 'unsupported'\uFF0C\u6BCF\u4EFB\u52A1\u81EA\u5305\u542B\u4F1A\u8BDD\uFF0C\u65E0\u540C\u8FDB\u7A0B idle \u590D\u7528\uFF09\u3002\u6062\u590D\u6307\u5F15\uFF1A\u6539\u7528\u5355\u6B21 subagent \u8C03\u7528\u91CD\u65B0\u6D3E\u53D1\u4EFB\u52A1\uFF0C\u6216\u4F7F\u7528 engine: 'pi'\uFF08chatMode idle \u590D\u7528\uFF0C\u652F\u6301 message/close/cancel\uFF09\u3002"
|
|
2159
|
-
};
|
|
2160
|
-
}
|
|
2161
2400
|
/** [U7] 模型可发现性:v2 桌面登录态聚合(带凭据 provider × models),失败安全返回清单本身可能为空。 */
|
|
2162
2401
|
listModels() {
|
|
2163
2402
|
return listZcodeModels(this.deps.sources);
|
|
@@ -2178,8 +2417,12 @@ var ZcodeEngine = class {
|
|
|
2178
2417
|
* sessionId 缺失(解析失败的 run 无法定位 session)跳过①级;②级依赖
|
|
2179
2418
|
* handle.journalPath(宿主 run 后回填)。dbPath:新 handle 恒为隔离库绝对路径
|
|
2180
2419
|
* (zcodeSessionDbPath(engineDataDir),tier1 白名单集合见方法体——宿主路径仅
|
|
2181
|
-
* 「共享 HOME 时代」存量兼容);旧 records
|
|
2182
|
-
*
|
|
2420
|
+
* 「共享 HOME 时代」存量兼容);旧 records(池时代)的相对路径仍按池目录锚定
|
|
2421
|
+
* 解析(read 兼容旧数据,池目录不存在时自然落②级 journal 降级)。[池抽象降级
|
|
2422
|
+
* 2026-09-13] 锚定 key 用常量 SHARED_POOL_KEY 承载——协议面 poolKey 已删,池
|
|
2423
|
+
* 时代真实池 key 不再随 handle 传输;若旧 record 的池目录恰为 shared 布局则①级
|
|
2424
|
+
* 仍可达,其余池 key 的旧 record 直接走②级 journal 降级(30 天 TTL 同尺度衰减,
|
|
2425
|
+
* 行为安全)。
|
|
2183
2426
|
*/
|
|
2184
2427
|
async read(handle) {
|
|
2185
2428
|
if (handle.data.engineId !== ZCODE_ENGINE_ID) {
|
|
@@ -2193,21 +2436,28 @@ var ZcodeEngine = class {
|
|
|
2193
2436
|
if (zcodeDbPathAllowlist(this.deps.engineDataDir()).includes(dbPathRaw)) {
|
|
2194
2437
|
dbPath = dbPathRaw;
|
|
2195
2438
|
} else {
|
|
2196
|
-
|
|
2439
|
+
logger4.warn("[zcode-engine] record dbPath \u975E\u767D\u540D\u5355 db \u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u62D2\u7EDD \u2460\u7EA7\u8BFB\u53D6\u964D journal", {
|
|
2197
2440
|
dbPath: dbPathRaw
|
|
2198
2441
|
});
|
|
2199
2442
|
}
|
|
2200
2443
|
} else {
|
|
2201
|
-
|
|
2202
|
-
(0,
|
|
2203
|
-
dbPathRaw
|
|
2444
|
+
const poolDir = path4.resolve(
|
|
2445
|
+
(0, import_subagent_engine_sdk10.resolvePoolDir)(this.deps.engineDataDir(), ZCODE_ENGINE_ID, import_subagent_engine_sdk10.SHARED_POOL_KEY)
|
|
2204
2446
|
);
|
|
2447
|
+
const resolved = path4.resolve(poolDir, dbPathRaw);
|
|
2448
|
+
if (resolved.startsWith(poolDir + path4.sep)) {
|
|
2449
|
+
dbPath = resolved;
|
|
2450
|
+
} else {
|
|
2451
|
+
logger4.warn("[zcode-engine] record dbPath \u76F8\u5BF9\u8DEF\u5F84\u9003\u9038\u6C60\u76EE\u5F55\uFF0C\u62D2\u7EDD \u2460\u7EA7\u8BFB\u53D6\u964D journal", {
|
|
2452
|
+
dbPath: dbPathRaw
|
|
2453
|
+
});
|
|
2454
|
+
}
|
|
2205
2455
|
}
|
|
2206
2456
|
if (dbPath !== void 0) {
|
|
2207
2457
|
try {
|
|
2208
2458
|
return await readZcodeSessionView(dbPath, sessionId);
|
|
2209
2459
|
} catch (err) {
|
|
2210
|
-
|
|
2460
|
+
logger4.warn("[zcode-engine] native session read failed, degrade to journal replay", {
|
|
2211
2461
|
dbPath,
|
|
2212
2462
|
sessionId,
|
|
2213
2463
|
reason: (0, import_subagent_engine_sdk3.toErrorMessage)(err)
|
|
@@ -2233,7 +2483,7 @@ var ZcodeEngine = class {
|
|
|
2233
2483
|
const thoughtLevel = task.thinkingLevel?.trim();
|
|
2234
2484
|
if (thoughtLevel === void 0 || thoughtLevel === "") return;
|
|
2235
2485
|
if (COMMON_THOUGHT_LEVELS.includes(thoughtLevel)) return;
|
|
2236
|
-
|
|
2486
|
+
logger4.warn(
|
|
2237
2487
|
`[zcode-engine] thinkingLevel=${thoughtLevel} \u5DF2\u900F\u4F20\u4E3A thoughtLevel\uFF08\u975E\u5E38\u89C1\u6863\u4F4D\uFF09\uFF1A\u82E5\u76EE\u6807\u6A21\u578B\u4E0D\u652F\u6301\u8BE5\u6863\u4F4D\u5C06\u88AB\u5FFD\u7565/\u56DE\u843D\u5230\u6A21\u578B\u7F3A\u7701\u63A8\u7406\u6863\u4F4D\uFF08\u5E38\u89C1\u6863\u4F4D\uFF1A${COMMON_THOUGHT_LEVELS.join("/")}\uFF09\uFF1B\u6863\u4F4D\u662F\u5426\u751F\u6548\u4EE5\u6A21\u578B\u5B9E\u9645\u884C\u4E3A\u4E3A\u51C6`,
|
|
2238
2488
|
{ taskId: ctx.taskId }
|
|
2239
2489
|
);
|
|
@@ -2251,11 +2501,40 @@ var ZcodeEngine = class {
|
|
|
2251
2501
|
if (ctx.ctxModel === void 0) return;
|
|
2252
2502
|
const requested = task.model?.trim();
|
|
2253
2503
|
if (requested !== void 0 && requested !== "") return;
|
|
2254
|
-
|
|
2504
|
+
logger4.warn(
|
|
2255
2505
|
`[zcode-engine] ctx.ctxModel\uFF08${ctx.ctxModel.id}\uFF09\u88AB\u5FFD\u7565\u2014\u2014ctxModel \u662F pi \u94FE\u8DEF\u515C\u5E95\uFF0Czcode \u4E0D\u6D88\u8D39\uFF1Btask.model \u672A\u663E\u5F0F\u6307\u5B9A\uFF0C\u5B9E\u9645\u4F7F\u7528\u5F15\u64CE\u7F3A\u7701\u6A21\u578B ${modelRef}`,
|
|
2256
2506
|
{ taskId: ctx.taskId }
|
|
2257
2507
|
);
|
|
2258
2508
|
}
|
|
2509
|
+
/**
|
|
2510
|
+
* [U6 / §3.2.6 要点 3] resume 锚 → 历史前缀(interact-resume 的读半段)。
|
|
2511
|
+
*
|
|
2512
|
+
* 无锚 / 非 zcode 锚形态 → undefined(行为不变)。读通道失败(条目被 TTL 清 /
|
|
2513
|
+
* 会话失效 / 控制面错误)= 宿主侧锚判据通过后、引擎派发前的窄竞态窗——降级为
|
|
2514
|
+
* **无历史前缀的新会话**(warn 留痕;宿主 reopen 摘要承担主降级面),不炸轮:
|
|
2515
|
+
* 续聊消息本身仍可送达(模型缺历史上下文,比整轮失败可用性高,与 reopen 降级
|
|
2516
|
+
* 的「带摘要重开」语义同族)。
|
|
2517
|
+
*/
|
|
2518
|
+
async buildResumeHistoryPrefix(ctx) {
|
|
2519
|
+
const anchor = zcodeResumeAnchorOf(ctx, this.deps.engineDataDir());
|
|
2520
|
+
if (anchor === void 0) return void 0;
|
|
2521
|
+
const rt = this.ensureAppServerRuntime();
|
|
2522
|
+
let history;
|
|
2523
|
+
let tokens;
|
|
2524
|
+
try {
|
|
2525
|
+
const result = await rt.channel.resumeSession(anchor.sessionId);
|
|
2526
|
+
history = extractResumeHistory(result);
|
|
2527
|
+
tokens = extractResumeTotalTokens(result);
|
|
2528
|
+
} catch (err) {
|
|
2529
|
+
logger4.warn(
|
|
2530
|
+
`[zcode-engine] session/resume \u8BFB\u5386\u53F2\u5931\u8D25\uFF08\u951A ${anchor.sessionId}\uFF09\u2014\u2014\u964D\u7EA7\u4E3A\u65E0\u5386\u53F2\u524D\u7F00\u7684\u65B0\u4F1A\u8BDD: ${errMessage3(err)}`,
|
|
2531
|
+
{ taskId: ctx.taskId }
|
|
2532
|
+
);
|
|
2533
|
+
return void 0;
|
|
2534
|
+
}
|
|
2535
|
+
if (history.length === 0) return void 0;
|
|
2536
|
+
return buildResumeInjectionSegment(history, anchor.sessionId, tokens);
|
|
2537
|
+
}
|
|
2259
2538
|
/**
|
|
2260
2539
|
* persona 拼接后的完整 prompt(personaInjection: 'prompt'——zcode 无 flag 通道):
|
|
2261
2540
|
* appendSystemPrompt 段在前(人设/约束语境——D6 合流后 persona≡skillPath+
|
|
@@ -2265,10 +2544,42 @@ var ZcodeEngine = class {
|
|
|
2265
2544
|
buildPrompt(task, schema) {
|
|
2266
2545
|
const segments = [...task.appendSystemPrompt ?? []];
|
|
2267
2546
|
segments.push(task.prompt);
|
|
2268
|
-
if (schema !== void 0) segments.push((0,
|
|
2547
|
+
if (schema !== void 0) segments.push((0, import_subagent_engine_sdk10.buildSchemaEmulationSegment)(schema));
|
|
2269
2548
|
return segments.join("\n\n");
|
|
2270
2549
|
}
|
|
2271
2550
|
};
|
|
2551
|
+
function zcodeResumeAnchorOf(ctx, engineDataDir) {
|
|
2552
|
+
const ref = ctx.resume?.resume?.sessionRef;
|
|
2553
|
+
if (ref === void 0) return void 0;
|
|
2554
|
+
const sessionId = ref["sessionId"];
|
|
2555
|
+
const dbPath = ref["dbPath"];
|
|
2556
|
+
if (typeof sessionId !== "string" || sessionId === "") return void 0;
|
|
2557
|
+
if (typeof dbPath !== "string" || dbPath === "") return void 0;
|
|
2558
|
+
if (!zcodeDbPathAllowlist(engineDataDir).includes(dbPath)) return void 0;
|
|
2559
|
+
return { sessionId, dbPath };
|
|
2560
|
+
}
|
|
2561
|
+
function buildResumeInjectionSegment(history, priorSessionId, totalTokens, tokenBudget = ZCODE_RESUME_HISTORY_TOKEN_BUDGET) {
|
|
2562
|
+
const budgetTokens = tokenBudget;
|
|
2563
|
+
const charBudget = budgetTokens * ZCODE_RESUME_CHARS_PER_TOKEN;
|
|
2564
|
+
const lines = history.map((t) => `${t.role}: ${t.text}`);
|
|
2565
|
+
let kept = lines;
|
|
2566
|
+
let omitted = 0;
|
|
2567
|
+
while (kept.length > 1 && kept.reduce((n, l) => n + l.length + 1, 0) > charBudget) {
|
|
2568
|
+
kept = kept.slice(1);
|
|
2569
|
+
omitted++;
|
|
2570
|
+
}
|
|
2571
|
+
const omissionNote = omitted > 0 ? `[... ${omitted} older turn(s) omitted to fit the ${tokenBudget}-token history budget ...]
|
|
2572
|
+
` : "";
|
|
2573
|
+
const usageNote = totalTokens !== void 0 ? `
|
|
2574
|
+
(prior session retained ~${totalTokens} tokens of history)` : "";
|
|
2575
|
+
return `[Continued conversation] You are continuing an existing subagent conversation on a NEW session (prior session id: ${priorSessionId}). The new session has no memory of its own \u2014 the full prior conversation history recovered from the session store follows. Continue seamlessly from it; the user message after this block is the next turn of the SAME conversation.
|
|
2576
|
+
|
|
2577
|
+
<conversation_history>
|
|
2578
|
+
${omissionNote}${kept.join("\n")}
|
|
2579
|
+
</conversation_history>${usageNote}
|
|
2580
|
+
|
|
2581
|
+
`;
|
|
2582
|
+
}
|
|
2272
2583
|
var ZCODE_TURN_RETRY_MIN_BUDGET_MS = 3e5;
|
|
2273
2584
|
function resolveTransientRetryBudget(totalBudgetMs, consumedMs) {
|
|
2274
2585
|
if (totalBudgetMs === void 0) return { state: "unbounded" };
|
|
@@ -2286,8 +2597,8 @@ function errMessage3(err) {
|
|
|
2286
2597
|
return (0, import_subagent_engine_sdk3.toErrorMessage)(err);
|
|
2287
2598
|
}
|
|
2288
2599
|
function delayResolved(ms, value) {
|
|
2289
|
-
return new Promise((
|
|
2290
|
-
const t = setTimeout(() =>
|
|
2600
|
+
return new Promise((resolve2) => {
|
|
2601
|
+
const t = setTimeout(() => resolve2(value), ms);
|
|
2291
2602
|
if (typeof t.unref === "function") t.unref();
|
|
2292
2603
|
});
|
|
2293
2604
|
}
|
|
@@ -2357,9 +2668,6 @@ function authoritativeTerminalStatus(r) {
|
|
|
2357
2668
|
if (r.lastTerminalStatus !== void 0) return r.lastTerminalStatus;
|
|
2358
2669
|
return r.terminal.source === "turn.terminal" ? r.terminal.status : void 0;
|
|
2359
2670
|
}
|
|
2360
|
-
function isFailedTerminalStatus(status) {
|
|
2361
|
-
return status === "failed" || status === "error";
|
|
2362
|
-
}
|
|
2363
2671
|
function parsedAppServerAttempt(task, r) {
|
|
2364
2672
|
if (isFailedTerminalStatus(authoritativeTerminalStatus(r))) {
|
|
2365
2673
|
return failedTerminalAppServerAttempt(r);
|
|
@@ -2369,7 +2677,7 @@ function parsedAppServerAttempt(task, r) {
|
|
|
2369
2677
|
kind: "parsed",
|
|
2370
2678
|
output: syntheticAppServerOutput(0),
|
|
2371
2679
|
payload: turnResultToPayload(r),
|
|
2372
|
-
...schema !== void 0 ? { schemaResult: (0,
|
|
2680
|
+
...schema !== void 0 ? { schemaResult: (0, import_subagent_engine_sdk10.extractAndValidateStructuredOutput)(r.response, schema) } : {}
|
|
2373
2681
|
};
|
|
2374
2682
|
}
|
|
2375
2683
|
function failedTerminalAppServerAttempt(r) {
|
|
@@ -2440,16 +2748,16 @@ function buildAppServerTimeoutMessage(err, sessionId, stopPath, retried = false)
|
|
|
2440
2748
|
${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`;
|
|
2441
2749
|
}
|
|
2442
2750
|
function isHostTimeoutAbort(ctx) {
|
|
2443
|
-
return ctx.signal?.aborted === true && ctx.signal.reason ===
|
|
2751
|
+
return ctx.signal?.aborted === true && ctx.signal.reason === import_subagent_engine_sdk10.HOST_TIMEOUT_ABORT_REASON;
|
|
2444
2752
|
}
|
|
2445
2753
|
var PROBE_STDOUT_CAP_CHARS = 4096;
|
|
2446
2754
|
async function defaultProbeVersion(cliPath, dataDir) {
|
|
2447
2755
|
try {
|
|
2448
|
-
return await new Promise((
|
|
2449
|
-
const child = (0,
|
|
2756
|
+
return await new Promise((resolve2, reject) => {
|
|
2757
|
+
const child = (0, import_subagent_engine_sdk10.spawnEngineChild)({
|
|
2450
2758
|
command: "node",
|
|
2451
2759
|
args: [cliPath, "--version"],
|
|
2452
|
-
env: (0,
|
|
2760
|
+
env: (0, import_subagent_engine_sdk10.buildEngineChildEnv)(process.env, { dataDir }),
|
|
2453
2761
|
stdout: "pipe",
|
|
2454
2762
|
stderr: "ignore",
|
|
2455
2763
|
signal: AbortSignal.timeout(PROBE_VERSION_TIMEOUT_MS)
|
|
@@ -2462,11 +2770,11 @@ async function defaultProbeVersion(cliPath, dataDir) {
|
|
|
2462
2770
|
child.once("error", reject);
|
|
2463
2771
|
child.once("close", (code) => {
|
|
2464
2772
|
if (code !== 0) reject(new Error(`zcode --version exited with code ${code}`));
|
|
2465
|
-
else
|
|
2773
|
+
else resolve2(out.trim().split("\n")[0]?.trim() || void 0);
|
|
2466
2774
|
});
|
|
2467
2775
|
});
|
|
2468
2776
|
} catch (err) {
|
|
2469
|
-
|
|
2777
|
+
logger4.debug(
|
|
2470
2778
|
`[zcode-engine] probe version check failed (best-effort continue): ${(0, import_subagent_engine_sdk3.toErrorMessage)(err)}`
|
|
2471
2779
|
);
|
|
2472
2780
|
return void 0;
|
|
@@ -2475,7 +2783,7 @@ async function defaultProbeVersion(cliPath, dataDir) {
|
|
|
2475
2783
|
|
|
2476
2784
|
// src/registration.ts
|
|
2477
2785
|
function defaultEngineDataDir() {
|
|
2478
|
-
return (0,
|
|
2786
|
+
return (0, import_subagent_engine_sdk11.resolveEngineDataDir)(process.env);
|
|
2479
2787
|
}
|
|
2480
2788
|
function createZcodeEngine(deps) {
|
|
2481
2789
|
return new ZcodeEngine(deps);
|
|
@@ -2488,7 +2796,7 @@ function createDefaultZcodeEngine() {
|
|
|
2488
2796
|
}
|
|
2489
2797
|
|
|
2490
2798
|
// src/port-types.ts
|
|
2491
|
-
var
|
|
2799
|
+
var import_subagent_engine_sdk12 = require("@zhushanwen/subagent-engine-sdk");
|
|
2492
2800
|
|
|
2493
2801
|
// src/server.ts
|
|
2494
2802
|
var REVERSE_TIMEOUT_DEFAULT_MS = 6e4;
|
|
@@ -2509,11 +2817,11 @@ var EngineProtocolServer = class {
|
|
|
2509
2817
|
}
|
|
2510
2818
|
/** 入站帧消费(请求帧 + 反向请求应答帧;main.ts 的行解析器拆行后喂入)。 */
|
|
2511
2819
|
handleFrame(frame) {
|
|
2512
|
-
if ((0,
|
|
2820
|
+
if ((0, import_subagent_engine_sdk13.isResponseFrame)(frame)) {
|
|
2513
2821
|
this.settleReverse(frame.id, frame);
|
|
2514
2822
|
return;
|
|
2515
2823
|
}
|
|
2516
|
-
if ((0,
|
|
2824
|
+
if ((0, import_subagent_engine_sdk13.isReverseRequestFrame)(frame)) {
|
|
2517
2825
|
this.write({
|
|
2518
2826
|
id: 0,
|
|
2519
2827
|
error: {
|
|
@@ -2535,11 +2843,11 @@ var EngineProtocolServer = class {
|
|
|
2535
2843
|
}
|
|
2536
2844
|
}
|
|
2537
2845
|
}
|
|
2538
|
-
/**
|
|
2846
|
+
/** 9 正向方法分发(表驱动:method → 处理器;未知方法 → engine_protocol_unknown_method)。 */
|
|
2539
2847
|
async dispatch(id, method, params) {
|
|
2540
2848
|
const handler = this.methodHandlers[method];
|
|
2541
2849
|
if (handler === void 0) {
|
|
2542
|
-
throw new
|
|
2850
|
+
throw new import_subagent_engine_sdk13.EngineSdkError(
|
|
2543
2851
|
"engine_protocol_unknown_method",
|
|
2544
2852
|
`unknown protocol method: ${method} (request id ${id})`,
|
|
2545
2853
|
"The engine speaks protocol v1; check the installed engine package version vs the host."
|
|
@@ -2548,7 +2856,7 @@ var EngineProtocolServer = class {
|
|
|
2548
2856
|
return handler(params);
|
|
2549
2857
|
}
|
|
2550
2858
|
/**
|
|
2551
|
-
*
|
|
2859
|
+
* 9 正向方法 → 处理器映射(每个处理器消费原始 params 并自行收敛类型——
|
|
2552
2860
|
* 与原 switch case 表达式一一对应)。
|
|
2553
2861
|
*/
|
|
2554
2862
|
methodHandlers = {
|
|
@@ -2556,7 +2864,6 @@ var EngineProtocolServer = class {
|
|
|
2556
2864
|
probe: (p) => this.engine.probe(probeParamsOf(p)),
|
|
2557
2865
|
run: (p) => this.run(p),
|
|
2558
2866
|
cancel: (p) => this.cancel(p),
|
|
2559
|
-
interact: (p) => this.interact(p),
|
|
2560
2867
|
read: (p) => this.read(p),
|
|
2561
2868
|
listModels: () => ({ models: this.engine.listModels?.() ?? null }),
|
|
2562
2869
|
validateModel: (p) => this.validateModel(p),
|
|
@@ -2568,17 +2875,17 @@ var EngineProtocolServer = class {
|
|
|
2568
2875
|
};
|
|
2569
2876
|
// ── initialize:版本协商(越界 → engine_protocol_mismatch)+ 能力应答 ──
|
|
2570
2877
|
initialize(params) {
|
|
2571
|
-
if (params?.protocolVersion !==
|
|
2572
|
-
throw new
|
|
2878
|
+
if (params?.protocolVersion !== import_subagent_engine_sdk13.ENGINE_PROTOCOL_VERSION) {
|
|
2879
|
+
throw new import_subagent_engine_sdk13.EngineSdkError(
|
|
2573
2880
|
"engine_protocol_mismatch",
|
|
2574
|
-
`host protocol version ${String(params?.protocolVersion)} is not compatible with engine protocol v${
|
|
2575
|
-
`Upgrade the engine package or the host so both speak protocol v${
|
|
2881
|
+
`host protocol version ${String(params?.protocolVersion)} is not compatible with engine protocol v${import_subagent_engine_sdk13.ENGINE_PROTOCOL_VERSION}`,
|
|
2882
|
+
`Upgrade the engine package or the host so both speak protocol v${import_subagent_engine_sdk13.ENGINE_PROTOCOL_VERSION}.`
|
|
2576
2883
|
);
|
|
2577
2884
|
}
|
|
2578
2885
|
this.initialized = true;
|
|
2579
2886
|
const models = this.engine.listModels?.() ?? null;
|
|
2580
2887
|
return {
|
|
2581
|
-
protocolVersion:
|
|
2888
|
+
protocolVersion: import_subagent_engine_sdk13.ENGINE_PROTOCOL_VERSION,
|
|
2582
2889
|
engineId: this.engine.id,
|
|
2583
2890
|
engineVersion: ZCODE_ADAPTER_VERSION,
|
|
2584
2891
|
adapterVersion: ZCODE_ADAPTER_VERSION,
|
|
@@ -2589,7 +2896,7 @@ var EngineProtocolServer = class {
|
|
|
2589
2896
|
// ── run:协议载荷 → 本地 AgentCallOpts/RunContext;事件 → 通知/host 通道 ──
|
|
2590
2897
|
async run(params) {
|
|
2591
2898
|
if (!this.initialized) {
|
|
2592
|
-
throw new
|
|
2899
|
+
throw new import_subagent_engine_sdk13.EngineSdkError(
|
|
2593
2900
|
"engine_protocol_not_initialized",
|
|
2594
2901
|
"run before initialize is a protocol violation",
|
|
2595
2902
|
"The host must complete the initialize handshake before dispatching runs."
|
|
@@ -2600,24 +2907,23 @@ var EngineProtocolServer = class {
|
|
|
2600
2907
|
const active = { controller, seq: 0 };
|
|
2601
2908
|
this.activeRuns.set(runId, active);
|
|
2602
2909
|
const fullTask = { ...task, ...ctx.model !== void 0 ? { model: ctx.model } : {} };
|
|
2603
|
-
const ctxModel = (0,
|
|
2910
|
+
const ctxModel = (0, import_subagent_engine_sdk12.parseCtxModel)(ctx.ctxModel);
|
|
2604
2911
|
const stream = ctx.streamMode === "stream" ? { onDelta: (delta) => {
|
|
2605
2912
|
void this.reverseRequestInternal("host/streamDelta", { runId, delta });
|
|
2606
2913
|
} } : void 0;
|
|
2607
2914
|
const runCtx = {
|
|
2608
2915
|
taskId: runId,
|
|
2609
|
-
poolKey: ctx.poolKey,
|
|
2610
2916
|
signal: controller.signal,
|
|
2611
2917
|
onEvent: (event) => this.emitEvent(runId, event),
|
|
2612
2918
|
...ctxModel !== void 0 ? { ctxModel } : {},
|
|
2613
2919
|
...stream !== void 0 ? { stream } : {},
|
|
2614
2920
|
...ctx.schemaEnv !== void 0 ? { schemaEnv: ctx.schemaEnv } : {},
|
|
2615
2921
|
...ctx.engineFallback !== void 0 ? { engineFallback: ctx.engineFallback } : {},
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
},
|
|
2922
|
+
// [U6 / §3.2.6 要点 3] resume 锚点透传(宿主 → 引擎的续聊通道:zcode 锚
|
|
2923
|
+
// sessionRef {sessionId, dbPath},引擎侧 resume 读 + 新 session 注入消费)。
|
|
2924
|
+
...params.resume !== void 0 ? { resume: params.resume } : {},
|
|
2619
2925
|
onHandleReady: (partial) => {
|
|
2620
|
-
void this.reverseRequestInternal("host/handleReady", { runId, sessionRef: partial.sessionRef
|
|
2926
|
+
void this.reverseRequestInternal("host/handleReady", { runId, sessionRef: partial.sessionRef });
|
|
2621
2927
|
}
|
|
2622
2928
|
};
|
|
2623
2929
|
try {
|
|
@@ -2632,15 +2938,12 @@ var EngineProtocolServer = class {
|
|
|
2632
2938
|
if (active !== void 0) active.controller.abort(new Error(`cancelled by host: ${params.reason}`));
|
|
2633
2939
|
return { ok: true };
|
|
2634
2940
|
}
|
|
2635
|
-
async interact(params) {
|
|
2636
|
-
return this.engine.interact({ data: params.handle }, params.action);
|
|
2637
|
-
}
|
|
2638
2941
|
read(params) {
|
|
2639
2942
|
return this.engine.read({ data: params.handle });
|
|
2640
2943
|
}
|
|
2641
2944
|
validateModel(params) {
|
|
2642
2945
|
if (this.engine.validateModel === void 0) {
|
|
2643
|
-
throw new
|
|
2946
|
+
throw new import_subagent_engine_sdk13.EngineSdkError(
|
|
2644
2947
|
"engine_capability_unsupported",
|
|
2645
2948
|
"engine does not implement validateModel",
|
|
2646
2949
|
"Manifest omits modelCatalog; model validation falls back to run-time engine checks."
|
|
@@ -2666,14 +2969,14 @@ var EngineProtocolServer = class {
|
|
|
2666
2969
|
}
|
|
2667
2970
|
reverseRequestInternal(method, params) {
|
|
2668
2971
|
const id = `rev-${++this.revSeq}`;
|
|
2669
|
-
return new Promise((
|
|
2972
|
+
return new Promise((resolve2, reject) => {
|
|
2670
2973
|
const timer = setTimeout(() => {
|
|
2671
2974
|
this.reversePending.delete(id);
|
|
2672
2975
|
this.reverseClock?.settled(id);
|
|
2673
2976
|
reject(new Error(`reverse request ${method} (${id}) timed out after ${this.reverseTimeoutMs}ms`));
|
|
2674
2977
|
}, this.reverseTimeoutMs);
|
|
2675
2978
|
if (typeof timer.unref === "function") timer.unref();
|
|
2676
|
-
this.reversePending.set(id, { resolve, reject, timer });
|
|
2979
|
+
this.reversePending.set(id, { resolve: resolve2, reject, timer });
|
|
2677
2980
|
this.reverseClock?.started(id);
|
|
2678
2981
|
this.write({ id, method, params });
|
|
2679
2982
|
});
|
|
@@ -2694,7 +2997,7 @@ function probeParamsOf(params) {
|
|
|
2694
2997
|
return typeof params === "object" && params !== null ? params : void 0;
|
|
2695
2998
|
}
|
|
2696
2999
|
function toProtocolError(err) {
|
|
2697
|
-
if (err instanceof
|
|
3000
|
+
if (err instanceof import_subagent_engine_sdk13.EngineSdkError) return err.toStructured();
|
|
2698
3001
|
return {
|
|
2699
3002
|
code: "engine_run_failed",
|
|
2700
3003
|
message: (0, import_subagent_engine_sdk3.toErrorMessage)(err),
|
|
@@ -2703,8 +3006,8 @@ function toProtocolError(err) {
|
|
|
2703
3006
|
}
|
|
2704
3007
|
|
|
2705
3008
|
// src/main.ts
|
|
2706
|
-
var clock = (0,
|
|
2707
|
-
(0,
|
|
3009
|
+
var clock = (0, import_subagent_engine_sdk14.armEngineSelfDestruct)({ stdin: process.stdin });
|
|
3010
|
+
(0, import_subagent_engine_sdk14.runEngineCliEntry)({
|
|
2708
3011
|
component: "zcode-engine-cli",
|
|
2709
3012
|
server: new EngineProtocolServer({
|
|
2710
3013
|
write: (frame) => {
|