@sema-agent/client-core 0.12.2 → 0.13.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/README.md +14 -2
- package/dist/abortableSleep.d.ts +29 -0
- package/dist/abortableSleep.js +43 -0
- package/dist/adapt/arms.d.ts +58 -0
- package/dist/adapt/arms.js +613 -0
- package/dist/adapt/ids.d.ts +22 -0
- package/dist/adapt/ids.js +34 -0
- package/dist/adapt/instanceLedger.d.ts +36 -0
- package/dist/adapt/instanceLedger.js +50 -0
- package/dist/adapt/panelTasks.d.ts +54 -0
- package/dist/adapt/panelTasks.js +193 -0
- package/dist/adapt/textStream.d.ts +49 -0
- package/dist/adapt/textStream.js +141 -0
- package/dist/adapt/toolCards.d.ts +65 -0
- package/dist/adapt/toolCards.js +100 -0
- package/dist/adapt/turnFlags.d.ts +33 -0
- package/dist/adapt/turnFlags.js +55 -0
- package/dist/adapt/wireShapes.d.ts +93 -0
- package/dist/adapt/wireShapes.js +167 -0
- package/dist/adapt.d.ts +32 -59
- package/dist/adapt.js +78 -1206
- package/dist/adapter/downstream/eventToSdkMessage.d.ts +55 -13
- package/dist/adapter/downstream/eventToSdkMessage.js +166 -106
- package/dist/adapter/downstream/terminalToSdkResult.js +149 -160
- package/dist/adapter/downstream/turnUsageToModelUsage.d.ts +36 -0
- package/dist/adapter/downstream/turnUsageToModelUsage.js +34 -6
- package/dist/adapter/runStream.d.ts +29 -4
- package/dist/adapter/runStream.js +129 -13
- package/dist/adapter/types.d.ts +2 -2
- package/dist/agentSession/backgroundView.js +4 -15
- package/dist/agentsWireCaps.d.ts +10 -6
- package/dist/agentsWireCaps.js +21 -7
- package/dist/argvFlagValue.d.ts +41 -0
- package/dist/argvFlagValue.js +69 -0
- package/dist/attachmentsWireCaps.d.ts +3 -2
- package/dist/attachmentsWireCaps.js +5 -3
- package/dist/classifierVerdictWire.d.ts +8 -0
- package/dist/classifierVerdictWire.js +8 -0
- package/dist/cloudConfigWireCaps.d.ts +28 -1
- package/dist/cloudConfigWireCaps.js +51 -11
- package/dist/controlRouter.d.ts +14 -8
- package/dist/controlRouter.js +15 -21
- package/dist/detachWire.d.ts +15 -5
- package/dist/detachWire.js +17 -7
- package/dist/effortWire.d.ts +0 -21
- package/dist/effortWire.js +6 -20
- package/dist/engineInlineTaskStats.d.ts +12 -6
- package/dist/engineWireSdk.d.ts +12 -0
- package/dist/env/localeGeo.js +2 -1
- package/dist/envFlag.d.ts +39 -0
- package/dist/envFlag.js +51 -0
- package/dist/finalVerifyWire.d.ts +7 -5
- package/dist/finalVerifyWire.js +6 -5
- package/dist/fleet/fleetLedger.d.ts +32 -9
- package/dist/fleet/fleetLedger.js +119 -34
- package/dist/fleet/fleetProjection.d.ts +44 -6
- package/dist/fleet/fleetProjection.js +52 -10
- package/dist/fleetAgentPanelProjection.d.ts +18 -1
- package/dist/fleetAgentPanelProjection.js +61 -14
- package/dist/forkWireCaps.d.ts +2 -1
- package/dist/forkWireCaps.js +5 -11
- package/dist/goalStopHook.d.ts +142 -0
- package/dist/goalStopHook.js +258 -0
- package/dist/headlessPermissionModeWire.d.ts +10 -0
- package/dist/headlessPermissionModeWire.js +24 -21
- package/dist/headlessReconnectWire.d.ts +7 -1
- package/dist/headlessReconnectWire.js +20 -2
- package/dist/hitl/approvalsFeed.js +31 -8
- package/dist/hitl/askGateWire.d.ts +27 -96
- package/dist/hitl/askGateWire.js +69 -618
- package/dist/hitl/frameRouter.d.ts +86 -0
- package/dist/hitl/frameRouter.js +342 -0
- package/dist/hitl/gateLedger.d.ts +107 -0
- package/dist/hitl/gateLedger.js +113 -0
- package/dist/hitl/hitlBridge.d.ts +75 -15
- package/dist/hitl/hitlBridge.js +94 -22
- package/dist/hitl/hitlHostSurface.d.ts +49 -0
- package/dist/hitl/hitlHostSurface.js +155 -0
- package/dist/hitl/parkResolver.d.ts +74 -0
- package/dist/hitl/parkResolver.js +241 -0
- package/dist/hitl/planReviewWire.d.ts +60 -2
- package/dist/hitl/planReviewWire.js +152 -74
- package/dist/hitl/toolApprovalWire.d.ts +67 -4
- package/dist/hitl/toolApprovalWire.js +119 -31
- package/dist/hooksWireCaps.d.ts +1 -82
- package/dist/hooksWireCaps.js +34 -235
- package/dist/host.d.ts +16 -5
- package/dist/index.d.ts +2 -0
- package/dist/index.js +15 -1
- package/dist/interactiveToolsWire.d.ts +15 -4
- package/dist/interactiveToolsWire.js +24 -26
- package/dist/limitsWire.js +7 -40
- package/dist/liveInitToolFace.d.ts +51 -6
- package/dist/liveQuestionStore.d.ts +5 -6
- package/dist/model/providerPresets.js +11 -1
- package/dist/notifications.d.ts +48 -2
- package/dist/notifications.js +223 -46
- package/dist/retainBackgroundWireCaps.d.ts +3 -2
- package/dist/retainBackgroundWireCaps.js +5 -9
- package/dist/sandboxWire.d.ts +9 -31
- package/dist/sandboxWire.js +51 -50
- package/dist/scenarioWire.d.ts +1 -1
- package/dist/scenarioWire.js +25 -36
- package/dist/seam.d.ts +23 -6
- package/dist/seam.js +40 -30
- package/dist/seatContract.d.ts +369 -83
- package/dist/seatContract.js +585 -198
- package/dist/selfOrchestrationWireCaps.d.ts +6 -5
- package/dist/selfOrchestrationWireCaps.js +8 -12
- package/dist/sessionSlot.d.ts +8 -0
- package/dist/sessionSlot.js +1 -0
- package/dist/steering.js +2 -2
- package/dist/subagent/engineTaskHandleWire.d.ts +3 -0
- package/dist/subagent/engineTaskHandleWire.js +17 -2
- package/dist/subagentContentStore.d.ts +5 -5
- package/dist/toolResult.d.ts +89 -8
- package/dist/toolResult.js +99 -30
- package/dist/typePins.d.ts +17 -0
- package/dist/typePins.js +1 -0
- package/dist/ultracodeWireCaps.js +5 -6
- package/dist/unrefTimer.d.ts +19 -0
- package/dist/unrefTimer.js +5 -0
- package/dist/workflow.d.ts +3 -2
- package/dist/workflow.js +3 -2
- package/dist/workflowClient.d.ts +7 -0
- package/dist/workflowClient.js +47 -12
- package/package.json +3 -3
|
@@ -4,6 +4,105 @@ import { terminalToSdkResult } from './downstream/terminalToSdkResult.js';
|
|
|
4
4
|
import { publishSubagentContentEvent } from '../subagentContentStore.js';
|
|
5
5
|
/** 本文件发的 chrome 事件全在 leader lane(子代内容在上面就被 divert 走了)。 */
|
|
6
6
|
const MAIN = { lane: 'main' };
|
|
7
|
+
/**
|
|
8
|
+
* 409 session-busy 拒绝的 **canonical errorCode**([2377]C-1,server main `049ff2c`,随 5.0.0 发)。
|
|
9
|
+
* 引擎把它 stamp 在 `done{status:'failed'}` / `failed` 终帧上,壳据此**结构判读**,不再读人话。
|
|
10
|
+
*/
|
|
11
|
+
const ACTIVE_RUN_BUSY_ERROR_CODE = 'conflict.session_active_run';
|
|
12
|
+
/**
|
|
13
|
+
* 判别一个**原始 AgentEvent** 是不是 409 active-run 拒收终帧;非 busy ⇒ null。
|
|
14
|
+
* 判据=结构两腿(canonical `errorCode` 优先 → `activeTaskId` 在场);人话文案腿已随 #117 提货
|
|
15
|
+
* 退役(§B8 禁按错误文案判别)。两种 wire 真形:
|
|
16
|
+
* ① `done{result:{status:'failed', errorCode|activeTaskId,…}}`(交互 tasks/stream 腿,409 骑终帧);
|
|
17
|
+
* ② `failed{errorCode|activeTaskId,…}`(任何把它投影成 failed 臂的上游形)。
|
|
18
|
+
*/
|
|
19
|
+
export function activeRunBusySignal(ev) {
|
|
20
|
+
if (typeof ev !== 'object' || ev === null || !('type' in ev))
|
|
21
|
+
return null;
|
|
22
|
+
const type = ev.type;
|
|
23
|
+
let carrier;
|
|
24
|
+
if (type === 'done') {
|
|
25
|
+
const result = ev.result;
|
|
26
|
+
if (typeof result !== 'object' || result === null)
|
|
27
|
+
return null;
|
|
28
|
+
if (result.status !== 'failed')
|
|
29
|
+
return null;
|
|
30
|
+
carrier = result;
|
|
31
|
+
}
|
|
32
|
+
else if (type === 'failed') {
|
|
33
|
+
carrier = ev;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
const cls = classifyActiveRunBusy({
|
|
39
|
+
errorCode: typeof carrier.errorCode === 'string' ? carrier.errorCode : undefined,
|
|
40
|
+
activeTaskId: carrier.activeTaskId,
|
|
41
|
+
});
|
|
42
|
+
if (!cls.busy)
|
|
43
|
+
return null;
|
|
44
|
+
const status = carrier.activeTaskStatus;
|
|
45
|
+
const rawGate = carrier.pendingGate;
|
|
46
|
+
let pendingGate = null;
|
|
47
|
+
if (typeof rawGate === 'object' && rawGate !== null) {
|
|
48
|
+
const k = rawGate.kind;
|
|
49
|
+
const d = rawGate.decidePath;
|
|
50
|
+
pendingGate = {
|
|
51
|
+
kind: typeof k === 'string' && k.length > 0 ? k : null,
|
|
52
|
+
decidePath: typeof d === 'string' && d.length > 0 ? d : null,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
activeTaskId: cls.handle,
|
|
57
|
+
activeTaskStatus: typeof status === 'string' && status.length > 0 ? status : null,
|
|
58
|
+
pendingGate,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* 结构位优先的 409 判别(REF-CC-054 / dup-03 + 域词表-02,§B8 禁按错误文案判别)。
|
|
63
|
+
*
|
|
64
|
+
* 顺序即优先级:①引擎 canonical `errorCode`(结构位,机器码);②`activeTaskId` 在场(同样是
|
|
65
|
+
* 结构性判据,[1833] G10 起就在 wire 上)。③人话子串锚已于 2026-08-03 随 #117 提货退役(见上)。
|
|
66
|
+
*
|
|
67
|
+
* 事故出处:此前整条判别是 `errText.includes(锚) || typeof activeTaskId === 'string'`,而 2026-07-31
|
|
68
|
+
* 才发现锚曾是**全等**式、在今天的任何引擎上一次都命中不了 —— 判别一直只靠 activeTaskId 那一半在兜。
|
|
69
|
+
* 上游把人话加长一句判别就死一半,这正是 B8 要禁的那类定时炸弹。
|
|
70
|
+
*/
|
|
71
|
+
function classifyActiveRunBusy(input) {
|
|
72
|
+
const handle = typeof input.activeTaskId === 'string' && input.activeTaskId.length > 0 ? input.activeTaskId : null;
|
|
73
|
+
if (input.errorCode === ACTIVE_RUN_BUSY_ERROR_CODE)
|
|
74
|
+
return { busy: true, handle };
|
|
75
|
+
if (typeof input.activeTaskId === 'string')
|
|
76
|
+
return { busy: true, handle };
|
|
77
|
+
return { busy: false, handle };
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* 已上报过的未知帧类型(REF-CC-057:每种臂只吼一次,免得一条流刷屏)。
|
|
81
|
+
* 🔴 单例登记见 `docs/refactor/p1-scan/singleton-manifest.json`:复制两份的后果 = 同一种臂多打
|
|
82
|
+
* 几行 stderr,不影响正确性(dupRisk=low)。
|
|
83
|
+
*/
|
|
84
|
+
const reportedDroppedTypes = new Set();
|
|
85
|
+
/**
|
|
86
|
+
* 未知/畸形帧的**留痕**(§C5 丢弃必须留痕,且痕迹要到得了能处置它的人)。
|
|
87
|
+
*
|
|
88
|
+
* 为什么是 `console.error` 而不是 `hostLog`:runStream 是**可移植内核**,portability 门对它的
|
|
89
|
+
* 传递闭包断言「零 Node 内建 + 文件数上限 6」,值级 import `host.ts` 会当场把闭包撑破。
|
|
90
|
+
* console 在 Node 与浏览器都在,与 `host.ts` 自己那条「口没装就吼一声」的 miss 提示同款姿势。
|
|
91
|
+
* 🔴 已知限制(诚实披露):Ink 挂载后宿主会吞 console,所以 TUI 里这行未必上屏 —— 那正是
|
|
92
|
+
* `EventProjection.dropped` 存在的意义:想在自己那一端把它渲出来的宿主,读返回值即可。
|
|
93
|
+
*/
|
|
94
|
+
function reportDroppedFrame(why, type) {
|
|
95
|
+
if (reportedDroppedTypes.has(type))
|
|
96
|
+
return;
|
|
97
|
+
reportedDroppedTypes.add(type);
|
|
98
|
+
// eslint-disable-next-line no-console
|
|
99
|
+
console.error(`[client-core] dropped an engine frame (${why}): type="${type}" — this build's projector has no arm ` +
|
|
100
|
+
'for it (engine newer than the client, or a malformed frame). It renders NOWHERE.');
|
|
101
|
+
}
|
|
102
|
+
/** 测试钩:清空「已上报过的臂」去重表(去重是**跨调用**状态,不清就只有第一条用例看得见)。 */
|
|
103
|
+
export function _resetDroppedFrameReportForTest() {
|
|
104
|
+
reportedDroppedTypes.clear();
|
|
105
|
+
}
|
|
7
106
|
/**
|
|
8
107
|
* Drive one AgentEvent source into a CC SDKMessage stream.
|
|
9
108
|
*
|
|
@@ -94,8 +193,14 @@ async function* runStreamInner(events, ctx, handle = {}) {
|
|
|
94
193
|
if (!isSubFlow && ctx.emitChrome) {
|
|
95
194
|
try {
|
|
96
195
|
// engineUsage = [2295] 裁 ② 逐字原形(additive 键,契约见 seam.ts 本臂 doc):
|
|
97
|
-
// 总量/命中率消费面吃它,镜像 usage 保纯。
|
|
98
|
-
|
|
196
|
+
// 总量/命中率消费面吃它,镜像 usage 保纯。eopt:additive 键按「诚实缺席」= 键不在
|
|
197
|
+
// (与 turn_end.usage 本身「整体 optional,缺席≠空对象」同一语义,不是「键在值 undefined」)。
|
|
198
|
+
void ctx.emitChrome({
|
|
199
|
+
kind: 'last_turn_usage',
|
|
200
|
+
laneProof: MAIN,
|
|
201
|
+
usage,
|
|
202
|
+
...(ev.usage !== undefined ? { engineUsage: ev.usage } : {}),
|
|
203
|
+
});
|
|
99
204
|
}
|
|
100
205
|
catch { /* fail-soft — statusline 退回 null,原语义 */ }
|
|
101
206
|
}
|
|
@@ -139,14 +244,19 @@ async function* runStreamInner(events, ctx, handle = {}) {
|
|
|
139
244
|
// 本层只负责:识别 + 说真话。
|
|
140
245
|
const activeTaskId = failedResult?.activeTaskId ??
|
|
141
246
|
(ev.type === 'failed' ? ev.activeTaskId : undefined);
|
|
142
|
-
//
|
|
143
|
-
//
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
247
|
+
// REF-CC-054:判别**结构位两腿**(errorCode → activeTaskId;文案兜底腿 2026-08-03 已退役),
|
|
248
|
+
// 判别体见文件上方 `classifyActiveRunBusy`。
|
|
249
|
+
const busy = classifyActiveRunBusy({
|
|
250
|
+
errorCode: ev.type === 'failed' ? ev.errorCode : failedResult?.errorCode,
|
|
251
|
+
activeTaskId,
|
|
252
|
+
});
|
|
147
253
|
// 件14 rev2 (2026-07-14): provider max_tokens cap rejection (e.g. glm-5.2 preset 131072 >
|
|
148
254
|
// a third-party gateway's 128000) → append the way out. Keyword match on the upstream text,
|
|
149
255
|
// supplement never mask (raw provider words stay on the row).
|
|
256
|
+
// 🟢 B8 ALLOW 清单登记(REF-CC-域词表-08,属主=client-core 规范重构轮,单列一类:命中只
|
|
257
|
+
// 流向字符串拼接、不流向 if/return——supplement-only,零控制流。误判方向单侧:误命中只多
|
|
258
|
+
// 一行提示,误失效只少一行提示,行为面(哪一行 API Error / isError)不受影响。别把它跟
|
|
259
|
+
// 会改判别方向的判据(域词表-01/02 那种)混进同一张门里整体豁免)。
|
|
150
260
|
const maxTokHint = /max_tokens/i.test(errText)
|
|
151
261
|
? '\nyour provider caps max_tokens lower — lower it in /model (press m, or M to type a value)'
|
|
152
262
|
: '';
|
|
@@ -158,8 +268,8 @@ async function* runStreamInner(events, ctx, handle = {}) {
|
|
|
158
268
|
// 重启引擎捞不回来(boot 期孤儿回收只捞 running)、时间型 reap 挂在
|
|
159
269
|
// APPROVAL_TIMEOUT_SEC(默认 0 ⇒ 整条腿不跑),唯一兜底窗是 30 天。
|
|
160
270
|
// 换成真话 + 真的存在的两条动作(引擎的 cancel 端点 / 换一个会话)。
|
|
161
|
-
const busyHandle =
|
|
162
|
-
const rowText =
|
|
271
|
+
const busyHandle = busy.handle;
|
|
272
|
+
const rowText = busy.busy
|
|
163
273
|
? `This session is locked by an earlier run${busyHandle ? ` (run ${busyHandle})` : ''} that ` +
|
|
164
274
|
`has not been released, so this message was NOT sent. Nothing releases it on its own — ` +
|
|
165
275
|
`cancel that run (POST /v1/runs/${busyHandle ?? '<id>'}/cancel), or start a new session.`
|
|
@@ -192,9 +302,15 @@ async function* runStreamInner(events, ctx, handle = {}) {
|
|
|
192
302
|
yield terminalToSdkResult(ev, ctx);
|
|
193
303
|
return;
|
|
194
304
|
}
|
|
195
|
-
// Every other arm →
|
|
196
|
-
const
|
|
197
|
-
if (
|
|
198
|
-
yield
|
|
305
|
+
// Every other arm → typed three-state projection(REF-CC-058)。
|
|
306
|
+
const projection = eventToSdkMessage(ev, ctx);
|
|
307
|
+
if (projection.kind === 'message') {
|
|
308
|
+
yield projection.message;
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
// REF-CC-057:`dropped` 是「引擎发了一帧、这个 build 渲不出来」——**必须留痕**;
|
|
312
|
+
// `none` 是设计内无可渲染臂(usage 折叠/终帧代理/HITL 登记),不留痕才是对的。
|
|
313
|
+
if (projection.kind === 'dropped')
|
|
314
|
+
reportDroppedFrame(projection.why, projection.type);
|
|
199
315
|
}
|
|
200
316
|
}
|
package/dist/adapter/types.d.ts
CHANGED
|
@@ -65,8 +65,8 @@ export interface EmitContext {
|
|
|
65
65
|
}
|
|
66
66
|
/** Stamp `uuid` + `session_id` onto a freshly-built arm body. */
|
|
67
67
|
export declare function stamp<T extends {
|
|
68
|
-
uuid?: string;
|
|
69
|
-
session_id?: string;
|
|
68
|
+
uuid?: string | undefined;
|
|
69
|
+
session_id?: string | undefined;
|
|
70
70
|
}>(ctx: EmitContext, body: T): T & {
|
|
71
71
|
uuid: string;
|
|
72
72
|
session_id: string;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { abortableSleep } from '../abortableSleep.js';
|
|
1
2
|
import { errCodes } from '../controlRouter.js';
|
|
2
3
|
import { engineWireDebugEnabled } from '../engineWireTarget.js';
|
|
3
4
|
import { hostLog } from '../host.js';
|
|
@@ -217,20 +218,6 @@ export function createBackgroundView(client, opts) {
|
|
|
217
218
|
notify();
|
|
218
219
|
}
|
|
219
220
|
}
|
|
220
|
-
/** abort 感知的 sleep:dispose 立即唤醒并清定时器(不留悬挂 timer 拖住宿主进程)。 */
|
|
221
|
-
function sleep(ms) {
|
|
222
|
-
return new Promise((resolve) => {
|
|
223
|
-
const timer = setTimeout(() => {
|
|
224
|
-
abort.signal.removeEventListener('abort', onAbort);
|
|
225
|
-
resolve();
|
|
226
|
-
}, ms);
|
|
227
|
-
const onAbort = () => {
|
|
228
|
-
clearTimeout(timer);
|
|
229
|
-
resolve();
|
|
230
|
-
};
|
|
231
|
-
abort.signal.addEventListener('abort', onAbort, { once: true });
|
|
232
|
-
});
|
|
233
|
-
}
|
|
234
221
|
async function loop() {
|
|
235
222
|
while (!disposed && !abort.signal.aborted) {
|
|
236
223
|
try {
|
|
@@ -242,7 +229,9 @@ export function createBackgroundView(client, opts) {
|
|
|
242
229
|
}
|
|
243
230
|
if (disposed || abort.signal.aborted)
|
|
244
231
|
return;
|
|
245
|
-
|
|
232
|
+
// REF-CC-147:abort 感知的 sleep(dispose 立即唤醒并清定时器,不留悬挂 timer 拖住宿主
|
|
233
|
+
// 进程)——本函数原实现已抽成共享叶 ../abortableSleep.js,workflowClient.ts 同款消费。
|
|
234
|
+
await abortableSleep(intervalMs, abort.signal);
|
|
246
235
|
}
|
|
247
236
|
}
|
|
248
237
|
void loop();
|
package/dist/agentsWireCaps.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type EngineProbeOpts } from './engineWireSdk.js';
|
|
1
2
|
export declare const MAX_TASK_AGENTS = 32;
|
|
2
3
|
export declare const MAX_AGENT_NAME_CHARS = 64;
|
|
3
4
|
export declare const MAX_AGENT_TEXT_CHARS = 4096;
|
|
@@ -78,12 +79,7 @@ export declare function projectAgentsForWire(defs: readonly AgentDefLike[], deps
|
|
|
78
79
|
* 语义变形)。差分:SDK 恒 stamp x-agent-principal(缺省 'anon:shell-live'),原手抄缺 principal
|
|
79
80
|
* 时省略该头——principal-first 宪法姿势,fail-open 改善(engineWireSdk 头注记账)。
|
|
80
81
|
*/
|
|
81
|
-
export declare function engineSupportsTaskAgents(baseUrl: string, opts?:
|
|
82
|
-
fetchImpl?: typeof fetch;
|
|
83
|
-
timeoutMs?: number;
|
|
84
|
-
authToken?: string;
|
|
85
|
-
principal?: string;
|
|
86
|
-
}): Promise<boolean | undefined>;
|
|
82
|
+
export declare function engineSupportsTaskAgents(baseUrl: string, opts?: EngineProbeOpts): Promise<boolean | undefined>;
|
|
87
83
|
export type WireConfig = {
|
|
88
84
|
baseUrl: string;
|
|
89
85
|
authToken?: string;
|
|
@@ -98,6 +94,14 @@ export declare function prepareTaskAgentsWireWith(cfg: WireConfig, projector: Pr
|
|
|
98
94
|
/**
|
|
99
95
|
* 有界就绪门(liveClient.stream 首帧前 await;缺省 4s 上限)。prepare 未 kick(mock 车道/测试)或
|
|
100
96
|
* 超时 ⇒ 立即放行(本 turn 不带 agents,fail-soft)。永不抛。
|
|
97
|
+
*
|
|
98
|
+
* 🔴 域词表-13(RB-447 同形):这个 race 的唯一有界退出臂**绝不 unref**——它是被调用方真
|
|
99
|
+
* await 的控制流(liveClient.ts `await awaitTaskAgentsWire()`),不是后台保活豁免;unref 会让
|
|
100
|
+
* 宿主进程能在它 settle 前提前退出,届时这个 await 永远等不到结果。对照组:
|
|
101
|
+
* askGateWire.ts 的 budget 定时器同样 unref,但它挂在无人 await 的 `void Promise.race(...)` 上,
|
|
102
|
+
* 后果只是丢一行 warn——两处形状相同后果不同,分野在于「这个 promise 有没有被 await」,不能
|
|
103
|
+
* 套用同一个 unref 兼容套(见 unrefTimer.ts 头注)。race settle 后 clearTimeout 掉该句柄
|
|
104
|
+
* (此前完全没有 clear,超时臂即使先输也留着一个已到期的句柄)。
|
|
101
105
|
*/
|
|
102
106
|
export declare function awaitTaskAgentsWire(timeoutMs?: number): Promise<void>;
|
|
103
107
|
/**
|
package/dist/agentsWireCaps.js
CHANGED
|
@@ -277,17 +277,31 @@ export function prepareTaskAgentsWireWith(cfg, projector) {
|
|
|
277
277
|
/**
|
|
278
278
|
* 有界就绪门(liveClient.stream 首帧前 await;缺省 4s 上限)。prepare 未 kick(mock 车道/测试)或
|
|
279
279
|
* 超时 ⇒ 立即放行(本 turn 不带 agents,fail-soft)。永不抛。
|
|
280
|
+
*
|
|
281
|
+
* 🔴 域词表-13(RB-447 同形):这个 race 的唯一有界退出臂**绝不 unref**——它是被调用方真
|
|
282
|
+
* await 的控制流(liveClient.ts `await awaitTaskAgentsWire()`),不是后台保活豁免;unref 会让
|
|
283
|
+
* 宿主进程能在它 settle 前提前退出,届时这个 await 永远等不到结果。对照组:
|
|
284
|
+
* askGateWire.ts 的 budget 定时器同样 unref,但它挂在无人 await 的 `void Promise.race(...)` 上,
|
|
285
|
+
* 后果只是丢一行 warn——两处形状相同后果不同,分野在于「这个 promise 有没有被 await」,不能
|
|
286
|
+
* 套用同一个 unref 兼容套(见 unrefTimer.ts 头注)。race settle 后 clearTimeout 掉该句柄
|
|
287
|
+
* (此前完全没有 clear,超时臂即使先输也留着一个已到期的句柄)。
|
|
280
288
|
*/
|
|
281
289
|
export async function awaitTaskAgentsWire(timeoutMs = 4000) {
|
|
282
290
|
if (!preparedPromise)
|
|
283
291
|
return;
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
292
|
+
let timeoutHandle;
|
|
293
|
+
try {
|
|
294
|
+
await Promise.race([
|
|
295
|
+
preparedPromise.catch(() => { }),
|
|
296
|
+
new Promise(resolve => {
|
|
297
|
+
timeoutHandle = setTimeout(resolve, timeoutMs);
|
|
298
|
+
}),
|
|
299
|
+
]);
|
|
300
|
+
}
|
|
301
|
+
finally {
|
|
302
|
+
if (timeoutHandle !== undefined)
|
|
303
|
+
clearTimeout(timeoutHandle);
|
|
304
|
+
}
|
|
291
305
|
}
|
|
292
306
|
/**
|
|
293
307
|
* 同步读面(liveClient.toLiveRequest 消费):当前投影好的 agents 载荷。每次读取后 kick 一次后台
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/argvFlagValue.ts — shared CC/commander-style "last flag value" argv-scan primitive
|
|
3
|
+
* (REF-CC-143 / REF-CC-dup-07, P3 wave1 卡C-argv, 2026-08-01;缺值策略位补于 wave1 回炉,
|
|
4
|
+
* blocker 修复,同日).
|
|
5
|
+
*
|
|
6
|
+
* Five call sites (limitsWire / sandboxWire / scenarioWire / headlessPermissionModeWire —
|
|
7
|
+
* interactiveToolsWire's own copy folds away entirely per REF-CC-dup-10, delegating to
|
|
8
|
+
* headlessPermissionModeWire instead) each hand-rolled the identical loop: scan everything
|
|
9
|
+
* before a bare `--` (positionals are never flags), accept both `--name <v>` and `--name=<v>`
|
|
10
|
+
* forms, repeated flag ⇒ LAST wins (commander convention).
|
|
11
|
+
*
|
|
12
|
+
* 缺值策略(收编口径,`onMissingValue` 显式位):当某一次 occurrence 的值缺席/长得像另一个 flag
|
|
13
|
+
* 时,这个共用叶提供两种可命名的处置——**调用方选,不由本叶替调用方决定**:
|
|
14
|
+
* · `'invalidate'`(缺省,limitsWire/sandboxWire/scenarioWire 用这个):那次缺值让整个旗的最终
|
|
15
|
+
* 取值塌缩成「有旗、无值」(`{present:true}`,raw 缺席)——与这三处一直以来的 fail-LOUD 立场
|
|
16
|
+
* 一致:重复旗严格 LAST occurrence 定生死,哪怕最后一次是缺值也不会回落到更早的合法值。
|
|
17
|
+
* · `'latch-previous'`(headlessPermissionModeWire 用这个):那次缺值被当作「这次 occurrence 没
|
|
18
|
+
* 提供新信息」,直接跳过,锁存(latch)住之前已经取到的合法值不动——这是收编前那份手写循环
|
|
19
|
+
* 的原语义(`if (typeof v === 'string' && !v.startsWith('-')) { mode = v }`,缺值分支从不碰
|
|
20
|
+
* `mode`),收编成共用叶不能悄悄把它改造成 invalidate 语义。
|
|
21
|
+
* 两种策略都遵守同一条不变量:**从未出现过合法值** ⇒ 恒回 `{present:true}`(raw 缺席),从不
|
|
22
|
+
* 编造一个值;调用方各自决定「有旗无值」之后怎么办(fail-loud 用法提示,或落到下一车道)。
|
|
23
|
+
*/
|
|
24
|
+
/** `lastFlagValue` 的判别式返回型(非法组合 `{present:false, raw:'x'}` 在类型层就不可构造)。 */
|
|
25
|
+
export type FlagValue = {
|
|
26
|
+
present: false;
|
|
27
|
+
} | {
|
|
28
|
+
present: true;
|
|
29
|
+
raw?: string;
|
|
30
|
+
};
|
|
31
|
+
/** 缺值(occurrence 存在但值缺席/长得像另一个 flag)时的处置策略——见上方模块 doc。 */
|
|
32
|
+
export type OnMissingFlagValue = 'invalidate' | 'latch-previous';
|
|
33
|
+
/**
|
|
34
|
+
* Pull the LAST value of a `--name <v>` / `--name=<v>` flag out of an argv slice (everything
|
|
35
|
+
* before a bare `--` — positionals are never flags). Returns:
|
|
36
|
+
* {present:false} — flag absent
|
|
37
|
+
* {present:true, raw} — flag present with a value token (possibly empty string)
|
|
38
|
+
* {present:true, raw:undefined} — flag present but no value was ever captured (see
|
|
39
|
+
* `onMissingValue` for what "captured" means across repeats)
|
|
40
|
+
*/
|
|
41
|
+
export declare function lastFlagValue(argv: readonly string[], name: string, onMissingValue?: OnMissingFlagValue): FlagValue;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/argvFlagValue.ts — shared CC/commander-style "last flag value" argv-scan primitive
|
|
3
|
+
* (REF-CC-143 / REF-CC-dup-07, P3 wave1 卡C-argv, 2026-08-01;缺值策略位补于 wave1 回炉,
|
|
4
|
+
* blocker 修复,同日).
|
|
5
|
+
*
|
|
6
|
+
* Five call sites (limitsWire / sandboxWire / scenarioWire / headlessPermissionModeWire —
|
|
7
|
+
* interactiveToolsWire's own copy folds away entirely per REF-CC-dup-10, delegating to
|
|
8
|
+
* headlessPermissionModeWire instead) each hand-rolled the identical loop: scan everything
|
|
9
|
+
* before a bare `--` (positionals are never flags), accept both `--name <v>` and `--name=<v>`
|
|
10
|
+
* forms, repeated flag ⇒ LAST wins (commander convention).
|
|
11
|
+
*
|
|
12
|
+
* 缺值策略(收编口径,`onMissingValue` 显式位):当某一次 occurrence 的值缺席/长得像另一个 flag
|
|
13
|
+
* 时,这个共用叶提供两种可命名的处置——**调用方选,不由本叶替调用方决定**:
|
|
14
|
+
* · `'invalidate'`(缺省,limitsWire/sandboxWire/scenarioWire 用这个):那次缺值让整个旗的最终
|
|
15
|
+
* 取值塌缩成「有旗、无值」(`{present:true}`,raw 缺席)——与这三处一直以来的 fail-LOUD 立场
|
|
16
|
+
* 一致:重复旗严格 LAST occurrence 定生死,哪怕最后一次是缺值也不会回落到更早的合法值。
|
|
17
|
+
* · `'latch-previous'`(headlessPermissionModeWire 用这个):那次缺值被当作「这次 occurrence 没
|
|
18
|
+
* 提供新信息」,直接跳过,锁存(latch)住之前已经取到的合法值不动——这是收编前那份手写循环
|
|
19
|
+
* 的原语义(`if (typeof v === 'string' && !v.startsWith('-')) { mode = v }`,缺值分支从不碰
|
|
20
|
+
* `mode`),收编成共用叶不能悄悄把它改造成 invalidate 语义。
|
|
21
|
+
* 两种策略都遵守同一条不变量:**从未出现过合法值** ⇒ 恒回 `{present:true}`(raw 缺席),从不
|
|
22
|
+
* 编造一个值;调用方各自决定「有旗无值」之后怎么办(fail-loud 用法提示,或落到下一车道)。
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* Pull the LAST value of a `--name <v>` / `--name=<v>` flag out of an argv slice (everything
|
|
26
|
+
* before a bare `--` — positionals are never flags). Returns:
|
|
27
|
+
* {present:false} — flag absent
|
|
28
|
+
* {present:true, raw} — flag present with a value token (possibly empty string)
|
|
29
|
+
* {present:true, raw:undefined} — flag present but no value was ever captured (see
|
|
30
|
+
* `onMissingValue` for what "captured" means across repeats)
|
|
31
|
+
*/
|
|
32
|
+
export function lastFlagValue(argv, name, onMissingValue = 'invalidate') {
|
|
33
|
+
const eq = `${name}=`;
|
|
34
|
+
let present = false;
|
|
35
|
+
let raw;
|
|
36
|
+
let valueMissing = false;
|
|
37
|
+
for (let i = 0; i < argv.length; i++) {
|
|
38
|
+
const a = argv[i];
|
|
39
|
+
if (a === undefined)
|
|
40
|
+
continue;
|
|
41
|
+
if (a === '--')
|
|
42
|
+
break; // positionals — never flags
|
|
43
|
+
if (a === name) {
|
|
44
|
+
present = true;
|
|
45
|
+
const nxt = argv[i + 1];
|
|
46
|
+
if (nxt === undefined || nxt.startsWith('-')) {
|
|
47
|
+
// a value that LOOKS like another flag (or is plain missing) is not a value.
|
|
48
|
+
if (onMissingValue === 'latch-previous')
|
|
49
|
+
continue; // keep whatever raw/valueMissing already hold
|
|
50
|
+
valueMissing = true;
|
|
51
|
+
raw = undefined;
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
valueMissing = false;
|
|
55
|
+
raw = nxt;
|
|
56
|
+
i++; // consume the value token
|
|
57
|
+
}
|
|
58
|
+
else if (a.startsWith(eq)) {
|
|
59
|
+
present = true;
|
|
60
|
+
valueMissing = false;
|
|
61
|
+
raw = a.slice(eq.length);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (!present)
|
|
65
|
+
return { present: false };
|
|
66
|
+
if (valueMissing || raw === undefined)
|
|
67
|
+
return { present: true };
|
|
68
|
+
return { present: true, raw };
|
|
69
|
+
}
|
|
@@ -27,8 +27,9 @@
|
|
|
27
27
|
* changes.
|
|
28
28
|
*/
|
|
29
29
|
import { type EnvLike } from './hostEnv.js';
|
|
30
|
-
/** The env key the shell reads.
|
|
31
|
-
*
|
|
30
|
+
/** The env key the shell reads. An {@link envFlagOff} spelling(REF-CC-141 dup-02 单源:
|
|
31
|
+
* `0`/`false`/`no`/`off`/`none`)⇒ no stamp; `full|all` ⇒ all five producers; unset/anything else
|
|
32
|
+
* ⇒ the CC-parity default pair. */
|
|
32
33
|
export declare const ATTACHMENTS_ENV: "SEMA_ATTACHMENTS";
|
|
33
34
|
/** Mirror of core `TaskSpec.attachments` (types.ts:1139) — literal-true unions. */
|
|
34
35
|
export interface AttachmentsSpec {
|
|
@@ -27,8 +27,10 @@
|
|
|
27
27
|
* changes.
|
|
28
28
|
*/
|
|
29
29
|
import { hostEnv } from './hostEnv.js';
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
import { envFlagOff } from './envFlag.js';
|
|
31
|
+
/** The env key the shell reads. An {@link envFlagOff} spelling(REF-CC-141 dup-02 单源:
|
|
32
|
+
* `0`/`false`/`no`/`off`/`none`)⇒ no stamp; `full|all` ⇒ all five producers; unset/anything else
|
|
33
|
+
* ⇒ the CC-parity default pair. */
|
|
32
34
|
export const ATTACHMENTS_ENV = 'SEMA_ATTACHMENTS';
|
|
33
35
|
/**
|
|
34
36
|
* ENV source → the `TaskRequest.attachments` stamp. Returns `undefined` (⇒ no field) on explicit
|
|
@@ -36,7 +38,7 @@ export const ATTACHMENTS_ENV = 'SEMA_ATTACHMENTS';
|
|
|
36
38
|
*/
|
|
37
39
|
export function attachmentsForRequest(env = hostEnv()) {
|
|
38
40
|
const raw = (env[ATTACHMENTS_ENV] ?? '').trim().toLowerCase();
|
|
39
|
-
if (raw
|
|
41
|
+
if (envFlagOff(raw))
|
|
40
42
|
return undefined;
|
|
41
43
|
if (raw === 'full' || raw === 'all') {
|
|
42
44
|
return { todoReminder: true, changedFiles: true, planModeReminder: true, backgroundTasks: true, toolsDelta: true };
|
|
@@ -24,6 +24,14 @@
|
|
|
24
24
|
* 🔴 fail-soft 铁律:识别不中一律静默走原路,绝不伤害事件流。
|
|
25
25
|
* 🔴 UNTRUSTED:reason 为分类器(模型)产文,只渲染绝不回喂;通知行截断 ≤80(207 同款)。
|
|
26
26
|
*/
|
|
27
|
+
/**
|
|
28
|
+
* 🟢 B8 ALLOW 清单登记(REF-CC-域词表-05,属主=client-core 规范重构轮,到期复议=core 改这句
|
|
29
|
+
* deny message 文案时或 2026-Q4 复审以先到者为准):文本匹配 + 非文本结构性合取前置
|
|
30
|
+
* (`ev.type==='tool_end' && ev.isError===true`,见 `classifierDenyFromToolEnd`)。同批同表的
|
|
31
|
+
* 另两处:`detachWire.ts` `DETACH_DURABLE_OFF_400_ANCHOR`(server 契约话)、
|
|
32
|
+
* `subagent/engineTaskHandleWire.ts` `STOP_CONFLICT_CODES`(SDK typed 缺席回落)——三处互指,
|
|
33
|
+
* 理由逐条写在各自站点。
|
|
34
|
+
*/
|
|
27
35
|
/** core hooks.js 分类器 deny message 的机器签名(逐字锚;lockstep:core 改文案这里必须跟)。 */
|
|
28
36
|
export declare const CLASSIFIER_DENY_SIGNATURE = "auto-mode classifier blocked this call";
|
|
29
37
|
export interface ClassifierDenyVerdict {
|
|
@@ -24,6 +24,14 @@
|
|
|
24
24
|
* 🔴 fail-soft 铁律:识别不中一律静默走原路,绝不伤害事件流。
|
|
25
25
|
* 🔴 UNTRUSTED:reason 为分类器(模型)产文,只渲染绝不回喂;通知行截断 ≤80(207 同款)。
|
|
26
26
|
*/
|
|
27
|
+
/**
|
|
28
|
+
* 🟢 B8 ALLOW 清单登记(REF-CC-域词表-05,属主=client-core 规范重构轮,到期复议=core 改这句
|
|
29
|
+
* deny message 文案时或 2026-Q4 复审以先到者为准):文本匹配 + 非文本结构性合取前置
|
|
30
|
+
* (`ev.type==='tool_end' && ev.isError===true`,见 `classifierDenyFromToolEnd`)。同批同表的
|
|
31
|
+
* 另两处:`detachWire.ts` `DETACH_DURABLE_OFF_400_ANCHOR`(server 契约话)、
|
|
32
|
+
* `subagent/engineTaskHandleWire.ts` `STOP_CONFLICT_CODES`(SDK typed 缺席回落)——三处互指,
|
|
33
|
+
* 理由逐条写在各自站点。
|
|
34
|
+
*/
|
|
27
35
|
/** core hooks.js 分类器 deny message 的机器签名(逐字锚;lockstep:core 改文案这里必须跟)。 */
|
|
28
36
|
export const CLASSIFIER_DENY_SIGNATURE = 'auto-mode classifier blocked this call';
|
|
29
37
|
/** 通知 reason 段截断(CC 207 L696763 同款 80 → 79+…)。 */
|
|
@@ -33,17 +33,28 @@ export type { McpServerSpec };
|
|
|
33
33
|
type Rec = Record<string, unknown>;
|
|
34
34
|
/** Env lookup shape (process.env or a test fixture). */
|
|
35
35
|
export type { EnvLike };
|
|
36
|
+
/** REF-CC-157(midband-05,fix-outright) 丢弃理由的四态之一——仿 skillsMissingBody 给 mcp 域补留痕:
|
|
37
|
+
* 一个打错字的 server name/字段此前会在用户毫无感知的情况下从 wire 上消失。 */
|
|
38
|
+
export type CloudMcpDropReason = 'disabled' | 'missing-field' | 'unknown-transport' | 'capped';
|
|
39
|
+
export interface CloudMcpDroppedServer {
|
|
40
|
+
/** 能取到就带上(未取到 name 的原始行——比如整条不是对象——留空,调用方仍能报「有 N 行没生效」)。 */
|
|
41
|
+
name?: string;
|
|
42
|
+
reason: CloudMcpDropReason;
|
|
43
|
+
}
|
|
36
44
|
export interface CloudMcpProjection {
|
|
37
45
|
specs: McpServerSpec[];
|
|
38
46
|
/** env NAMES referenced by envRefs/headerRefs that resolve to nothing in `env` (the ref is DROPPED —
|
|
39
47
|
* fail-closed on the value, loud in the caller's warning line). */
|
|
40
48
|
missingEnv: string[];
|
|
49
|
+
/** REF-CC-157:每一条被丢弃的原始 mcp server 行 + 丢弃理由,登记进 CloudProjection 供宿主警示。 */
|
|
50
|
+
droppedServers: CloudMcpDroppedServer[];
|
|
41
51
|
}
|
|
42
52
|
/**
|
|
43
53
|
* Project the registry's mcp domain (`config.mcp.servers`, registry-core McpServerSpec — the CENTER shape
|
|
44
54
|
* with envRefs/headerRefs) → the SDK/core wire `McpServerSpec[]` (real env/header VALUES, resolved from the
|
|
45
55
|
* shell env). Disabled servers are skipped; unknown transport kinds are skipped (never mis-mapped); the
|
|
46
|
-
* result is capped at MCP_CAPS.items exactly like the local `.mcp.json` projection.
|
|
56
|
+
* result is capped at MCP_CAPS.items exactly like the local `.mcp.json` projection. Every skip is recorded
|
|
57
|
+
* in `droppedServers` (REF-CC-157) — nothing vanishes from the wire silently.
|
|
47
58
|
*/
|
|
48
59
|
export declare function cloudMcpToSpecs(servers: unknown, env: EnvLike): CloudMcpProjection;
|
|
49
60
|
/**
|
|
@@ -61,6 +72,17 @@ export declare function cloudSkillsToSpecs(manifestSkills: unknown, resolveBody:
|
|
|
61
72
|
* semantics: no enabled models ⇒ env-catalog fallback).
|
|
62
73
|
*/
|
|
63
74
|
export declare function cloudModelsToDoc(models: unknown): Rec | null;
|
|
75
|
+
export interface CloudDroppedModel {
|
|
76
|
+
/** 能取到就带上;整条丢弃是因为二者都缺时,两个字段都可能不在。 */
|
|
77
|
+
id?: string;
|
|
78
|
+
name?: string;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* REF-CC-157(midband-05,fix-outright):`config.models.models` 里被 `cloudModelsToDoc` 过滤掉的原始
|
|
82
|
+
* 条目(缺 `name` 或 `id`)——仿 `skillsMissingBody` 的形状,重扫同一份原始数组产出丢弃清单,让调用方
|
|
83
|
+
* 能警示用户「你的 model 配置有 N 行没生效」,而不是让一个打错字的字段静默从目录消失。
|
|
84
|
+
*/
|
|
85
|
+
export declare function cloudModelsDropped(models: unknown): CloudDroppedModel[];
|
|
64
86
|
/** ENABLED model names in a models doc (banner/status display + "did the cloud catalog apply" checks). */
|
|
65
87
|
export declare function cloudModelNames(doc: Rec | null): string[];
|
|
66
88
|
/** `apiKeyEnv` NAMES referenced by enabled models that resolve to nothing in `env` — the engine child would
|
|
@@ -99,6 +121,11 @@ export interface CloudProjection {
|
|
|
99
121
|
scope: string;
|
|
100
122
|
/** Skills present in the manifest whose body could not be resolved (skipped on the wire). */
|
|
101
123
|
skillsMissingBody: string[];
|
|
124
|
+
/** REF-CC-157(midband-05):mcp 域被丢弃的原始 server 行(disabled/missing-field/unknown-transport/
|
|
125
|
+
* capped 四态之一)——仿 skillsMissingBody 的留痕机制,此前 mcp/models 两域零回执。 */
|
|
126
|
+
droppedMcpServers: CloudMcpDroppedServer[];
|
|
127
|
+
/** REF-CC-157:models 域被丢弃的原始条目(缺 name 或 id)。 */
|
|
128
|
+
droppedModels: CloudDroppedModel[];
|
|
102
129
|
/** S3 execution-lane policy ([580]① / registry-core 0.8). Consumed by the sandbox policy-lock seam;
|
|
103
130
|
* ⚠️ client-enforced ADVISORY (P5=A) — the engine gate is service [580]. */
|
|
104
131
|
execution: CloudExecutionProjection;
|