@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/index.cjs
CHANGED
|
@@ -46,7 +46,7 @@ __export(src_exports, {
|
|
|
46
46
|
module.exports = __toCommonJS(src_exports);
|
|
47
47
|
|
|
48
48
|
// src/server.ts
|
|
49
|
-
var
|
|
49
|
+
var import_subagent_engine_sdk13 = require("@zhushanwen/subagent-engine-sdk");
|
|
50
50
|
|
|
51
51
|
// src/constants.ts
|
|
52
52
|
var ZCODE_ENGINE_ID = "zcode";
|
|
@@ -72,21 +72,26 @@ function parseZcodeTurnTimeoutEnv(raw) {
|
|
|
72
72
|
if (!Number.isFinite(parsed)) return { state: "invalid" };
|
|
73
73
|
return { state: "valid", ms: parsed };
|
|
74
74
|
}
|
|
75
|
-
var ZCODE_SHARED_POOL_KEY = "shared";
|
|
76
75
|
var ZCODE_APPSERVER_STOP_TIMEOUT_MS = 3e3;
|
|
77
76
|
var ZCODE_APPSERVER_ABORT_GRACE_MS = 3e3;
|
|
78
77
|
var ZCODE_APPSERVER_ERR_MODEL_CONFIG_MISSING = -32603;
|
|
79
78
|
var ZCODE_APPSERVER_ERR_BUSY_SESSION = -32010;
|
|
80
79
|
var ZCODE_APPSERVER_HARVEST_GRACE_MS = 1e3;
|
|
80
|
+
function isFailedTerminalStatus(status) {
|
|
81
|
+
return status === "failed" || status === "error";
|
|
82
|
+
}
|
|
83
|
+
var ZCODE_RESUME_HISTORY_TOKEN_BUDGET = 24e3;
|
|
84
|
+
var ZCODE_RESUME_CHARS_PER_TOKEN = 4;
|
|
85
|
+
var ZCODE_SESSION_SWEEP_DEFER_MS = 50;
|
|
81
86
|
|
|
82
87
|
// src/registration.ts
|
|
83
|
-
var
|
|
88
|
+
var import_subagent_engine_sdk11 = require("@zhushanwen/subagent-engine-sdk");
|
|
84
89
|
|
|
85
90
|
// src/zcode-engine.ts
|
|
86
|
-
var
|
|
91
|
+
var fs6 = __toESM(require("fs"), 1);
|
|
87
92
|
var path4 = __toESM(require("path"), 1);
|
|
88
|
-
var import_subagent_engine_sdk8 = require("@zhushanwen/subagent-engine-sdk");
|
|
89
93
|
var import_subagent_engine_sdk9 = require("@zhushanwen/subagent-engine-sdk");
|
|
94
|
+
var import_subagent_engine_sdk10 = require("@zhushanwen/subagent-engine-sdk");
|
|
90
95
|
|
|
91
96
|
// src/journal-io.ts
|
|
92
97
|
var import_subagent_engine_sdk = require("@zhushanwen/subagent-engine-sdk");
|
|
@@ -798,7 +803,7 @@ var AppServerConnection = class {
|
|
|
798
803
|
}
|
|
799
804
|
const timeoutMs = opts?.timeoutMs ?? this.requestTimeoutMs;
|
|
800
805
|
const id = ++this.reqSeq;
|
|
801
|
-
return new Promise((
|
|
806
|
+
return new Promise((resolve2, reject) => {
|
|
802
807
|
const timer = setTimeout(() => {
|
|
803
808
|
this.pending.delete(id);
|
|
804
809
|
reject(new Error(`\u8BF7\u6C42 ${method} \u8D85\u65F6\uFF08${timeoutMs}ms\uFF09`));
|
|
@@ -806,7 +811,7 @@ var AppServerConnection = class {
|
|
|
806
811
|
this.pending.set(id, {
|
|
807
812
|
// 泛型 T 是调用方对线上 unknown 结果的视图声明,连接层不做运行时校验
|
|
808
813
|
// (协议层保持透明,结构校验归会话层/消费方)。
|
|
809
|
-
resolve,
|
|
814
|
+
resolve: resolve2,
|
|
810
815
|
reject,
|
|
811
816
|
timer,
|
|
812
817
|
method
|
|
@@ -1157,6 +1162,46 @@ function extractReadUsage(readResult) {
|
|
|
1157
1162
|
}
|
|
1158
1163
|
return isRecord3(readResult.usage) ? readResult.usage : void 0;
|
|
1159
1164
|
}
|
|
1165
|
+
function extractResumeHistory(resumeResult) {
|
|
1166
|
+
if (!isRecord3(resumeResult) || !Array.isArray(resumeResult.messages)) return [];
|
|
1167
|
+
const turns = [];
|
|
1168
|
+
for (const m of resumeResult.messages) {
|
|
1169
|
+
if (!isRecord3(m)) continue;
|
|
1170
|
+
const role = messageRole(m);
|
|
1171
|
+
if (role !== "user" && role !== "assistant") continue;
|
|
1172
|
+
const text = partsToText(m.parts) ?? contentToText(m.content);
|
|
1173
|
+
if (text === void 0 || text === "") continue;
|
|
1174
|
+
turns.push({ role, text });
|
|
1175
|
+
}
|
|
1176
|
+
return turns;
|
|
1177
|
+
}
|
|
1178
|
+
function accumulateTokenFields(source, keys, acc) {
|
|
1179
|
+
for (const key of keys) {
|
|
1180
|
+
const raw = source[key];
|
|
1181
|
+
const v = typeof raw === "number" ? raw : Number(raw);
|
|
1182
|
+
if (Number.isFinite(v) && v > 0) {
|
|
1183
|
+
acc.total += v;
|
|
1184
|
+
acc.has = true;
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
function accumulateStepFinishTokens(parts, acc) {
|
|
1189
|
+
for (const p of parts) {
|
|
1190
|
+
if (!isRecord3(p) || p.type !== "step-finish" || !isRecord3(p.tokens)) continue;
|
|
1191
|
+
const t = p.tokens;
|
|
1192
|
+
accumulateTokenFields(t, ["input", "output"], acc);
|
|
1193
|
+
if (isRecord3(t.cache)) accumulateTokenFields(t.cache, ["read", "write"], acc);
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
function extractResumeTotalTokens(resumeResult) {
|
|
1197
|
+
if (!isRecord3(resumeResult) || !Array.isArray(resumeResult.messages)) return void 0;
|
|
1198
|
+
const acc = { total: 0, has: false };
|
|
1199
|
+
for (const m of resumeResult.messages) {
|
|
1200
|
+
if (!isRecord3(m) || messageRole(m) !== "assistant" || !Array.isArray(m.parts)) continue;
|
|
1201
|
+
accumulateStepFinishTokens(m.parts, acc);
|
|
1202
|
+
}
|
|
1203
|
+
return acc.has ? acc.total : void 0;
|
|
1204
|
+
}
|
|
1160
1205
|
var TurnTimeoutError = class extends Error {
|
|
1161
1206
|
kind;
|
|
1162
1207
|
elapsed;
|
|
@@ -1317,6 +1362,17 @@ var SessionChannel = class {
|
|
|
1317
1362
|
);
|
|
1318
1363
|
}
|
|
1319
1364
|
}
|
|
1365
|
+
/**
|
|
1366
|
+
* session/resume 读通道([U6 / §3.2.6 要点 3,P-1 探针实证]):应答自带完整
|
|
1367
|
+
* 双向 messages 历史(user/assistant 全量、tokens、parts)——zcode 续聊选型的
|
|
1368
|
+
* 历史来源(读通道成立;原地 resume 续写被 -32031 卡死,写通道不可用)。错误
|
|
1369
|
+
* 原样上抛(调用方决定降级形态——引擎侧 warn 后无历史前缀开新会话)。
|
|
1370
|
+
* 经 conn.request 惰性启动连接(resume 是 run 的**首个**请求——调用时点连接
|
|
1371
|
+
* 可能尚未启动,与 readBestEffort 的「已死跳过」判据不同场景,不做 alive 守卫)。
|
|
1372
|
+
*/
|
|
1373
|
+
async resumeSession(sessionId) {
|
|
1374
|
+
return this.conn.request("session/resume", { sessionId }, { timeoutMs: ZCODE_APPSERVER_TURN_READ_TIMEOUT_MS });
|
|
1375
|
+
}
|
|
1320
1376
|
/**
|
|
1321
1377
|
* session/close(A.2 ⑦,D4 用后即毁——回收引擎驻留内存,SQLite 持久化保留)。
|
|
1322
1378
|
* best-effort:失败只 warn 不抛(会话已终态,close 失败只泄漏一个驻留会话,
|
|
@@ -1393,7 +1449,13 @@ var SessionChannel = class {
|
|
|
1393
1449
|
});
|
|
1394
1450
|
const turn = {
|
|
1395
1451
|
sessionId,
|
|
1396
|
-
callbacks: {
|
|
1452
|
+
callbacks: {
|
|
1453
|
+
onTextDelta: opts.onTextDelta,
|
|
1454
|
+
onThinkingDelta: opts.onThinkingDelta,
|
|
1455
|
+
// [PR3] tool 执行期活性回调(SessionTurnCallbacks.onActivity 注释——宿主侧
|
|
1456
|
+
// 无进展守护的工具执行期刷新面)
|
|
1457
|
+
onActivity: opts.onActivity
|
|
1458
|
+
},
|
|
1397
1459
|
settled: false,
|
|
1398
1460
|
deltas: [],
|
|
1399
1461
|
finalText: void 0,
|
|
@@ -1509,7 +1571,9 @@ var SessionChannel = class {
|
|
|
1509
1571
|
if (payload === void 0) return;
|
|
1510
1572
|
this.refreshIdle(turn);
|
|
1511
1573
|
if (this.applyFinalFrame(turn, payload)) return;
|
|
1512
|
-
this.applyStreamDelta(turn, payload)
|
|
1574
|
+
if (!this.applyStreamDelta(turn, payload) && !turn.settled) {
|
|
1575
|
+
turn.callbacks.onActivity?.();
|
|
1576
|
+
}
|
|
1513
1577
|
}
|
|
1514
1578
|
/**
|
|
1515
1579
|
* 收尾帧判定与吸收(A.2 ⑤ 两种形态:payload.response / stopReason+content 变体)。
|
|
@@ -1533,9 +1597,12 @@ var SessionChannel = class {
|
|
|
1533
1597
|
/** 增量 delta 分发:非空 delta 入账 + 回调;终态后迟到丢弃(不变量 2)。
|
|
1534
1598
|
* kind 区分两通道(F2):reasoning_delta 只走 thinking 回调(不入 deltas 账本
|
|
1535
1599
|
* ——deltas 是 response 兜底聚合,推理文本不是答案正文);text_delta / kind
|
|
1536
|
-
* 缺席走 text 路径。
|
|
1600
|
+
* 缺席走 text 路径。
|
|
1601
|
+
* 返回值([PR3]):帧被 delta 路径消费(thinking 或 text,回调若注册则已触发)
|
|
1602
|
+
* → true;无 delta / 空 delta / 终态后迟到丢弃 → false(handleSessionEvent 据
|
|
1603
|
+
* 此分流 onActivity——delta 帧已是宿主可见进展,不双发活性信号)。 */
|
|
1537
1604
|
applyStreamDelta(turn, payload) {
|
|
1538
|
-
if (typeof payload.delta !== "string" || payload.delta === "") return;
|
|
1605
|
+
if (typeof payload.delta !== "string" || payload.delta === "") return false;
|
|
1539
1606
|
if (turn.settled) {
|
|
1540
1607
|
logger2.warn(
|
|
1541
1608
|
`\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(
|
|
@@ -1543,14 +1610,15 @@ var SessionChannel = class {
|
|
|
1543
1610
|
DELTA_LOG_CHARS
|
|
1544
1611
|
)}`
|
|
1545
1612
|
);
|
|
1546
|
-
return;
|
|
1613
|
+
return false;
|
|
1547
1614
|
}
|
|
1548
1615
|
if (payload.kind === "reasoning_delta") {
|
|
1549
1616
|
turn.callbacks.onThinkingDelta?.(payload.delta);
|
|
1550
|
-
return;
|
|
1617
|
+
return true;
|
|
1551
1618
|
}
|
|
1552
1619
|
turn.deltas.push(payload.delta);
|
|
1553
1620
|
turn.callbacks.onTextDelta?.(payload.delta);
|
|
1621
|
+
return true;
|
|
1554
1622
|
}
|
|
1555
1623
|
handleTelemetry(params) {
|
|
1556
1624
|
if (!isRecord3(params)) return;
|
|
@@ -1570,13 +1638,38 @@ var SessionChannel = class {
|
|
|
1570
1638
|
turn.lastTerminalStatus = status;
|
|
1571
1639
|
this.recordTerminalError(turn, params);
|
|
1572
1640
|
if (turn.settled) {
|
|
1573
|
-
|
|
1574
|
-
`\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`
|
|
1575
|
-
);
|
|
1641
|
+
this.logLateTerminal(turn, status);
|
|
1576
1642
|
return;
|
|
1577
1643
|
}
|
|
1578
1644
|
turn.settle({ status, source: "turn.terminal" });
|
|
1579
1645
|
}
|
|
1646
|
+
/**
|
|
1647
|
+
* 已落定 turn 的迟到权威终态分级日志(P-Z2 后续:常态迟到降噪)。真机实证该
|
|
1648
|
+
* 形态的唯一可达路径是 success 终态常态迟到(final-frame 先落定 + 权威
|
|
1649
|
+
* turn.terminal 迟到)——即每个成功任务必经;原无条件 warn 经 SDK cli-entry
|
|
1650
|
+
* 的 stderr 兜底 → runtime [rpc:stderr] 全量 console.error 链路,每个成功任务
|
|
1651
|
+
* 产一条零异常区分度的 ERROR 级日志。按权威 status 分级(落定语义不动——
|
|
1652
|
+
* lastTerminalStatus/lastTerminalError 的入账在上游无条件路径完成):
|
|
1653
|
+
* - "success":常态迟到,零日志;
|
|
1654
|
+
* - "interrupted":用户中断形态,debug(stderr 兜底对 debug no-op——对齐
|
|
1655
|
+
* SDK logger CONSOLE_SINK 语义,host/log 反向请求侧仍可观测);
|
|
1656
|
+
* - 失败类(isFailedTerminalStatus,与引擎失败分流同口径)与 unknown/未识别
|
|
1657
|
+
* status:保守 warn(原样 status 已写入文案)——假成功识破的防御面,理论
|
|
1658
|
+
* 不可达但保留,宁可误报不静默。
|
|
1659
|
+
*/
|
|
1660
|
+
logLateTerminal(turn, status) {
|
|
1661
|
+
if (status === "success") return;
|
|
1662
|
+
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`;
|
|
1663
|
+
if (isFailedTerminalStatus(status)) {
|
|
1664
|
+
logger2.warn(message);
|
|
1665
|
+
return;
|
|
1666
|
+
}
|
|
1667
|
+
if (status === "interrupted") {
|
|
1668
|
+
logger2.debug(message);
|
|
1669
|
+
return;
|
|
1670
|
+
}
|
|
1671
|
+
logger2.warn(message);
|
|
1672
|
+
}
|
|
1580
1673
|
/** terminal 帧专属错误信息入账(⛔P-Z2 实证:真实 failed 终态的 errorCode/errorMessage
|
|
1581
1674
|
* 只在 terminal 帧携带,read/delta 拿不到——先到/迟到都记录,消费层合成失败
|
|
1582
1675
|
* 文案时优先采信)。二者均缺失时不挂 lastTerminalError 字段。 */
|
|
@@ -1626,8 +1719,166 @@ var SessionChannel = class {
|
|
|
1626
1719
|
}
|
|
1627
1720
|
};
|
|
1628
1721
|
|
|
1629
|
-
// src/
|
|
1722
|
+
// src/session-db-maintenance.ts
|
|
1723
|
+
var fs5 = __toESM(require("fs"), 1);
|
|
1724
|
+
var import_subagent_engine_sdk8 = require("@zhushanwen/subagent-engine-sdk");
|
|
1630
1725
|
var logger3 = (0, import_subagent_engine_sdk8.getLogger)("subagents");
|
|
1726
|
+
var ZCODE_SESSION_TTL_MS = 2592e6;
|
|
1727
|
+
var ZCODE_SESSION_SWEEP_INTERVAL_MS = 864e5;
|
|
1728
|
+
var SWEEP_BUSY_TIMEOUT_MS = 5e3;
|
|
1729
|
+
var SESSION_CHILD_TABLES = [
|
|
1730
|
+
"message",
|
|
1731
|
+
"todo",
|
|
1732
|
+
"session_entry",
|
|
1733
|
+
"session_input",
|
|
1734
|
+
"session_target",
|
|
1735
|
+
"model_usage",
|
|
1736
|
+
"turn_usage",
|
|
1737
|
+
"tool_usage"
|
|
1738
|
+
];
|
|
1739
|
+
function loadDatabaseSyncCtor() {
|
|
1740
|
+
const getBuiltin = process.getBuiltinModule;
|
|
1741
|
+
if (typeof getBuiltin !== "function") return void 0;
|
|
1742
|
+
const mod = getBuiltin("node:sqlite");
|
|
1743
|
+
return typeof mod?.DatabaseSync === "function" ? mod.DatabaseSync : void 0;
|
|
1744
|
+
}
|
|
1745
|
+
function sessionLastActivity(row) {
|
|
1746
|
+
for (const v of [row.time_updated, row.time_created]) {
|
|
1747
|
+
if (typeof v === "number" && Number.isFinite(v)) return v;
|
|
1748
|
+
}
|
|
1749
|
+
return null;
|
|
1750
|
+
}
|
|
1751
|
+
function collectExpiredSessions(db, cutoff, keep) {
|
|
1752
|
+
const rows = db.prepare("SELECT id, time_updated, time_created FROM session").all();
|
|
1753
|
+
const expired = [];
|
|
1754
|
+
let keptActive = 0;
|
|
1755
|
+
for (const row of rows) {
|
|
1756
|
+
if (typeof row.id !== "string" || row.id === "") continue;
|
|
1757
|
+
const last = sessionLastActivity(row);
|
|
1758
|
+
if (last === null || last >= cutoff) continue;
|
|
1759
|
+
if (keep.has(row.id)) {
|
|
1760
|
+
keptActive++;
|
|
1761
|
+
continue;
|
|
1762
|
+
}
|
|
1763
|
+
expired.push(row.id);
|
|
1764
|
+
}
|
|
1765
|
+
return { expired, keptActive };
|
|
1766
|
+
}
|
|
1767
|
+
function ensureForeignKeysOn(db) {
|
|
1768
|
+
db.exec("PRAGMA foreign_keys = ON");
|
|
1769
|
+
const fkOn = db.prepare("PRAGMA foreign_keys").get();
|
|
1770
|
+
if (fkOn?.foreign_keys !== 1) {
|
|
1771
|
+
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");
|
|
1772
|
+
}
|
|
1773
|
+
}
|
|
1774
|
+
function listPresentTables(db) {
|
|
1775
|
+
return new Set(
|
|
1776
|
+
db.prepare("SELECT name FROM sqlite_master WHERE type = 'table'").all().map((r) => typeof r.name === "string" ? r.name : "")
|
|
1777
|
+
);
|
|
1778
|
+
}
|
|
1779
|
+
var DELETE_BATCH_SIZE = 500;
|
|
1780
|
+
function chunkIds(ids, size) {
|
|
1781
|
+
const batches = [];
|
|
1782
|
+
for (let i = 0; i < ids.length; i += size) batches.push(ids.slice(i, i + size));
|
|
1783
|
+
return batches;
|
|
1784
|
+
}
|
|
1785
|
+
function deleteExpiredSessionsInTx(db, expired, present) {
|
|
1786
|
+
db.exec("BEGIN");
|
|
1787
|
+
try {
|
|
1788
|
+
let swept = 0;
|
|
1789
|
+
for (const batch of chunkIds(expired, DELETE_BATCH_SIZE)) {
|
|
1790
|
+
const ph = batch.map(() => "?").join(", ");
|
|
1791
|
+
for (const table of SESSION_CHILD_TABLES) {
|
|
1792
|
+
if (present.has(table)) db.prepare(`DELETE FROM ${table} WHERE session_id IN (${ph})`).run(...batch);
|
|
1793
|
+
}
|
|
1794
|
+
if (present.has("session_task_link")) {
|
|
1795
|
+
db.prepare(`DELETE FROM session_task_link WHERE child_session_id IN (${ph})`).run(...batch);
|
|
1796
|
+
db.prepare(`UPDATE session_task_link SET parent_session_id = NULL WHERE parent_session_id IN (${ph})`).run(...batch);
|
|
1797
|
+
}
|
|
1798
|
+
if (present.has("workflow_run")) {
|
|
1799
|
+
db.prepare(`UPDATE workflow_run SET parent_session_id = NULL WHERE parent_session_id IN (${ph})`).run(...batch);
|
|
1800
|
+
}
|
|
1801
|
+
if (present.has("workflow_activity")) {
|
|
1802
|
+
db.prepare(`UPDATE workflow_activity SET child_session_id = NULL WHERE child_session_id IN (${ph})`).run(...batch);
|
|
1803
|
+
}
|
|
1804
|
+
if (present.has("input_history")) {
|
|
1805
|
+
db.prepare(`DELETE FROM input_history WHERE session_id IN (${ph})`).run(...batch);
|
|
1806
|
+
}
|
|
1807
|
+
const res = db.prepare(`DELETE FROM session WHERE id IN (${ph})`).run(...batch);
|
|
1808
|
+
swept += res.changes ?? batch.length;
|
|
1809
|
+
}
|
|
1810
|
+
db.exec("COMMIT");
|
|
1811
|
+
return swept;
|
|
1812
|
+
} catch (err) {
|
|
1813
|
+
try {
|
|
1814
|
+
db.exec("ROLLBACK");
|
|
1815
|
+
} catch (rollbackErr) {
|
|
1816
|
+
void rollbackErr;
|
|
1817
|
+
}
|
|
1818
|
+
throw err;
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1821
|
+
function sweepExpiredZcodeSessions(dbPath, opts = {}) {
|
|
1822
|
+
const noOp = { swept: 0, keptActive: 0 };
|
|
1823
|
+
if (!fs5.existsSync(dbPath)) return noOp;
|
|
1824
|
+
const Ctor = loadDatabaseSyncCtor();
|
|
1825
|
+
if (Ctor === void 0) {
|
|
1826
|
+
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");
|
|
1827
|
+
return noOp;
|
|
1828
|
+
}
|
|
1829
|
+
const now = opts.nowMs ?? Date.now();
|
|
1830
|
+
const ttl = opts.ttlMs ?? ZCODE_SESSION_TTL_MS;
|
|
1831
|
+
const cutoff = now - ttl;
|
|
1832
|
+
const keep = opts.keepSessionIds ?? /* @__PURE__ */ new Set();
|
|
1833
|
+
let db;
|
|
1834
|
+
try {
|
|
1835
|
+
db = new Ctor(dbPath);
|
|
1836
|
+
db.exec(`PRAGMA busy_timeout = ${SWEEP_BUSY_TIMEOUT_MS}`);
|
|
1837
|
+
const { expired, keptActive } = collectExpiredSessions(db, cutoff, keep);
|
|
1838
|
+
if (expired.length === 0) {
|
|
1839
|
+
db.close();
|
|
1840
|
+
return { swept: 0, keptActive };
|
|
1841
|
+
}
|
|
1842
|
+
ensureForeignKeysOn(db);
|
|
1843
|
+
const present = listPresentTables(db);
|
|
1844
|
+
const swept = deleteExpiredSessionsInTx(db, expired, present);
|
|
1845
|
+
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 });
|
|
1846
|
+
try {
|
|
1847
|
+
db.prepare("PRAGMA wal_checkpoint(PASSIVE)").get();
|
|
1848
|
+
} catch (err) {
|
|
1849
|
+
void err;
|
|
1850
|
+
}
|
|
1851
|
+
return { swept, keptActive };
|
|
1852
|
+
} catch (err) {
|
|
1853
|
+
logger3.warn(
|
|
1854
|
+
`[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)}`,
|
|
1855
|
+
{ dbPath }
|
|
1856
|
+
);
|
|
1857
|
+
return noOp;
|
|
1858
|
+
} finally {
|
|
1859
|
+
try {
|
|
1860
|
+
db?.close();
|
|
1861
|
+
} catch (err) {
|
|
1862
|
+
void err;
|
|
1863
|
+
}
|
|
1864
|
+
}
|
|
1865
|
+
}
|
|
1866
|
+
var sweepThrottle = /* @__PURE__ */ new Map();
|
|
1867
|
+
function maybeSweepExpiredZcodeSessions(dbPath, opts = {}) {
|
|
1868
|
+
const now = Date.now();
|
|
1869
|
+
const last = sweepThrottle.get(dbPath);
|
|
1870
|
+
if (!opts.force && last !== void 0 && now - last < ZCODE_SESSION_SWEEP_INTERVAL_MS) {
|
|
1871
|
+
return { swept: 0, keptActive: 0 };
|
|
1872
|
+
}
|
|
1873
|
+
const result = sweepExpiredZcodeSessions(dbPath, {
|
|
1874
|
+
...opts.keepSessionIds !== void 0 ? { keepSessionIds: opts.keepSessionIds } : {}
|
|
1875
|
+
});
|
|
1876
|
+
sweepThrottle.set(dbPath, now);
|
|
1877
|
+
return result;
|
|
1878
|
+
}
|
|
1879
|
+
|
|
1880
|
+
// src/zcode-engine.ts
|
|
1881
|
+
var logger4 = (0, import_subagent_engine_sdk9.getLogger)("subagents");
|
|
1631
1882
|
var PROBE_VERSION_TIMEOUT_MS = 15e3;
|
|
1632
1883
|
var COMMON_THOUGHT_LEVELS = ["low", "high", "max"];
|
|
1633
1884
|
var ZcodeEngine = class {
|
|
@@ -1654,8 +1905,11 @@ var ZcodeEngine = class {
|
|
|
1654
1905
|
schemaEnforcement: "emulated",
|
|
1655
1906
|
// send-while-running 恒 -32010 硬错误(旧实测)——app-server 常驻化不改变此判据
|
|
1656
1907
|
steer: "unsupported",
|
|
1657
|
-
//
|
|
1658
|
-
|
|
1908
|
+
// [U6 / §3.2.6 要点 4] "cold" = 冷恢复会话:session/resume 读通道取结构化
|
|
1909
|
+
// 历史 + session/create 新会话注入首轮(无热 steering——interrupt 维持
|
|
1910
|
+
// kill-only 如实声明)。P-1 探针:原地 resume 续写被 -32031 卡死,热会话
|
|
1911
|
+
// 通道不可用,声明不越级。
|
|
1912
|
+
conversation: "cold",
|
|
1659
1913
|
// 无 --append-system-prompt flag(实测拒收)——persona 只能拼进 prompt
|
|
1660
1914
|
personaInjection: "prompt",
|
|
1661
1915
|
// app-server 推送流实时流出(session/event payload.delta → text_delta)
|
|
@@ -1699,7 +1953,7 @@ var ZcodeEngine = class {
|
|
|
1699
1953
|
}
|
|
1700
1954
|
/** check 1:二进制存在性(isFile 才算——同名目录不是可执行入口)。 */
|
|
1701
1955
|
probeBinaryCheck(cliPath) {
|
|
1702
|
-
const binaryOk =
|
|
1956
|
+
const binaryOk = fs6.existsSync(cliPath) && fs6.statSync(cliPath).isFile();
|
|
1703
1957
|
return {
|
|
1704
1958
|
name: "binary",
|
|
1705
1959
|
ok: binaryOk,
|
|
@@ -1737,8 +1991,8 @@ var ZcodeEngine = class {
|
|
|
1737
1991
|
/**
|
|
1738
1992
|
* 常驻路径主编排:模型解析(v2 单源校验)→ 惰性连接 + runTurn(事件时序前移:
|
|
1739
1993
|
* text_delta 流式、终态后 message_end/turn_end)→ schema 仿真重试 → outcome/handle。
|
|
1740
|
-
*
|
|
1741
|
-
*
|
|
1994
|
+
* onHandleReady 在 create 应答后(§3.4 不变量 3;原 onPoolResolved prepare 期
|
|
1995
|
+
* 声明已随 [池抽象降级 2026-09-13] poolKey 协议面退役删除)。
|
|
1742
1996
|
*/
|
|
1743
1997
|
async runViaAppServer(task, ctx) {
|
|
1744
1998
|
const startedAt = Date.now();
|
|
@@ -1748,10 +2002,10 @@ var ZcodeEngine = class {
|
|
|
1748
2002
|
const modelRef = resolveZcodeModelRef(task.model, this.deps.sources);
|
|
1749
2003
|
this.warnIgnoredCtxModel(task, ctx, modelRef);
|
|
1750
2004
|
this.warnThoughtLevelUncommon(task, ctx);
|
|
1751
|
-
ctx.onPoolResolved?.(ZCODE_SHARED_POOL_KEY);
|
|
1752
2005
|
const cwd = task.cwd ?? process.cwd();
|
|
1753
2006
|
const schema = isPlainObject(task.schema) ? task.schema : void 0;
|
|
1754
|
-
const
|
|
2007
|
+
const resumePrefix = await this.buildResumeHistoryPrefix(ctx);
|
|
2008
|
+
const basePrompt = resumePrefix === void 0 ? this.buildPrompt(task, schema) : resumePrefix + this.buildPrompt(task, schema);
|
|
1755
2009
|
const usageAcc = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, has: false };
|
|
1756
2010
|
const final = await this.runAppServerAttemptsWithRetry(task, ctx, modelRef, cwd, basePrompt, schema, usageAcc);
|
|
1757
2011
|
const outcome = this.finalizeOutcome(task, ctx, final, usageAcc, startedAt);
|
|
@@ -1759,7 +2013,6 @@ var ZcodeEngine = class {
|
|
|
1759
2013
|
}
|
|
1760
2014
|
/** pre-aborted 短路收口:合成中止 outcome + 'shared' 锚定 handle。 */
|
|
1761
2015
|
abortedAppServerRun(task, ctx, startedAt) {
|
|
1762
|
-
ctx.onPoolResolved?.(ZCODE_SHARED_POOL_KEY);
|
|
1763
2016
|
const outcome = this.finalizeOutcome(
|
|
1764
2017
|
task,
|
|
1765
2018
|
ctx,
|
|
@@ -1793,11 +2046,11 @@ var ZcodeEngine = class {
|
|
|
1793
2046
|
if (final.kind === "run-failed" && final.transient !== void 0 && ctx.signal?.aborted !== true && !this.disposed) {
|
|
1794
2047
|
const budget = resolveTransientRetryBudget(explicitTurnBudgetMs(), Date.now() - attemptStartedAt);
|
|
1795
2048
|
if (budget.state === "depleted") {
|
|
1796
|
-
|
|
2049
|
+
logger4.warn(
|
|
1797
2050
|
`[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`
|
|
1798
2051
|
);
|
|
1799
2052
|
} else {
|
|
1800
|
-
|
|
2053
|
+
logger4.warn(
|
|
1801
2054
|
`[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")
|
|
1802
2055
|
);
|
|
1803
2056
|
const retry = await this.attemptAppServerTurn(task, ctx, modelRef, cwd, basePrompt, {
|
|
@@ -1833,7 +2086,6 @@ var ZcodeEngine = class {
|
|
|
1833
2086
|
dbPath: zcodeSessionDbPath(this.deps.engineDataDir()),
|
|
1834
2087
|
...outcome.sessionId !== void 0 ? { sessionId: outcome.sessionId } : {}
|
|
1835
2088
|
},
|
|
1836
|
-
poolKey: ZCODE_SHARED_POOL_KEY,
|
|
1837
2089
|
...this.probeCache?.engineVersion !== void 0 && this.probeCache.engineVersion !== "" ? { engineVersion: this.probeCache.engineVersion } : {},
|
|
1838
2090
|
adapterVersion: ZCODE_ADAPTER_VERSION
|
|
1839
2091
|
}
|
|
@@ -1853,8 +2105,8 @@ var ZcodeEngine = class {
|
|
|
1853
2105
|
const createParams = buildAppServerCreateParams(task, providerId, modelId, cwd);
|
|
1854
2106
|
let currentSessionId;
|
|
1855
2107
|
let signalSessionCreated;
|
|
1856
|
-
const sessionCreated = new Promise((
|
|
1857
|
-
signalSessionCreated =
|
|
2108
|
+
const sessionCreated = new Promise((resolve2) => {
|
|
2109
|
+
signalSessionCreated = resolve2;
|
|
1858
2110
|
});
|
|
1859
2111
|
const turn = rt.channel.runTurn(createParams, prompt, {
|
|
1860
2112
|
// 事件时序前移:payload.delta → text_delta 实时流出(stream 粒度,D5);
|
|
@@ -1862,13 +2114,17 @@ var ZcodeEngine = class {
|
|
|
1862
2114
|
// 不变量 3a 的拼接比对不含 reasoning)
|
|
1863
2115
|
onTextDelta: (delta) => ctx.onEvent?.({ type: "text_delta", delta }),
|
|
1864
2116
|
onThinkingDelta: (delta) => ctx.onEvent?.({ type: "thinking_delta", delta }),
|
|
2117
|
+
// [PR3] 工具执行期活性:非终态非增量的 session/event 帧(tool.updated progress
|
|
2118
|
+
// 等,真机探针实证每 ~1s 一帧)→ activity 事件(零载荷纯活性信号——宿主无进展
|
|
2119
|
+
// 守护对任何事件类型刷新;reducer no-op、不落 journal)。zcode 引擎
|
|
2120
|
+
// conversation:"unsupported",run 域是唯一发射面(无 chat 域接线)。
|
|
2121
|
+
onActivity: () => ctx.onEvent?.({ type: "activity" }),
|
|
1865
2122
|
onSessionCreated: (sessionId) => {
|
|
1866
2123
|
currentSessionId = sessionId;
|
|
1867
2124
|
rt.activeSessions.add(sessionId);
|
|
1868
2125
|
signalSessionCreated?.();
|
|
1869
2126
|
ctx.onHandleReady?.({
|
|
1870
|
-
sessionRef: { dbPath: zcodeSessionDbPath(this.deps.engineDataDir()), sessionId }
|
|
1871
|
-
poolKey: ZCODE_SHARED_POOL_KEY
|
|
2127
|
+
sessionRef: { dbPath: zcodeSessionDbPath(this.deps.engineDataDir()), sessionId }
|
|
1872
2128
|
});
|
|
1873
2129
|
},
|
|
1874
2130
|
// 显式总上界传参(D2/U4:缺省缺席——channel 侧 resolveTurnTimerMs 走 env→默认)
|
|
@@ -1916,14 +2172,14 @@ var ZcodeEngine = class {
|
|
|
1916
2172
|
*/
|
|
1917
2173
|
async awaitConnFinalized(rt) {
|
|
1918
2174
|
if (!rt.conn.alive) return;
|
|
1919
|
-
await new Promise((
|
|
2175
|
+
await new Promise((resolve2) => {
|
|
1920
2176
|
const timer = setTimeout(() => finish(), ZCODE_APPSERVER_HARVEST_GRACE_MS);
|
|
1921
2177
|
if (typeof timer.unref === "function") timer.unref();
|
|
1922
2178
|
const off = rt.conn.onClose(() => finish());
|
|
1923
2179
|
function finish() {
|
|
1924
2180
|
clearTimeout(timer);
|
|
1925
2181
|
off();
|
|
1926
|
-
|
|
2182
|
+
resolve2();
|
|
1927
2183
|
}
|
|
1928
2184
|
});
|
|
1929
2185
|
}
|
|
@@ -1957,7 +2213,7 @@ var ZcodeEngine = class {
|
|
|
1957
2213
|
delayResolved(ZCODE_APPSERVER_ABORT_GRACE_MS, false)
|
|
1958
2214
|
]);
|
|
1959
2215
|
if (settled) return "settled-in-grace";
|
|
1960
|
-
|
|
2216
|
+
logger4.warn(
|
|
1961
2217
|
`[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`
|
|
1962
2218
|
);
|
|
1963
2219
|
await rt.conn.shutdown({ graceMs: ZCODE_KILL_GRACE_MS });
|
|
@@ -1982,19 +2238,19 @@ var ZcodeEngine = class {
|
|
|
1982
2238
|
} catch (err) {
|
|
1983
2239
|
if (entry.escalateOn === "stop-outcome") {
|
|
1984
2240
|
if (isAppServerRpcError(err)) {
|
|
1985
|
-
|
|
2241
|
+
logger4.debug(
|
|
1986
2242
|
`[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`
|
|
1987
2243
|
);
|
|
1988
2244
|
return "stop-rejected";
|
|
1989
2245
|
}
|
|
1990
|
-
|
|
2246
|
+
logger4.warn(
|
|
1991
2247
|
`[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`
|
|
1992
2248
|
);
|
|
1993
2249
|
await rt.conn.shutdown({ graceMs: ZCODE_KILL_GRACE_MS });
|
|
1994
2250
|
await this.awaitConnFinalized(rt);
|
|
1995
2251
|
return "stop-unreachable-killed";
|
|
1996
2252
|
}
|
|
1997
|
-
|
|
2253
|
+
logger4.debug(
|
|
1998
2254
|
`[zcode-engine] session/stop \u5931\u8D25\uFF08${errMessage3(err)}\uFF09\u2014\u2014grace \u540E\u8D70 killChain \u515C\u5E95`
|
|
1999
2255
|
);
|
|
2000
2256
|
}
|
|
@@ -2023,7 +2279,7 @@ var ZcodeEngine = class {
|
|
|
2023
2279
|
const sessionDbPath = zcodeSessionDbPath(engineDataDir);
|
|
2024
2280
|
env.ZCODE_SESSION_DB_PATH = sessionDbPath;
|
|
2025
2281
|
delete env.ZCODE_SESSION_DB;
|
|
2026
|
-
|
|
2282
|
+
fs6.mkdirSync(path4.dirname(sessionDbPath), { recursive: true });
|
|
2027
2283
|
const conn = new AppServerConnection({
|
|
2028
2284
|
cliPath,
|
|
2029
2285
|
dataDir: engineDataDir,
|
|
@@ -2041,6 +2297,11 @@ var ZcodeEngine = class {
|
|
|
2041
2297
|
activeSessions: /* @__PURE__ */ new Set()
|
|
2042
2298
|
};
|
|
2043
2299
|
this.appserverRuntime = rt;
|
|
2300
|
+
const sweepDbPath = sessionDbPath;
|
|
2301
|
+
const sweepTimer = setTimeout(() => {
|
|
2302
|
+
maybeSweepExpiredZcodeSessions(sweepDbPath, { keepSessionIds: this.appserverRuntime?.activeSessions });
|
|
2303
|
+
}, ZCODE_SESSION_SWEEP_DEFER_MS);
|
|
2304
|
+
if (typeof sweepTimer.unref === "function") sweepTimer.unref();
|
|
2044
2305
|
return rt;
|
|
2045
2306
|
}
|
|
2046
2307
|
/**
|
|
@@ -2058,10 +2319,10 @@ var ZcodeEngine = class {
|
|
|
2058
2319
|
* 先到时 onClose 收割先行,dispose 收割幂等 no-op(零回归)。
|
|
2059
2320
|
*/
|
|
2060
2321
|
async shutdownRuntimeAndDisposeChannel(rt) {
|
|
2061
|
-
const harvested = new Promise((
|
|
2322
|
+
const harvested = new Promise((resolve2) => {
|
|
2062
2323
|
const off = rt.conn.onClose(() => {
|
|
2063
2324
|
off();
|
|
2064
|
-
|
|
2325
|
+
resolve2();
|
|
2065
2326
|
});
|
|
2066
2327
|
});
|
|
2067
2328
|
await rt.conn.shutdown({ graceMs: ZCODE_KILL_GRACE_MS });
|
|
@@ -2088,17 +2349,6 @@ var ZcodeEngine = class {
|
|
|
2088
2349
|
}
|
|
2089
2350
|
await this.shutdownRuntimeAndDisposeChannel(rt);
|
|
2090
2351
|
}
|
|
2091
|
-
/**
|
|
2092
|
-
* [u7a D5] 引擎在途只读快照:activeSessions 非空才算在途——poolKey 'shared' 的
|
|
2093
|
-
* app-server **空闲常驻进程恒活,禁止按进程存在判定**(进程在 ≠ 在途,否则推迟
|
|
2094
|
-
* 判定恒真、30min 上限从兜底变常态路径,设计 §3.3 D5 显式排除)。计数权威 =
|
|
2095
|
-
* activeSessions(attempt 入 create 应答后 add / finally settle 后 delete,与
|
|
2096
|
-
* dispose 的 close 帧目标集同一状态源,无双记账)。运行时未初始化(从未 run /
|
|
2097
|
-
* 已 dispose)→ 恒 0。
|
|
2098
|
-
*/
|
|
2099
|
-
inFlightSnapshot() {
|
|
2100
|
-
return { inFlight: this.appserverRuntime?.activeSessions.size ?? 0 };
|
|
2101
|
-
}
|
|
2102
2352
|
/** 终态合成(extension-conventions 函数 80 行上限,从 run 提取):aborted / run-failed / parsed 三分支。 */
|
|
2103
2353
|
finalizeOutcome(task, ctx, final, usageAcc, startedAt) {
|
|
2104
2354
|
const outcome = {
|
|
@@ -2125,7 +2375,7 @@ var ZcodeEngine = class {
|
|
|
2125
2375
|
/** abort 合成终态:exitCode=null(record 正常收尾,不留僵尸)。 */
|
|
2126
2376
|
applyAbortedOutcome(outcome, task, ctx, final, emit) {
|
|
2127
2377
|
outcome.exitCode = null;
|
|
2128
|
-
outcome.error = isHostTimeoutAbort(ctx) ? (0,
|
|
2378
|
+
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)}`;
|
|
2129
2379
|
emit({ type: "error", message: outcome.error });
|
|
2130
2380
|
}
|
|
2131
2381
|
/**
|
|
@@ -2167,17 +2417,6 @@ var ZcodeEngine = class {
|
|
|
2167
2417
|
}
|
|
2168
2418
|
for (const ev of synthesizeCoarseEvents(payload.response, payload.usage)) emit(ev);
|
|
2169
2419
|
}
|
|
2170
|
-
/**
|
|
2171
|
-
* D1 可选面:zcode 首期不支持 conversation(capabilities 声明)——同步拒绝、
|
|
2172
|
-
* 不创建进程,文案给可操作建议(A11)。
|
|
2173
|
-
*/
|
|
2174
|
-
async interact(_handle, _action) {
|
|
2175
|
-
return {
|
|
2176
|
-
ok: false,
|
|
2177
|
-
code: "engine_capability_unsupported",
|
|
2178
|
-
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"
|
|
2179
|
-
};
|
|
2180
|
-
}
|
|
2181
2420
|
/** [U7] 模型可发现性:v2 桌面登录态聚合(带凭据 provider × models),失败安全返回清单本身可能为空。 */
|
|
2182
2421
|
listModels() {
|
|
2183
2422
|
return listZcodeModels(this.deps.sources);
|
|
@@ -2198,8 +2437,12 @@ var ZcodeEngine = class {
|
|
|
2198
2437
|
* sessionId 缺失(解析失败的 run 无法定位 session)跳过①级;②级依赖
|
|
2199
2438
|
* handle.journalPath(宿主 run 后回填)。dbPath:新 handle 恒为隔离库绝对路径
|
|
2200
2439
|
* (zcodeSessionDbPath(engineDataDir),tier1 白名单集合见方法体——宿主路径仅
|
|
2201
|
-
* 「共享 HOME 时代」存量兼容);旧 records
|
|
2202
|
-
*
|
|
2440
|
+
* 「共享 HOME 时代」存量兼容);旧 records(池时代)的相对路径仍按池目录锚定
|
|
2441
|
+
* 解析(read 兼容旧数据,池目录不存在时自然落②级 journal 降级)。[池抽象降级
|
|
2442
|
+
* 2026-09-13] 锚定 key 用常量 SHARED_POOL_KEY 承载——协议面 poolKey 已删,池
|
|
2443
|
+
* 时代真实池 key 不再随 handle 传输;若旧 record 的池目录恰为 shared 布局则①级
|
|
2444
|
+
* 仍可达,其余池 key 的旧 record 直接走②级 journal 降级(30 天 TTL 同尺度衰减,
|
|
2445
|
+
* 行为安全)。
|
|
2203
2446
|
*/
|
|
2204
2447
|
async read(handle) {
|
|
2205
2448
|
if (handle.data.engineId !== ZCODE_ENGINE_ID) {
|
|
@@ -2213,21 +2456,28 @@ var ZcodeEngine = class {
|
|
|
2213
2456
|
if (zcodeDbPathAllowlist(this.deps.engineDataDir()).includes(dbPathRaw)) {
|
|
2214
2457
|
dbPath = dbPathRaw;
|
|
2215
2458
|
} else {
|
|
2216
|
-
|
|
2459
|
+
logger4.warn("[zcode-engine] record dbPath \u975E\u767D\u540D\u5355 db \u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u62D2\u7EDD \u2460\u7EA7\u8BFB\u53D6\u964D journal", {
|
|
2217
2460
|
dbPath: dbPathRaw
|
|
2218
2461
|
});
|
|
2219
2462
|
}
|
|
2220
2463
|
} else {
|
|
2221
|
-
|
|
2222
|
-
(0,
|
|
2223
|
-
dbPathRaw
|
|
2464
|
+
const poolDir = path4.resolve(
|
|
2465
|
+
(0, import_subagent_engine_sdk10.resolvePoolDir)(this.deps.engineDataDir(), ZCODE_ENGINE_ID, import_subagent_engine_sdk10.SHARED_POOL_KEY)
|
|
2224
2466
|
);
|
|
2467
|
+
const resolved = path4.resolve(poolDir, dbPathRaw);
|
|
2468
|
+
if (resolved.startsWith(poolDir + path4.sep)) {
|
|
2469
|
+
dbPath = resolved;
|
|
2470
|
+
} else {
|
|
2471
|
+
logger4.warn("[zcode-engine] record dbPath \u76F8\u5BF9\u8DEF\u5F84\u9003\u9038\u6C60\u76EE\u5F55\uFF0C\u62D2\u7EDD \u2460\u7EA7\u8BFB\u53D6\u964D journal", {
|
|
2472
|
+
dbPath: dbPathRaw
|
|
2473
|
+
});
|
|
2474
|
+
}
|
|
2225
2475
|
}
|
|
2226
2476
|
if (dbPath !== void 0) {
|
|
2227
2477
|
try {
|
|
2228
2478
|
return await readZcodeSessionView(dbPath, sessionId);
|
|
2229
2479
|
} catch (err) {
|
|
2230
|
-
|
|
2480
|
+
logger4.warn("[zcode-engine] native session read failed, degrade to journal replay", {
|
|
2231
2481
|
dbPath,
|
|
2232
2482
|
sessionId,
|
|
2233
2483
|
reason: (0, import_subagent_engine_sdk3.toErrorMessage)(err)
|
|
@@ -2253,7 +2503,7 @@ var ZcodeEngine = class {
|
|
|
2253
2503
|
const thoughtLevel = task.thinkingLevel?.trim();
|
|
2254
2504
|
if (thoughtLevel === void 0 || thoughtLevel === "") return;
|
|
2255
2505
|
if (COMMON_THOUGHT_LEVELS.includes(thoughtLevel)) return;
|
|
2256
|
-
|
|
2506
|
+
logger4.warn(
|
|
2257
2507
|
`[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`,
|
|
2258
2508
|
{ taskId: ctx.taskId }
|
|
2259
2509
|
);
|
|
@@ -2271,11 +2521,40 @@ var ZcodeEngine = class {
|
|
|
2271
2521
|
if (ctx.ctxModel === void 0) return;
|
|
2272
2522
|
const requested = task.model?.trim();
|
|
2273
2523
|
if (requested !== void 0 && requested !== "") return;
|
|
2274
|
-
|
|
2524
|
+
logger4.warn(
|
|
2275
2525
|
`[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}`,
|
|
2276
2526
|
{ taskId: ctx.taskId }
|
|
2277
2527
|
);
|
|
2278
2528
|
}
|
|
2529
|
+
/**
|
|
2530
|
+
* [U6 / §3.2.6 要点 3] resume 锚 → 历史前缀(interact-resume 的读半段)。
|
|
2531
|
+
*
|
|
2532
|
+
* 无锚 / 非 zcode 锚形态 → undefined(行为不变)。读通道失败(条目被 TTL 清 /
|
|
2533
|
+
* 会话失效 / 控制面错误)= 宿主侧锚判据通过后、引擎派发前的窄竞态窗——降级为
|
|
2534
|
+
* **无历史前缀的新会话**(warn 留痕;宿主 reopen 摘要承担主降级面),不炸轮:
|
|
2535
|
+
* 续聊消息本身仍可送达(模型缺历史上下文,比整轮失败可用性高,与 reopen 降级
|
|
2536
|
+
* 的「带摘要重开」语义同族)。
|
|
2537
|
+
*/
|
|
2538
|
+
async buildResumeHistoryPrefix(ctx) {
|
|
2539
|
+
const anchor = zcodeResumeAnchorOf(ctx, this.deps.engineDataDir());
|
|
2540
|
+
if (anchor === void 0) return void 0;
|
|
2541
|
+
const rt = this.ensureAppServerRuntime();
|
|
2542
|
+
let history;
|
|
2543
|
+
let tokens;
|
|
2544
|
+
try {
|
|
2545
|
+
const result = await rt.channel.resumeSession(anchor.sessionId);
|
|
2546
|
+
history = extractResumeHistory(result);
|
|
2547
|
+
tokens = extractResumeTotalTokens(result);
|
|
2548
|
+
} catch (err) {
|
|
2549
|
+
logger4.warn(
|
|
2550
|
+
`[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)}`,
|
|
2551
|
+
{ taskId: ctx.taskId }
|
|
2552
|
+
);
|
|
2553
|
+
return void 0;
|
|
2554
|
+
}
|
|
2555
|
+
if (history.length === 0) return void 0;
|
|
2556
|
+
return buildResumeInjectionSegment(history, anchor.sessionId, tokens);
|
|
2557
|
+
}
|
|
2279
2558
|
/**
|
|
2280
2559
|
* persona 拼接后的完整 prompt(personaInjection: 'prompt'——zcode 无 flag 通道):
|
|
2281
2560
|
* appendSystemPrompt 段在前(人设/约束语境——D6 合流后 persona≡skillPath+
|
|
@@ -2285,10 +2564,42 @@ var ZcodeEngine = class {
|
|
|
2285
2564
|
buildPrompt(task, schema) {
|
|
2286
2565
|
const segments = [...task.appendSystemPrompt ?? []];
|
|
2287
2566
|
segments.push(task.prompt);
|
|
2288
|
-
if (schema !== void 0) segments.push((0,
|
|
2567
|
+
if (schema !== void 0) segments.push((0, import_subagent_engine_sdk10.buildSchemaEmulationSegment)(schema));
|
|
2289
2568
|
return segments.join("\n\n");
|
|
2290
2569
|
}
|
|
2291
2570
|
};
|
|
2571
|
+
function zcodeResumeAnchorOf(ctx, engineDataDir) {
|
|
2572
|
+
const ref = ctx.resume?.resume?.sessionRef;
|
|
2573
|
+
if (ref === void 0) return void 0;
|
|
2574
|
+
const sessionId = ref["sessionId"];
|
|
2575
|
+
const dbPath = ref["dbPath"];
|
|
2576
|
+
if (typeof sessionId !== "string" || sessionId === "") return void 0;
|
|
2577
|
+
if (typeof dbPath !== "string" || dbPath === "") return void 0;
|
|
2578
|
+
if (!zcodeDbPathAllowlist(engineDataDir).includes(dbPath)) return void 0;
|
|
2579
|
+
return { sessionId, dbPath };
|
|
2580
|
+
}
|
|
2581
|
+
function buildResumeInjectionSegment(history, priorSessionId, totalTokens, tokenBudget = ZCODE_RESUME_HISTORY_TOKEN_BUDGET) {
|
|
2582
|
+
const budgetTokens = tokenBudget;
|
|
2583
|
+
const charBudget = budgetTokens * ZCODE_RESUME_CHARS_PER_TOKEN;
|
|
2584
|
+
const lines = history.map((t) => `${t.role}: ${t.text}`);
|
|
2585
|
+
let kept = lines;
|
|
2586
|
+
let omitted = 0;
|
|
2587
|
+
while (kept.length > 1 && kept.reduce((n, l) => n + l.length + 1, 0) > charBudget) {
|
|
2588
|
+
kept = kept.slice(1);
|
|
2589
|
+
omitted++;
|
|
2590
|
+
}
|
|
2591
|
+
const omissionNote = omitted > 0 ? `[... ${omitted} older turn(s) omitted to fit the ${tokenBudget}-token history budget ...]
|
|
2592
|
+
` : "";
|
|
2593
|
+
const usageNote = totalTokens !== void 0 ? `
|
|
2594
|
+
(prior session retained ~${totalTokens} tokens of history)` : "";
|
|
2595
|
+
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.
|
|
2596
|
+
|
|
2597
|
+
<conversation_history>
|
|
2598
|
+
${omissionNote}${kept.join("\n")}
|
|
2599
|
+
</conversation_history>${usageNote}
|
|
2600
|
+
|
|
2601
|
+
`;
|
|
2602
|
+
}
|
|
2292
2603
|
var ZCODE_TURN_RETRY_MIN_BUDGET_MS = 3e5;
|
|
2293
2604
|
function resolveTransientRetryBudget(totalBudgetMs, consumedMs) {
|
|
2294
2605
|
if (totalBudgetMs === void 0) return { state: "unbounded" };
|
|
@@ -2306,8 +2617,8 @@ function errMessage3(err) {
|
|
|
2306
2617
|
return (0, import_subagent_engine_sdk3.toErrorMessage)(err);
|
|
2307
2618
|
}
|
|
2308
2619
|
function delayResolved(ms, value) {
|
|
2309
|
-
return new Promise((
|
|
2310
|
-
const t = setTimeout(() =>
|
|
2620
|
+
return new Promise((resolve2) => {
|
|
2621
|
+
const t = setTimeout(() => resolve2(value), ms);
|
|
2311
2622
|
if (typeof t.unref === "function") t.unref();
|
|
2312
2623
|
});
|
|
2313
2624
|
}
|
|
@@ -2377,9 +2688,6 @@ function authoritativeTerminalStatus(r) {
|
|
|
2377
2688
|
if (r.lastTerminalStatus !== void 0) return r.lastTerminalStatus;
|
|
2378
2689
|
return r.terminal.source === "turn.terminal" ? r.terminal.status : void 0;
|
|
2379
2690
|
}
|
|
2380
|
-
function isFailedTerminalStatus(status) {
|
|
2381
|
-
return status === "failed" || status === "error";
|
|
2382
|
-
}
|
|
2383
2691
|
function parsedAppServerAttempt(task, r) {
|
|
2384
2692
|
if (isFailedTerminalStatus(authoritativeTerminalStatus(r))) {
|
|
2385
2693
|
return failedTerminalAppServerAttempt(r);
|
|
@@ -2389,7 +2697,7 @@ function parsedAppServerAttempt(task, r) {
|
|
|
2389
2697
|
kind: "parsed",
|
|
2390
2698
|
output: syntheticAppServerOutput(0),
|
|
2391
2699
|
payload: turnResultToPayload(r),
|
|
2392
|
-
...schema !== void 0 ? { schemaResult: (0,
|
|
2700
|
+
...schema !== void 0 ? { schemaResult: (0, import_subagent_engine_sdk10.extractAndValidateStructuredOutput)(r.response, schema) } : {}
|
|
2393
2701
|
};
|
|
2394
2702
|
}
|
|
2395
2703
|
function failedTerminalAppServerAttempt(r) {
|
|
@@ -2460,16 +2768,16 @@ function buildAppServerTimeoutMessage(err, sessionId, stopPath, retried = false)
|
|
|
2460
2768
|
${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`;
|
|
2461
2769
|
}
|
|
2462
2770
|
function isHostTimeoutAbort(ctx) {
|
|
2463
|
-
return ctx.signal?.aborted === true && ctx.signal.reason ===
|
|
2771
|
+
return ctx.signal?.aborted === true && ctx.signal.reason === import_subagent_engine_sdk10.HOST_TIMEOUT_ABORT_REASON;
|
|
2464
2772
|
}
|
|
2465
2773
|
var PROBE_STDOUT_CAP_CHARS = 4096;
|
|
2466
2774
|
async function defaultProbeVersion(cliPath, dataDir) {
|
|
2467
2775
|
try {
|
|
2468
|
-
return await new Promise((
|
|
2469
|
-
const child = (0,
|
|
2776
|
+
return await new Promise((resolve2, reject) => {
|
|
2777
|
+
const child = (0, import_subagent_engine_sdk10.spawnEngineChild)({
|
|
2470
2778
|
command: "node",
|
|
2471
2779
|
args: [cliPath, "--version"],
|
|
2472
|
-
env: (0,
|
|
2780
|
+
env: (0, import_subagent_engine_sdk10.buildEngineChildEnv)(process.env, { dataDir }),
|
|
2473
2781
|
stdout: "pipe",
|
|
2474
2782
|
stderr: "ignore",
|
|
2475
2783
|
signal: AbortSignal.timeout(PROBE_VERSION_TIMEOUT_MS)
|
|
@@ -2482,11 +2790,11 @@ async function defaultProbeVersion(cliPath, dataDir) {
|
|
|
2482
2790
|
child.once("error", reject);
|
|
2483
2791
|
child.once("close", (code) => {
|
|
2484
2792
|
if (code !== 0) reject(new Error(`zcode --version exited with code ${code}`));
|
|
2485
|
-
else
|
|
2793
|
+
else resolve2(out.trim().split("\n")[0]?.trim() || void 0);
|
|
2486
2794
|
});
|
|
2487
2795
|
});
|
|
2488
2796
|
} catch (err) {
|
|
2489
|
-
|
|
2797
|
+
logger4.debug(
|
|
2490
2798
|
`[zcode-engine] probe version check failed (best-effort continue): ${(0, import_subagent_engine_sdk3.toErrorMessage)(err)}`
|
|
2491
2799
|
);
|
|
2492
2800
|
return void 0;
|
|
@@ -2495,7 +2803,7 @@ async function defaultProbeVersion(cliPath, dataDir) {
|
|
|
2495
2803
|
|
|
2496
2804
|
// src/registration.ts
|
|
2497
2805
|
function defaultEngineDataDir() {
|
|
2498
|
-
return (0,
|
|
2806
|
+
return (0, import_subagent_engine_sdk11.resolveEngineDataDir)(process.env);
|
|
2499
2807
|
}
|
|
2500
2808
|
function createZcodeEngine(deps) {
|
|
2501
2809
|
return new ZcodeEngine(deps);
|
|
@@ -2508,7 +2816,7 @@ function createDefaultZcodeEngine() {
|
|
|
2508
2816
|
}
|
|
2509
2817
|
|
|
2510
2818
|
// src/port-types.ts
|
|
2511
|
-
var
|
|
2819
|
+
var import_subagent_engine_sdk12 = require("@zhushanwen/subagent-engine-sdk");
|
|
2512
2820
|
|
|
2513
2821
|
// src/server.ts
|
|
2514
2822
|
var REVERSE_TIMEOUT_DEFAULT_MS = 6e4;
|
|
@@ -2529,11 +2837,11 @@ var EngineProtocolServer = class {
|
|
|
2529
2837
|
}
|
|
2530
2838
|
/** 入站帧消费(请求帧 + 反向请求应答帧;main.ts 的行解析器拆行后喂入)。 */
|
|
2531
2839
|
handleFrame(frame) {
|
|
2532
|
-
if ((0,
|
|
2840
|
+
if ((0, import_subagent_engine_sdk13.isResponseFrame)(frame)) {
|
|
2533
2841
|
this.settleReverse(frame.id, frame);
|
|
2534
2842
|
return;
|
|
2535
2843
|
}
|
|
2536
|
-
if ((0,
|
|
2844
|
+
if ((0, import_subagent_engine_sdk13.isReverseRequestFrame)(frame)) {
|
|
2537
2845
|
this.write({
|
|
2538
2846
|
id: 0,
|
|
2539
2847
|
error: {
|
|
@@ -2555,11 +2863,11 @@ var EngineProtocolServer = class {
|
|
|
2555
2863
|
}
|
|
2556
2864
|
}
|
|
2557
2865
|
}
|
|
2558
|
-
/**
|
|
2866
|
+
/** 9 正向方法分发(表驱动:method → 处理器;未知方法 → engine_protocol_unknown_method)。 */
|
|
2559
2867
|
async dispatch(id, method, params) {
|
|
2560
2868
|
const handler = this.methodHandlers[method];
|
|
2561
2869
|
if (handler === void 0) {
|
|
2562
|
-
throw new
|
|
2870
|
+
throw new import_subagent_engine_sdk13.EngineSdkError(
|
|
2563
2871
|
"engine_protocol_unknown_method",
|
|
2564
2872
|
`unknown protocol method: ${method} (request id ${id})`,
|
|
2565
2873
|
"The engine speaks protocol v1; check the installed engine package version vs the host."
|
|
@@ -2568,7 +2876,7 @@ var EngineProtocolServer = class {
|
|
|
2568
2876
|
return handler(params);
|
|
2569
2877
|
}
|
|
2570
2878
|
/**
|
|
2571
|
-
*
|
|
2879
|
+
* 9 正向方法 → 处理器映射(每个处理器消费原始 params 并自行收敛类型——
|
|
2572
2880
|
* 与原 switch case 表达式一一对应)。
|
|
2573
2881
|
*/
|
|
2574
2882
|
methodHandlers = {
|
|
@@ -2576,7 +2884,6 @@ var EngineProtocolServer = class {
|
|
|
2576
2884
|
probe: (p) => this.engine.probe(probeParamsOf(p)),
|
|
2577
2885
|
run: (p) => this.run(p),
|
|
2578
2886
|
cancel: (p) => this.cancel(p),
|
|
2579
|
-
interact: (p) => this.interact(p),
|
|
2580
2887
|
read: (p) => this.read(p),
|
|
2581
2888
|
listModels: () => ({ models: this.engine.listModels?.() ?? null }),
|
|
2582
2889
|
validateModel: (p) => this.validateModel(p),
|
|
@@ -2588,17 +2895,17 @@ var EngineProtocolServer = class {
|
|
|
2588
2895
|
};
|
|
2589
2896
|
// ── initialize:版本协商(越界 → engine_protocol_mismatch)+ 能力应答 ──
|
|
2590
2897
|
initialize(params) {
|
|
2591
|
-
if (params?.protocolVersion !==
|
|
2592
|
-
throw new
|
|
2898
|
+
if (params?.protocolVersion !== import_subagent_engine_sdk13.ENGINE_PROTOCOL_VERSION) {
|
|
2899
|
+
throw new import_subagent_engine_sdk13.EngineSdkError(
|
|
2593
2900
|
"engine_protocol_mismatch",
|
|
2594
|
-
`host protocol version ${String(params?.protocolVersion)} is not compatible with engine protocol v${
|
|
2595
|
-
`Upgrade the engine package or the host so both speak protocol v${
|
|
2901
|
+
`host protocol version ${String(params?.protocolVersion)} is not compatible with engine protocol v${import_subagent_engine_sdk13.ENGINE_PROTOCOL_VERSION}`,
|
|
2902
|
+
`Upgrade the engine package or the host so both speak protocol v${import_subagent_engine_sdk13.ENGINE_PROTOCOL_VERSION}.`
|
|
2596
2903
|
);
|
|
2597
2904
|
}
|
|
2598
2905
|
this.initialized = true;
|
|
2599
2906
|
const models = this.engine.listModels?.() ?? null;
|
|
2600
2907
|
return {
|
|
2601
|
-
protocolVersion:
|
|
2908
|
+
protocolVersion: import_subagent_engine_sdk13.ENGINE_PROTOCOL_VERSION,
|
|
2602
2909
|
engineId: this.engine.id,
|
|
2603
2910
|
engineVersion: ZCODE_ADAPTER_VERSION,
|
|
2604
2911
|
adapterVersion: ZCODE_ADAPTER_VERSION,
|
|
@@ -2609,7 +2916,7 @@ var EngineProtocolServer = class {
|
|
|
2609
2916
|
// ── run:协议载荷 → 本地 AgentCallOpts/RunContext;事件 → 通知/host 通道 ──
|
|
2610
2917
|
async run(params) {
|
|
2611
2918
|
if (!this.initialized) {
|
|
2612
|
-
throw new
|
|
2919
|
+
throw new import_subagent_engine_sdk13.EngineSdkError(
|
|
2613
2920
|
"engine_protocol_not_initialized",
|
|
2614
2921
|
"run before initialize is a protocol violation",
|
|
2615
2922
|
"The host must complete the initialize handshake before dispatching runs."
|
|
@@ -2620,24 +2927,23 @@ var EngineProtocolServer = class {
|
|
|
2620
2927
|
const active = { controller, seq: 0 };
|
|
2621
2928
|
this.activeRuns.set(runId, active);
|
|
2622
2929
|
const fullTask = { ...task, ...ctx.model !== void 0 ? { model: ctx.model } : {} };
|
|
2623
|
-
const ctxModel = (0,
|
|
2930
|
+
const ctxModel = (0, import_subagent_engine_sdk12.parseCtxModel)(ctx.ctxModel);
|
|
2624
2931
|
const stream = ctx.streamMode === "stream" ? { onDelta: (delta) => {
|
|
2625
2932
|
void this.reverseRequestInternal("host/streamDelta", { runId, delta });
|
|
2626
2933
|
} } : void 0;
|
|
2627
2934
|
const runCtx = {
|
|
2628
2935
|
taskId: runId,
|
|
2629
|
-
poolKey: ctx.poolKey,
|
|
2630
2936
|
signal: controller.signal,
|
|
2631
2937
|
onEvent: (event) => this.emitEvent(runId, event),
|
|
2632
2938
|
...ctxModel !== void 0 ? { ctxModel } : {},
|
|
2633
2939
|
...stream !== void 0 ? { stream } : {},
|
|
2634
2940
|
...ctx.schemaEnv !== void 0 ? { schemaEnv: ctx.schemaEnv } : {},
|
|
2635
2941
|
...ctx.engineFallback !== void 0 ? { engineFallback: ctx.engineFallback } : {},
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
},
|
|
2942
|
+
// [U6 / §3.2.6 要点 3] resume 锚点透传(宿主 → 引擎的续聊通道:zcode 锚
|
|
2943
|
+
// sessionRef {sessionId, dbPath},引擎侧 resume 读 + 新 session 注入消费)。
|
|
2944
|
+
...params.resume !== void 0 ? { resume: params.resume } : {},
|
|
2639
2945
|
onHandleReady: (partial) => {
|
|
2640
|
-
void this.reverseRequestInternal("host/handleReady", { runId, sessionRef: partial.sessionRef
|
|
2946
|
+
void this.reverseRequestInternal("host/handleReady", { runId, sessionRef: partial.sessionRef });
|
|
2641
2947
|
}
|
|
2642
2948
|
};
|
|
2643
2949
|
try {
|
|
@@ -2652,15 +2958,12 @@ var EngineProtocolServer = class {
|
|
|
2652
2958
|
if (active !== void 0) active.controller.abort(new Error(`cancelled by host: ${params.reason}`));
|
|
2653
2959
|
return { ok: true };
|
|
2654
2960
|
}
|
|
2655
|
-
async interact(params) {
|
|
2656
|
-
return this.engine.interact({ data: params.handle }, params.action);
|
|
2657
|
-
}
|
|
2658
2961
|
read(params) {
|
|
2659
2962
|
return this.engine.read({ data: params.handle });
|
|
2660
2963
|
}
|
|
2661
2964
|
validateModel(params) {
|
|
2662
2965
|
if (this.engine.validateModel === void 0) {
|
|
2663
|
-
throw new
|
|
2966
|
+
throw new import_subagent_engine_sdk13.EngineSdkError(
|
|
2664
2967
|
"engine_capability_unsupported",
|
|
2665
2968
|
"engine does not implement validateModel",
|
|
2666
2969
|
"Manifest omits modelCatalog; model validation falls back to run-time engine checks."
|
|
@@ -2686,14 +2989,14 @@ var EngineProtocolServer = class {
|
|
|
2686
2989
|
}
|
|
2687
2990
|
reverseRequestInternal(method, params) {
|
|
2688
2991
|
const id = `rev-${++this.revSeq}`;
|
|
2689
|
-
return new Promise((
|
|
2992
|
+
return new Promise((resolve2, reject) => {
|
|
2690
2993
|
const timer = setTimeout(() => {
|
|
2691
2994
|
this.reversePending.delete(id);
|
|
2692
2995
|
this.reverseClock?.settled(id);
|
|
2693
2996
|
reject(new Error(`reverse request ${method} (${id}) timed out after ${this.reverseTimeoutMs}ms`));
|
|
2694
2997
|
}, this.reverseTimeoutMs);
|
|
2695
2998
|
if (typeof timer.unref === "function") timer.unref();
|
|
2696
|
-
this.reversePending.set(id, { resolve, reject, timer });
|
|
2999
|
+
this.reversePending.set(id, { resolve: resolve2, reject, timer });
|
|
2697
3000
|
this.reverseClock?.started(id);
|
|
2698
3001
|
this.write({ id, method, params });
|
|
2699
3002
|
});
|
|
@@ -2714,7 +3017,7 @@ function probeParamsOf(params) {
|
|
|
2714
3017
|
return typeof params === "object" && params !== null ? params : void 0;
|
|
2715
3018
|
}
|
|
2716
3019
|
function toProtocolError(err) {
|
|
2717
|
-
if (err instanceof
|
|
3020
|
+
if (err instanceof import_subagent_engine_sdk13.EngineSdkError) return err.toStructured();
|
|
2718
3021
|
return {
|
|
2719
3022
|
code: "engine_run_failed",
|
|
2720
3023
|
message: (0, import_subagent_engine_sdk3.toErrorMessage)(err),
|