@sema-agent/client-core 0.92.0 → 0.93.1
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/CHANGELOG.md +227 -0
- package/README.md +25 -16
- package/dist/adapt/arms.js +2 -0
- package/dist/adapt/toolCards.js +6 -4
- package/dist/adapt.d.ts +1 -1
- package/dist/adapt.js +1 -1
- package/dist/adapter/runStream.js +3 -1
- package/dist/agentsWireCaps.js +1 -1
- package/dist/approvalDecidedByCapability.d.ts +16 -0
- package/dist/approvalDecidedByCapability.js +47 -0
- package/dist/approvalsStreamLiveCapability.js +3 -3
- package/dist/askSurvivesStandingAnswer.d.ts +1 -1
- package/dist/centerWiringCapability.js +1 -1
- package/dist/cloudConfigWireCaps.js +5 -5
- package/dist/compensations.js +2 -2
- package/dist/decideReceipt.d.ts +2 -0
- package/dist/decideReceipt.js +34 -9
- package/dist/detachWire.d.ts +2 -14
- package/dist/detachWire.js +1 -47
- package/dist/deviceExecutorManagementCapability.d.ts +6 -2
- package/dist/deviceExecutorManagementCapability.js +61 -15
- package/dist/engineConfigDrift.d.ts +20 -0
- package/dist/engineConfigDrift.js +54 -0
- package/dist/engineErrorCodes.d.ts +3 -0
- package/dist/engineErrorCodes.js +12 -4
- package/dist/engineInlineTaskStats.d.ts +1 -0
- package/dist/engineNoticeCodes.d.ts +2 -2
- package/dist/engineWireFor.d.ts +22 -0
- package/dist/engineWireFor.js +154 -9
- package/dist/engineWireSdk.d.ts +0 -1
- package/dist/engineWireSdk.js +0 -3
- package/dist/executionLaneCapability.js +2 -2
- package/dist/fileHistoryCaptureCapability.d.ts +1 -1
- package/dist/fileHistoryCaptureCapability.js +1 -6
- package/dist/fileHistoryLegNotice.d.ts +1 -1
- package/dist/fileHistoryLegNotice.js +1 -6
- package/dist/gateVocabulary.d.ts +1 -5
- package/dist/gateVocabulary.js +4 -22
- package/dist/generated/engineFactTables.d.ts +4 -3
- package/dist/generated/engineFactTables.js +10 -0
- package/dist/generated/engineNoticeTables.d.ts +1 -1
- package/dist/generated/engineNoticeTables.js +1 -1
- package/dist/goalStopHook.d.ts +1 -8
- package/dist/goalStopHook.js +2 -58
- package/dist/headlessPermissionModeWire.d.ts +3 -2
- package/dist/headlessPermissionModeWire.js +46 -5
- package/dist/hitl/approvalResolution.d.ts +3 -2
- package/dist/hitl/approvalResolution.js +13 -0
- package/dist/hitl/askParkRowRouting.js +2 -2
- package/dist/hitl/frameRouter.js +7 -2
- package/dist/hitl/gateLedger.d.ts +1 -0
- package/dist/hitl/gateLedger.js +3 -0
- package/dist/hitl/hitlBridge.d.ts +1 -0
- package/dist/hitl/hitlBridge.js +6 -1
- package/dist/hitl/hitlHostSurface.d.ts +6 -2
- package/dist/hitl/hitlHostSurface.js +29 -3
- package/dist/hitl/parkResolver.js +22 -4
- package/dist/hitl/persistedRulesWire.js +29 -17
- package/dist/hitl/planReviewWire.d.ts +0 -2
- package/dist/hitl/planReviewWire.js +1 -18
- package/dist/hitl/sessionPolicyDeliverable.js +3 -3
- package/dist/hitl/sessionPolicyWire.d.ts +2 -0
- package/dist/hitl/sessionPolicyWire.js +7 -4
- package/dist/hitl/toolApprovalWire.d.ts +32 -7
- package/dist/hitl/toolApprovalWire.js +282 -59
- package/dist/hooksWireCaps.d.ts +1 -1
- package/dist/hooksWireCaps.js +1 -1
- package/dist/index.d.ts +7 -2
- package/dist/index.js +6 -2
- package/dist/inheritEnvWire.d.ts +1 -4
- package/dist/inheritEnvWire.js +0 -18
- package/dist/limitsWire.d.ts +0 -6
- package/dist/limitsWire.js +0 -38
- package/dist/mcpProbeCapability.js +1 -1
- package/dist/mcpProbeWire.js +10 -12
- package/dist/mcpReconnect.d.ts +5 -0
- package/dist/mcpReconnect.js +28 -0
- package/dist/memoryComplianceCapability.js +2 -2
- package/dist/memoryOriginCapability.js +2 -2
- package/dist/memoryVerbsWire.js +14 -13
- package/dist/ownKey.d.ts +2 -0
- package/dist/ownKey.js +15 -0
- package/dist/peerLaneCapability.js +2 -2
- package/dist/permissionModesCapability.d.ts +16 -0
- package/dist/permissionModesCapability.js +71 -0
- package/dist/permissionRuleIssue.js +1 -1
- package/dist/permissionRulesWriteCapability.js +2 -2
- package/dist/permissionWireCaps.d.ts +2 -0
- package/dist/permissionWireCaps.js +8 -1
- package/dist/permissionsAllowGrantCapability.js +7 -2
- package/dist/postureKnob.js +1 -1
- package/dist/protocolSegment.d.ts +2 -0
- package/dist/protocolSegment.js +3 -0
- package/dist/readFacePosture.js +1 -1
- package/dist/resumeRefusalCopy.d.ts +1 -0
- package/dist/resumeRefusalCopy.js +26 -3
- package/dist/retryStatus.js +2 -1
- package/dist/rewindArchiveCapability.js +2 -2
- package/dist/runTerminal.d.ts +16 -0
- package/dist/runTerminal.js +32 -3
- package/dist/seam.d.ts +1 -0
- package/dist/sessionPolicyCapability.js +1 -1
- package/dist/sessionSyncFileHistoryCapability.js +2 -2
- package/dist/skillToolListsCapability.js +1 -1
- package/dist/sqlEngineCapability.js +1 -1
- package/dist/steerPriorityCapability.js +1 -1
- package/dist/storePostureCapability.js +2 -2
- package/dist/supportFloor.d.ts +1 -0
- package/dist/supportFloor.js +13 -3
- package/dist/taskRequestWords.d.ts +4 -2
- package/dist/taskRequestWords.js +1 -1
- package/dist/toolHistoryBadTurn.js +1 -2
- package/dist/toolResult.d.ts +2 -1
- package/dist/toolResult.js +33 -3
- package/dist/userInvokedSkillsCapability.js +1 -1
- package/dist/webSearchBackendCapability.js +2 -2
- package/dist/webSearchWireCaps.d.ts +1 -1
- package/dist/webSearchWireCaps.js +40 -2
- package/dist/wireFailureShape.js +2 -2
- package/dist/wireRefusalCopy.d.ts +9 -3
- package/dist/wireRefusalCopy.js +41 -4
- package/dist/workflowsJournalCapability.js +1 -1
- package/dist/writeProtectionCapability.js +1 -1
- package/docs/INTEGRATION-CLIENTS.md +999 -15
- package/package.json +2 -2
package/dist/adapt/arms.js
CHANGED
|
@@ -604,6 +604,7 @@ const taskProgressArm = function* (m, { ctx, cards, panel, inst }) {
|
|
|
604
604
|
toolUses: usage.toolUses ?? null,
|
|
605
605
|
}));
|
|
606
606
|
const currentAction = typeof m.currentAction === 'string' && m.currentAction.length > 0 ? m.currentAction : undefined;
|
|
607
|
+
const model = typeof m.model === 'string' && m.model.length > 0 ? m.model : undefined;
|
|
607
608
|
const spawnName = m.spawnName;
|
|
608
609
|
if (cardId !== undefined) {
|
|
609
610
|
yield chrome({
|
|
@@ -616,6 +617,7 @@ const taskProgressArm = function* (m, { ctx, cards, panel, inst }) {
|
|
|
616
617
|
totalTokens: typeof usage.totalTokens === 'number' ? usage.totalTokens : 0,
|
|
617
618
|
durationMs: typeof usage.durationMs === 'number' ? usage.durationMs : 0,
|
|
618
619
|
...(currentAction !== undefined ? { currentAction } : {}),
|
|
620
|
+
...(model !== undefined ? { model } : {}),
|
|
619
621
|
},
|
|
620
622
|
});
|
|
621
623
|
}
|
package/dist/adapt/toolCards.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { deriveTranscriptId } from '../seam.js';
|
|
2
|
-
import { degradedToolResultBody, detectEngineBgShellReceipt, reportFindingsToolUseResult, structuredToToolUseResult, todoWriteToolUseResult, wireOutputToBody, } from '../toolResult.js';
|
|
2
|
+
import { degradedToolResultBody, detectEngineBgShellDetach, detectEngineBgShellReceipt, reportFindingsToolUseResult, structuredToToolUseResult, todoWriteToolUseResult, wireOutputToBody, } from '../toolResult.js';
|
|
3
3
|
import { chrome, mainLane, transcript } from './ids.js';
|
|
4
4
|
import { flattenWireOutput } from './wireShapes.js';
|
|
5
5
|
import { isCcToolDenialKind } from '../gateVocabulary.js';
|
|
@@ -34,9 +34,11 @@ export function createToolCardLedger(ctx, idOf) {
|
|
|
34
34
|
let lastLiveTodos = [];
|
|
35
35
|
function* buildToolResult(p, end) {
|
|
36
36
|
const isError = end?.isError ?? false;
|
|
37
|
-
if ((p.name === 'Bash' || p.name === 'Monitor') && !isError
|
|
38
|
-
const
|
|
39
|
-
|
|
37
|
+
if ((p.name === 'Bash' || p.name === 'Monitor') && !isError) {
|
|
38
|
+
const outputText = end?.output !== undefined ? flattenWireOutput(end.output) : undefined;
|
|
39
|
+
const reg = detectEngineBgShellDetach(p.name, p.rawInput, end?.structured, outputText) ??
|
|
40
|
+
detectEngineBgShellReceipt(p.name, p.rawInput, outputText, end?.structured);
|
|
41
|
+
if (reg !== null) {
|
|
40
42
|
yield chrome({ kind: 'bgshell_register', laneProof: mainLane(), taskId: reg.taskId, registration: reg });
|
|
41
43
|
}
|
|
42
44
|
}
|
package/dist/adapt.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export declare const ADAPTER_COVERAGE: {
|
|
|
11
11
|
readonly transcriptKinds: readonly ["assistant_text", "assistant_thinking", "assistant_tool_use", "user_tool_result_decision", "user_task_notification", "system_passthrough"];
|
|
12
12
|
readonly b3: readonly ["T38 三清第三清 + T57 第五处断闸:prompt_suggestions(turn 开场作废 + 子流断闸)", "T40 IDLE-FLUSH 1.5s 竞速(需 ctx.setTimer;缺席=不启用)", "T58 手动 iterator 的 finally cleanup(early break/throw 都要关上游生成器)", "T59 abort 半场(ctx.signal;中断后不产终答)", "T60 无 result 收尾腿(泄尾增量 → 清 liveness → 尾思考 → 尾文本段)"];
|
|
13
13
|
readonly b4: readonly ["A 层第 14 臂 task_progress:workflow lane 三级门 + 判据④ belt 回植 + C1 alias + bindTaskCard(显式父/FIFO/含糊即 unbound)+ inline stats + T50 双形读 + SubagentStart + #6 resident 台账 + 面板 tick", "settlePanelTasks 三处 sweep 全接线(tool_end 显式关卡带报告 / result 防御 sweep / turn 末 + abort sweep)", "P0-2 tool label 侧信道(sanitizeToolUseBlock 摘 label + engineToolLabelStore 登记;0.5.0 真缺口,label 会随 tool_use block 落转录 → /compact 直发 provider 400)", "task_notification 的两件宿主义务收回库内自持:dropQueuedNotificationsForRun + clearEnginePanelTaskResident;stop hook 的 if-started 门由库解", "T8 flattenWireOutput 提为独立导出(A 层 settle 报告与 B 层卡体同一份)"];
|
|
14
|
-
readonly b5: readonly ["B 层 structuredToToolUseResult 14 case(ask-user-question/bash/edit/create/update/text/grep/glob/notebook-edit/cron-create/cron-delete/cron-list/agent/task-output)+ workflow-run 登记副作用", "D 层 wireOutputToBody 3 臂(bash / taskoutput / 泛化);structured 白名单在场时 T11+T14 正则退位,缺席保回落", "E 层 4 臂:#117a bg Bash 回执 + #158 Monitor 回执(同臂按工具名分,registration.source 判别;判定在库→chrome bgshell_register)· TodoWrite oldTodos 富卡 · ReportFindings 按名认领 · Remember→memory_saved 系统消息", "tool_end_result → user tool_result 正常路径(卡本体);result 与 turn 末两处开卡兜底关闭(abort 不兜底,cli 同)", "task/task-list structured → chrome task_ledger_sync{source:\"structured\"}(判定归一在库、落盘留宿主)", "T7 诚实缺席(§8-4:不搬 mock 合成器,改 degraded 标记)· T20 diff hunks 进包(src/diff/patch.ts)"];
|
|
14
|
+
readonly b5: readonly ["B 层 structuredToToolUseResult 14 case(ask-user-question/bash/edit/create/update/text/grep/glob/notebook-edit/cron-create/cron-delete/cron-list/agent/task-output)+ workflow-run 登记副作用", "D 层 wireOutputToBody 3 臂(bash / taskoutput / 泛化);structured 白名单在场时 T11+T14 正则退位,缺席保回落", "E 层 4 臂:#117a bg Bash 回执 + #158 Monitor 回执(同臂按工具名分,registration.source 判别;判定在库→chrome bgshell_register)+ CC-331 交出后台的 Bash(结构化 detached 位同形登记,一张卡至多一条;结构化位自述登记失败时两臂都不铸)· TodoWrite oldTodos 富卡 · ReportFindings 按名认领 · Remember→memory_saved 系统消息", "tool_end_result → user tool_result 正常路径(卡本体);result 与 turn 末两处开卡兜底关闭(abort 不兜底,cli 同)", "task/task-list structured → chrome task_ledger_sync{source:\"structured\"}(判定归一在库、落盘留宿主)", "T7 诚实缺席(§8-4:不搬 mock 合成器,改 degraded 标记)· T20 diff hunks 进包(src/diff/patch.ts)"];
|
|
15
15
|
readonly todo: readonly ["T13 的 **D 层** 半场(taskoutput block content)未随 structured 退位:退位会改 block content 形状(cli 那里是裸对象 = 件1 隐患),属行为面改动,无真实需求驱动 ⇒ 见 DIVERGENCE-8", "macrotask 让渡(cli 在提交前让出宏任务给 Ink;宿主渲染策略,不进库)"];
|
|
16
16
|
};
|
|
17
17
|
export declare const ADAPTER_DIVERGENCES: readonly [string, string, string, string, string, string, string, string, string, string, string, string];
|
package/dist/adapt.js
CHANGED
|
@@ -55,7 +55,7 @@ export const ADAPTER_COVERAGE = {
|
|
|
55
55
|
b5: [
|
|
56
56
|
'B 层 structuredToToolUseResult 14 case(ask-user-question/bash/edit/create/update/text/grep/glob/notebook-edit/cron-create/cron-delete/cron-list/agent/task-output)+ workflow-run 登记副作用',
|
|
57
57
|
'D 层 wireOutputToBody 3 臂(bash / taskoutput / 泛化);structured 白名单在场时 T11+T14 正则退位,缺席保回落',
|
|
58
|
-
'E 层 4 臂:#117a bg Bash 回执 + #158 Monitor 回执(同臂按工具名分,registration.source 判别;判定在库→chrome bgshell_register)· TodoWrite oldTodos 富卡 · ReportFindings 按名认领 · Remember→memory_saved 系统消息',
|
|
58
|
+
'E 层 4 臂:#117a bg Bash 回执 + #158 Monitor 回执(同臂按工具名分,registration.source 判别;判定在库→chrome bgshell_register)+ CC-331 交出后台的 Bash(结构化 detached 位同形登记,一张卡至多一条;结构化位自述登记失败时两臂都不铸)· TodoWrite oldTodos 富卡 · ReportFindings 按名认领 · Remember→memory_saved 系统消息',
|
|
59
59
|
'tool_end_result → user tool_result 正常路径(卡本体);result 与 turn 末两处开卡兜底关闭(abort 不兜底,cli 同)',
|
|
60
60
|
'task/task-list structured → chrome task_ledger_sync{source:"structured"}(判定归一在库、落盘留宿主)',
|
|
61
61
|
'T7 诚实缺席(§8-4:不搬 mock 合成器,改 degraded 标记)· T20 diff hunks 进包(src/diff/patch.ts)',
|
|
@@ -329,8 +329,10 @@ const DROPPED_WHY_SENTENCE = Object.freeze({
|
|
|
329
329
|
'If the engine reuses an id across two DIFFERENT frames (server 7.77.0 does this for `reasoning_end`, fixed upstream in 7.78.1), the second one is lost here — this line is the only trace.',
|
|
330
330
|
turn_end_usage_absent: "the engine declares `turn_end.usage` as always present (core >= 7.17.0), and this frame has none. " +
|
|
331
331
|
'The turn is counted as UNKNOWN spend (the run total is reported as a lower bound), and the frame itself renders NOWHERE.',
|
|
332
|
+
unknown_arm: "this build's projector has no arm for this frame type, so it was dropped — the type is not one this build knows (an engine newer than this client can send such frames). It renders NOWHERE.",
|
|
333
|
+
malformed: "this build's projector has an arm for this frame type, but the frame did not pass that arm's shape check (a field it requires was not usable), so it was dropped. It renders NOWHERE.",
|
|
332
334
|
});
|
|
333
|
-
const DROPPED_WHY_SENTENCE_DEFAULT = "this build's projector has no arm for it (engine newer than the client, or a malformed frame). It renders NOWHERE.";
|
|
335
|
+
const DROPPED_WHY_SENTENCE_DEFAULT = "this build's projector has no arm for it (engine newer than the client, or a malformed frame; this build cannot tell which). It renders NOWHERE.";
|
|
334
336
|
export function droppedWhySentence(why) {
|
|
335
337
|
const row = Object.hasOwn(DROPPED_WHY_SENTENCE, why) ? DROPPED_WHY_SENTENCE[why] : undefined;
|
|
336
338
|
return typeof row === 'string' ? row : DROPPED_WHY_SENTENCE_DEFAULT;
|
package/dist/agentsWireCaps.js
CHANGED
|
@@ -249,7 +249,7 @@ async function runPrepare(cfg, projector, probe, generation) {
|
|
|
249
249
|
const [caps, projected] = await Promise.all([probe, projector()]);
|
|
250
250
|
if (caps === false) {
|
|
251
251
|
if (projected.agents && preparedKey === cfg.baseUrl) {
|
|
252
|
-
warnOnce(`agents wire: this engine does not support per-task custom agents (capabilities.taskAgents
|
|
252
|
+
warnOnce(`agents wire: this engine does not support per-task custom agents (capabilities.taskAgents is not true: the engine does not report it, or this deployment turns it off, for example a multi-tenant one; this client cannot tell which) — ${projected.agents.length} custom agent definition(s) will NOT be sent`);
|
|
253
253
|
}
|
|
254
254
|
return;
|
|
255
255
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type ApprovalDecidedByReading = {
|
|
2
|
+
kind: 'unobserved';
|
|
3
|
+
} | {
|
|
4
|
+
kind: 'not_reported';
|
|
5
|
+
} | {
|
|
6
|
+
kind: 'present';
|
|
7
|
+
value: true;
|
|
8
|
+
};
|
|
9
|
+
export declare function projectApprovalDecidedByCapability(caps: unknown): ApprovalDecidedByReading | undefined;
|
|
10
|
+
export declare function noteEngineCapsForApprovalDecidedBy(baseUrl: string, caps: unknown, opts?: {
|
|
11
|
+
generation?: number;
|
|
12
|
+
}): void;
|
|
13
|
+
export declare function observedApprovalDecidedBy(baseUrl?: string | undefined): ApprovalDecidedByReading;
|
|
14
|
+
export declare function approvalDecidedByAdmitted(reading: ApprovalDecidedByReading | undefined): boolean;
|
|
15
|
+
export declare function forgetApprovalDecidedByReading(baseUrl: string | undefined): void;
|
|
16
|
+
export declare function __resetApprovalDecidedByReadingsForTests(): void;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { engineWireTarget } from './engineWireTarget.js';
|
|
2
|
+
import { createEngineCapReader } from './engineCapReader.js';
|
|
3
|
+
import { readOwnDataValue } from './ownKey.js';
|
|
4
|
+
export function projectApprovalDecidedByCapability(caps) {
|
|
5
|
+
try {
|
|
6
|
+
if (caps === null || typeof caps !== 'object' || Array.isArray(caps))
|
|
7
|
+
return undefined;
|
|
8
|
+
if (!Object.hasOwn(caps, 'approvalDecidedBy'))
|
|
9
|
+
return { kind: 'not_reported' };
|
|
10
|
+
const v = caps.approvalDecidedBy;
|
|
11
|
+
if (v === undefined)
|
|
12
|
+
return { kind: 'not_reported' };
|
|
13
|
+
return v === true ? { kind: 'present', value: true } : undefined;
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
const reader = createEngineCapReader({
|
|
20
|
+
name: 'approvalDecidedBy',
|
|
21
|
+
project: projectApprovalDecidedByCapability,
|
|
22
|
+
makeUnobserved: () => ({ kind: 'unobserved' }),
|
|
23
|
+
});
|
|
24
|
+
export function noteEngineCapsForApprovalDecidedBy(baseUrl, caps, opts) {
|
|
25
|
+
reader.note(baseUrl, caps, opts);
|
|
26
|
+
}
|
|
27
|
+
export function observedApprovalDecidedBy(baseUrl = engineWireTarget()?.baseUrl) {
|
|
28
|
+
return reader.observed(baseUrl);
|
|
29
|
+
}
|
|
30
|
+
export function approvalDecidedByAdmitted(reading) {
|
|
31
|
+
try {
|
|
32
|
+
if (reading === null || reading === undefined || typeof reading !== 'object' || Array.isArray(reading))
|
|
33
|
+
return false;
|
|
34
|
+
if (readOwnDataValue(reading, 'kind') !== 'present')
|
|
35
|
+
return false;
|
|
36
|
+
return readOwnDataValue(reading, 'value') === true;
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
export function forgetApprovalDecidedByReading(baseUrl) {
|
|
43
|
+
reader.forget(baseUrl);
|
|
44
|
+
}
|
|
45
|
+
export function __resetApprovalDecidedByReadingsForTests() {
|
|
46
|
+
reader.__resetForTests();
|
|
47
|
+
}
|
|
@@ -31,13 +31,13 @@ export function livePendingNeedsReconcile(reading) {
|
|
|
31
31
|
export function approvalsStreamLiveDoctorDetail(reading) {
|
|
32
32
|
switch (reading.kind) {
|
|
33
33
|
case 'unobserved':
|
|
34
|
-
return 'live approval push not observed — the engine reports it on /v1/capabilities; this process has no usable capabilities reading cached for it (none received, or the last one was
|
|
34
|
+
return 'live approval push not observed — the engine reports it on /v1/capabilities; this process has no usable capabilities reading cached for it (none received, the last one was unreadable, or the last one was discarded when the engine connection was reset; this process cannot tell which), so suspended asks are pulled by the reconcile cadence';
|
|
35
35
|
case 'not_reported':
|
|
36
|
-
return 'live approval push not reported by this engine
|
|
36
|
+
return 'live approval push not reported by this engine; this does not say whether it pushes, so suspended asks are pulled by the reconcile cadence';
|
|
37
37
|
case 'present':
|
|
38
38
|
return reading.live
|
|
39
39
|
? 'live approval push on — the engine announces suspended asks on the approvals stream; the reconcile cadence is only a fallback'
|
|
40
|
-
: 'live approval push off on this deployment (no checkpoint store or tool approvals disabled) — suspended asks are only visible through the reconcile cadence, so the client polls for them';
|
|
40
|
+
: 'live approval push off on this deployment (no checkpoint store or tool approvals disabled; the engine reports one bit for both, so this client cannot tell which) — suspended asks are only visible through the reconcile cadence, so the client polls for them';
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
export function forgetApprovalsStreamLiveReading(baseUrl) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type AutomaticAnswerRoad, type AutomaticAnswerUnknownWhy } from './hitl/automaticAnswerVerdict.js';
|
|
2
|
-
export declare const MODE_ARBITRATION: Readonly<Record<"hook" | "write_protection" | "mode" | "rule_unreadable" | "content_question" | "ancestor" | "unverifiable_delete" | "transcript_write" | "org_rule" | "governance_unavailable" | "ask_rule" | "denial_limit_fallback" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "write_protection_unresolved" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary", import("./generated/engineFactTables.js").CoreModeArbitrationRow>>;
|
|
2
|
+
export declare const MODE_ARBITRATION: Readonly<Record<"hook" | "write_protection" | "mode" | "rule_unreadable" | "content_question" | "ancestor" | "unverifiable_delete" | "transcript_write" | "org_rule" | "governance_unavailable" | "ask_rule" | "denial_limit_fallback" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "write_protection_unresolved" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary", import("./generated/engineFactTables.js").CoreModeArbitrationRow>>;
|
|
3
3
|
export type StandingAnswerVerdict = {
|
|
4
4
|
readonly kind: 'must_ask';
|
|
5
5
|
readonly by: string;
|
|
@@ -159,7 +159,7 @@ export function centerWiringDoctorDetail(reading) {
|
|
|
159
159
|
const unobserved = 'center wiring not observed — the engine reports it on /v1/capabilities; this process has no usable capabilities reading cached for it, so whether this engine is connected to a configuration center is unknown';
|
|
160
160
|
const r = guarded(reading);
|
|
161
161
|
if (r?.kind === 'not_reported') {
|
|
162
|
-
return 'center wiring not reported by this engine
|
|
162
|
+
return 'center wiring not reported by this engine; this does not say whether the engine is connected to a configuration center';
|
|
163
163
|
}
|
|
164
164
|
if (r?.kind === 'none') {
|
|
165
165
|
return 'no configuration center on this deployment — the engine runs on its own local configuration; no quota lease or usage reporting goes through a center';
|
|
@@ -489,6 +489,8 @@ export function projectEffectiveBody(body, skillBodies, env, rostersValue, opts)
|
|
|
489
489
|
}
|
|
490
490
|
const quoted = (s, fallback) => (s === undefined ? fallback : `the "${s}" settings`);
|
|
491
491
|
const listOf = (xs, truncatedFrom) => xs === undefined ? '' : `: ${xs.join(', ')}${truncatedFrom === undefined ? '' : ` (${truncatedFrom} in total)`}`;
|
|
492
|
+
const ENTRY_UNUSABLE_WHY = '(incomplete or invalid settings; this client cannot tell which)';
|
|
493
|
+
const ENTRY_REJECTED = `is in the catalog, but its entry is one the local engine cannot use ${ENTRY_UNUSABLE_WHY}`;
|
|
492
494
|
function warningNotice(w) {
|
|
493
495
|
const where = quoted(w.domain, 'the configuration');
|
|
494
496
|
switch (w.kind) {
|
|
@@ -512,12 +514,10 @@ function warningNotice(w) {
|
|
|
512
514
|
}
|
|
513
515
|
function droppedRefNotice(d) {
|
|
514
516
|
const t = d.target;
|
|
515
|
-
const notServed = d.reason === 'rejected'
|
|
516
|
-
? 'is in the catalog, but its entry is one the local engine cannot use (incomplete or invalid settings)'
|
|
517
|
-
: 'is not in the model catalog served to you';
|
|
517
|
+
const notServed = d.reason === 'rejected' ? ENTRY_REJECTED : 'is not in the model catalog served to you';
|
|
518
518
|
switch (d.key) {
|
|
519
519
|
case 'models':
|
|
520
|
-
return { level: 'warn', text: `cloud config: ${t === undefined ? 'a model entry' : `model "${t}"`}
|
|
520
|
+
return { level: 'warn', text: `cloud config: ${t === undefined ? 'a model entry' : `model "${t}"`} ${ENTRY_REJECTED} — it was left out of the local catalog` };
|
|
521
521
|
case 'default':
|
|
522
522
|
return { level: 'warn', text: `cloud config: ${t === undefined ? 'the default model setting could not be read' : `the default model "${t}" ${notServed}`}, so it was left out — the local engine picks its default from roles and tiers instead` };
|
|
523
523
|
case 'roles':
|
|
@@ -599,7 +599,7 @@ export function cloudEffectiveNotices(p) {
|
|
|
599
599
|
const shown = named.slice(0, 5).join(', ') + (named.length > 5 ? `, +${named.length - 5} more` : '');
|
|
600
600
|
out.push({
|
|
601
601
|
level: 'warn',
|
|
602
|
-
text: `cloud config: none of the model entries served to you${shown !== '' ? ` (${shown})` : ''} is one the local engine can use
|
|
602
|
+
text: `cloud config: none of the model entries served to you${shown !== '' ? ` (${shown})` : ''} is one the local engine can use ${ENTRY_UNUSABLE_WHY} — ` +
|
|
603
603
|
'the catalog is kept as sent, and a locally started engine rejects the cloud model settings: at startup it uses its own environment catalog instead, and on a later refresh it keeps the previous configuration',
|
|
604
604
|
});
|
|
605
605
|
}
|
package/dist/compensations.js
CHANGED
|
@@ -25,7 +25,7 @@ export const MIGRATED_COMPENSATIONS = [
|
|
|
25
25
|
libraryHalf: 'adapt.ts fireSubagentStart()(类型恒记 + 一生一次去重 + if-started 门)',
|
|
26
26
|
chromeArm: 'subagent_lifecycle',
|
|
27
27
|
hostHalf: '真执行用户 hook 进程(浏览器宿主根本不能执行 ⇒ 这一半必须留端)',
|
|
28
|
-
retireOn:
|
|
28
|
+
retireOn: null,
|
|
29
29
|
},
|
|
30
30
|
{
|
|
31
31
|
id: 'T36',
|
|
@@ -34,7 +34,7 @@ export const MIGRATED_COMPENSATIONS = [
|
|
|
34
34
|
libraryHalf: 'adapt.ts settlePanelTasks 的四个调用点(tool_end 关卡 / result / turn 末 / abort)',
|
|
35
35
|
chromeArm: 'inline_task_stats',
|
|
36
36
|
hostHalf: null,
|
|
37
|
-
retireOn:
|
|
37
|
+
retireOn: null,
|
|
38
38
|
},
|
|
39
39
|
{
|
|
40
40
|
id: 'T44',
|
package/dist/decideReceipt.d.ts
CHANGED
|
@@ -18,6 +18,8 @@ export declare function decideAcceptedNotResolved(receipt: DecideReceiptView | u
|
|
|
18
18
|
export interface DecideRefusalDetail {
|
|
19
19
|
code: string;
|
|
20
20
|
runId?: string;
|
|
21
|
+
runIds?: readonly string[];
|
|
22
|
+
readableHolderRunId?: string;
|
|
21
23
|
detail: string;
|
|
22
24
|
resendable: boolean;
|
|
23
25
|
}
|
package/dist/decideReceipt.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { gateOutcomeOf } from './gateOutcome.js';
|
|
2
2
|
import { resumeReopenFromError } from './hitl/suspendedReopen.js';
|
|
3
|
-
import { ASK_GONE, ASK_GONE_DENIED_WORD, DECIDE_CLAIM_LOST, DECIDE_GATE_MOVED, DECIDE_NOT_PARKED, DECIDE_WORKFLOW_HOST_UNKNOWN, DECIDE_WORKFLOW_LANE_CODES, DECIDE_WORKFLOW_REMEMBER_UNSUPPORTED, isDecideParkMovedCode, } from './engineErrorCodes.js';
|
|
3
|
+
import { ASK_GONE, ASK_GONE_DENIED_WORD, DECIDE_CLAIM_LOST, DECIDE_GATE_MOVED, DECIDE_NOT_PARKED, DECIDE_WORKFLOW_HOST_UNKNOWN, DECIDE_WORKFLOW_LANE_CODES, DECIDE_WORKFLOW_PARK_FORKED, DECIDE_WORKFLOW_PARKS_UNREADABLE, DECIDE_WORKFLOW_REMEMBER_UNSUPPORTED, isDecideParkMovedCode, } from './engineErrorCodes.js';
|
|
4
4
|
import { effectiveWireErrorCode } from './wireErrorTriage.js';
|
|
5
|
-
import { readErrorString } from './wireFailureShape.js';
|
|
5
|
+
import { readErrorString, readErrorStrictStringList } from './wireFailureShape.js';
|
|
6
6
|
import { isCrashConvergedCause } from './hitl/crashConverged.js';
|
|
7
7
|
const STATUS_RESUMING = 'resuming';
|
|
8
8
|
function str(v) {
|
|
@@ -57,25 +57,50 @@ export function decideAcceptedNotResolved(receipt) {
|
|
|
57
57
|
const DECIDE_REFUSAL_SENTENCES = Object.freeze({
|
|
58
58
|
[DECIDE_WORKFLOW_HOST_UNKNOWN]: 'no session is attached to this run to receive the decision, so re-sending the same decision cannot help; the approval is still pending and can be decided again once the run is reachable',
|
|
59
59
|
[DECIDE_WORKFLOW_REMEMBER_UNSUPPORTED]: 'this run cannot remember the decision for the session; re-send the same decision without the remember option — nothing was consumed by this refusal',
|
|
60
|
+
[DECIDE_WORKFLOW_PARKS_UNREADABLE]: "this approval cannot be matched to the run that is waiting on it, because that run's record was written by an earlier engine version or is damaged; nothing was delivered and the approval is still pending — try resuming that run, and if this approval is still refused afterwards, the record has to be repaired by whoever operates this deployment before it can be decided",
|
|
61
|
+
[DECIDE_WORKFLOW_PARK_FORKED]: 'the same run was resumed more than once and each resumed copy is waiting on this same approval, so there is no single run to hand the decision to; nothing was delivered and the approval is still pending — resume one of those runs, and if it reaches this approval again, decide here',
|
|
60
62
|
});
|
|
61
63
|
const DECIDE_RESENDABLE = Object.freeze({
|
|
62
64
|
[DECIDE_WORKFLOW_HOST_UNKNOWN]: false,
|
|
63
65
|
[DECIDE_WORKFLOW_REMEMBER_UNSUPPORTED]: true,
|
|
66
|
+
[DECIDE_WORKFLOW_PARKS_UNREADABLE]: false,
|
|
67
|
+
[DECIDE_WORKFLOW_PARK_FORKED]: false,
|
|
64
68
|
});
|
|
69
|
+
function readTopOwn(e, key) {
|
|
70
|
+
try {
|
|
71
|
+
return e !== null && e !== undefined ? e[key] : undefined;
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function readForkedRunIds(e) {
|
|
78
|
+
const list = readErrorStrictStringList(e, 'runIds');
|
|
79
|
+
if (list === undefined || list.length === 0)
|
|
80
|
+
return undefined;
|
|
81
|
+
for (const id of list)
|
|
82
|
+
if (id.length === 0)
|
|
83
|
+
return undefined;
|
|
84
|
+
return Object.freeze(list.slice());
|
|
85
|
+
}
|
|
65
86
|
export function decideRefusalFromError(e) {
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
: undefined;
|
|
87
|
+
const rawCode = readTopOwn(e, 'errorCode');
|
|
88
|
+
const code = typeof rawCode === 'string' ? rawCode : undefined;
|
|
69
89
|
if (code === undefined || !DECIDE_WORKFLOW_LANE_CODES.includes(code))
|
|
70
90
|
return null;
|
|
71
|
-
const rawRunId = e
|
|
91
|
+
const rawRunId = code === DECIDE_WORKFLOW_PARK_FORKED ? undefined : readTopOwn(e, 'runId');
|
|
72
92
|
const runId = typeof rawRunId === 'string' && rawRunId.length > 0 ? rawRunId : undefined;
|
|
93
|
+
const runIds = code === DECIDE_WORKFLOW_PARK_FORKED ? readForkedRunIds(e) : undefined;
|
|
94
|
+
const holderRaw = code === DECIDE_WORKFLOW_PARKS_UNREADABLE ? readErrorString(e, 'readableHolderRunId') : undefined;
|
|
95
|
+
const readableHolderRunId = holderRaw !== undefined && holderRaw.length > 0 ? holderRaw : undefined;
|
|
73
96
|
const detail = Object.hasOwn(DECIDE_REFUSAL_SENTENCES, code)
|
|
74
97
|
? DECIDE_REFUSAL_SENTENCES[code]
|
|
75
98
|
: undefined;
|
|
76
99
|
return {
|
|
77
100
|
code,
|
|
78
101
|
...(runId !== undefined ? { runId } : {}),
|
|
102
|
+
...(runIds !== undefined ? { runIds } : {}),
|
|
103
|
+
...(readableHolderRunId !== undefined ? { readableHolderRunId } : {}),
|
|
79
104
|
detail: detail ?? 'the engine refused this decision; the approval is still pending and can be decided again',
|
|
80
105
|
resendable: Object.hasOwn(DECIDE_RESENDABLE, code) ? DECIDE_RESENDABLE[code] === true : false,
|
|
81
106
|
};
|
|
@@ -88,9 +113,9 @@ export function decideParkMovedFromError(e) {
|
|
|
88
113
|
return { code, ...(taskId !== undefined && taskId.length > 0 ? { taskId } : {}) };
|
|
89
114
|
}
|
|
90
115
|
const DECIDE_PARK_MOVED_WHAT = Object.freeze({
|
|
91
|
-
[DECIDE_NOT_PARKED]: 'This approval was no longer waiting when the decision arrived (the agent was stopped, the approval was decided elsewhere, or the session it belongs to was deleted)',
|
|
92
|
-
[DECIDE_GATE_MOVED]: 'This approval moved while the decision was on its way (it was parked again, or settled elsewhere)',
|
|
93
|
-
[DECIDE_CLAIM_LOST]: 'Another decision on this approval got there first, or an earlier attempt is still holding it until the engine clears that hold on its own',
|
|
116
|
+
[DECIDE_NOT_PARKED]: 'This approval was no longer waiting when the decision arrived (the agent was stopped, the approval was decided elsewhere, or the session it belongs to was deleted; this client cannot tell which)',
|
|
117
|
+
[DECIDE_GATE_MOVED]: 'This approval moved while the decision was on its way (it was parked again, or settled elsewhere; this client cannot tell which)',
|
|
118
|
+
[DECIDE_CLAIM_LOST]: 'Another decision on this approval got there first, or an earlier attempt is still holding it until the engine clears that hold on its own; this client cannot tell which',
|
|
94
119
|
});
|
|
95
120
|
export function decideParkMovedContent(detail) {
|
|
96
121
|
let code;
|
package/dist/detachWire.d.ts
CHANGED
|
@@ -2,27 +2,15 @@ import { type EnvLike } from './hostEnv.js';
|
|
|
2
2
|
import { type WireAuthTokenSource } from './engineWireSdk.js';
|
|
3
3
|
export declare const DETACH_HEADER = "x-detach-on-disconnect";
|
|
4
4
|
export declare const HEADLESS_DETACH_ENV = "SEMA_HEADLESS_DETACH";
|
|
5
|
-
export declare const DETACH_WIRE_MIN_ENGINE: readonly [number, number, number];
|
|
6
|
-
export declare const versionSupportsDetach: (v: string | undefined) => boolean;
|
|
7
5
|
export declare function headlessDetachDisabledByEnv(env?: EnvLike): boolean;
|
|
8
|
-
export type EngineDetachSupport = 'supported' | 'unsupported' | 'unknown';
|
|
9
|
-
export declare function probeEngineDetachSupport(baseUrl: string, opts?: {
|
|
10
|
-
fetchImpl?: typeof fetch;
|
|
11
|
-
timeoutMs?: number;
|
|
12
|
-
}): Promise<EngineDetachSupport>;
|
|
13
|
-
export declare function detachSupportDisclosure(support: EngineDetachSupport): string | undefined;
|
|
14
|
-
export declare function engineSupportsDetach(baseUrl: string, opts?: {
|
|
15
|
-
fetchImpl?: typeof fetch;
|
|
16
|
-
timeoutMs?: number;
|
|
17
|
-
}): Promise<boolean>;
|
|
18
6
|
export type DetachResolution = {
|
|
19
7
|
on: true;
|
|
20
8
|
reason: 'default-on';
|
|
21
9
|
} | {
|
|
22
10
|
on: false;
|
|
23
|
-
reason: 'env-off'
|
|
11
|
+
reason: 'env-off';
|
|
24
12
|
};
|
|
25
|
-
export declare function resolveHeadlessDetach(
|
|
13
|
+
export declare function resolveHeadlessDetach(_baseUrl: string, env?: EnvLike, _opts?: {
|
|
26
14
|
fetchImpl?: typeof fetch;
|
|
27
15
|
timeoutMs?: number;
|
|
28
16
|
}): Promise<DetachResolution>;
|
package/dist/detachWire.js
CHANGED
|
@@ -1,60 +1,14 @@
|
|
|
1
1
|
import { hostEnv } from './hostEnv.js';
|
|
2
2
|
import { envFlagOff } from './envFlag.js';
|
|
3
|
-
import { versionSupportsLimits } from './limitsWire.js';
|
|
4
3
|
import { resolveWireAuth } from './engineWireSdk.js';
|
|
5
4
|
export const DETACH_HEADER = 'x-detach-on-disconnect';
|
|
6
5
|
export const HEADLESS_DETACH_ENV = 'SEMA_HEADLESS_DETACH';
|
|
7
|
-
export const DETACH_WIRE_MIN_ENGINE = [1, 196, 0];
|
|
8
|
-
export const versionSupportsDetach = versionSupportsLimits;
|
|
9
6
|
export function headlessDetachDisabledByEnv(env = hostEnv()) {
|
|
10
7
|
return envFlagOff(env[HEADLESS_DETACH_ENV]);
|
|
11
8
|
}
|
|
12
|
-
export async function
|
|
13
|
-
const fetchImpl = opts?.fetchImpl ?? fetch;
|
|
14
|
-
const controller = new AbortController();
|
|
15
|
-
const timer = setTimeout(() => controller.abort(), opts?.timeoutMs ?? 1500);
|
|
16
|
-
try {
|
|
17
|
-
const res = await fetchImpl(`${baseUrl.replace(/\/+$/, '')}/health`, {
|
|
18
|
-
method: 'GET',
|
|
19
|
-
signal: controller.signal,
|
|
20
|
-
});
|
|
21
|
-
if (!res.ok)
|
|
22
|
-
return 'unknown';
|
|
23
|
-
const body = await res.json();
|
|
24
|
-
if (body === null || typeof body !== 'object' || Array.isArray(body))
|
|
25
|
-
return 'unknown';
|
|
26
|
-
if (!('version' in body))
|
|
27
|
-
return 'unsupported';
|
|
28
|
-
const version = body.version;
|
|
29
|
-
if (typeof version !== 'string' || !/^\d+\.\d+\.\d+/.test(version))
|
|
30
|
-
return 'unknown';
|
|
31
|
-
if (versionSupportsDetach(version))
|
|
32
|
-
return 'supported';
|
|
33
|
-
return 'unsupported';
|
|
34
|
-
}
|
|
35
|
-
catch {
|
|
36
|
-
return 'unknown';
|
|
37
|
-
}
|
|
38
|
-
finally {
|
|
39
|
-
clearTimeout(timer);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
export function detachSupportDisclosure(support) {
|
|
43
|
-
if (support !== 'unknown')
|
|
44
|
-
return undefined;
|
|
45
|
-
return 'could not confirm whether this engine supports detach (its /health did not answer usably); sending the detach header anyway — it is harmless on the wire, and a dead engine fails the request loudly';
|
|
46
|
-
}
|
|
47
|
-
export async function engineSupportsDetach(baseUrl, opts) {
|
|
48
|
-
return (await probeEngineDetachSupport(baseUrl, opts)) !== 'unsupported';
|
|
49
|
-
}
|
|
50
|
-
export async function resolveHeadlessDetach(baseUrl, env = hostEnv(), opts) {
|
|
9
|
+
export async function resolveHeadlessDetach(_baseUrl, env = hostEnv(), _opts) {
|
|
51
10
|
if (headlessDetachDisabledByEnv(env))
|
|
52
11
|
return { on: false, reason: 'env-off' };
|
|
53
|
-
if (env.SEMA_ENGINE_URL) {
|
|
54
|
-
const ok = await engineSupportsDetach(baseUrl, opts);
|
|
55
|
-
if (!ok)
|
|
56
|
-
return { on: false, reason: 'old-engine' };
|
|
57
|
-
}
|
|
58
12
|
return { on: true, reason: 'default-on' };
|
|
59
13
|
}
|
|
60
14
|
export const DETACH_DURABLE_OFF_400_ANCHOR = 'x-detach-on-disconnect requires a durable run';
|
|
@@ -2,12 +2,15 @@ export type DeviceExecutorManagementReading = {
|
|
|
2
2
|
kind: 'unobserved';
|
|
3
3
|
} | {
|
|
4
4
|
kind: 'not_reported';
|
|
5
|
-
why: 'capability_absent'
|
|
5
|
+
why: 'capability_absent';
|
|
6
6
|
} | {
|
|
7
7
|
kind: 'lane_absent';
|
|
8
8
|
} | {
|
|
9
9
|
kind: 'present';
|
|
10
|
-
management:
|
|
10
|
+
management: 'present-true' | 'present-false' | 'absent';
|
|
11
|
+
protocolVersion?: number;
|
|
12
|
+
maxInflightPerDevice?: number;
|
|
13
|
+
wsPath?: string;
|
|
11
14
|
};
|
|
12
15
|
export declare function projectDeviceExecutorManagementCapability(caps: unknown): DeviceExecutorManagementReading | undefined;
|
|
13
16
|
export declare function noteEngineCapsForDeviceExecutorManagement(baseUrl: string, caps: unknown, opts?: {
|
|
@@ -15,6 +18,7 @@ export declare function noteEngineCapsForDeviceExecutorManagement(baseUrl: strin
|
|
|
15
18
|
}): void;
|
|
16
19
|
export declare function observedDeviceExecutorManagement(baseUrl?: string | undefined): DeviceExecutorManagementReading;
|
|
17
20
|
export declare function deviceManagementVerbsAvailable(reading: DeviceExecutorManagementReading): 'yes' | 'no' | 'unknown';
|
|
21
|
+
export declare function deviceLaneOpen(reading: DeviceExecutorManagementReading): 'yes' | 'no' | 'unknown';
|
|
18
22
|
export declare function deviceExecutorManagementDoctorDetail(reading: DeviceExecutorManagementReading): string;
|
|
19
23
|
export declare function forgetDeviceExecutorManagementReading(baseUrl: string | undefined): void;
|
|
20
24
|
export declare function __resetDeviceExecutorManagementReadingsForTests(): void;
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { engineWireTarget } from './engineWireTarget.js';
|
|
2
2
|
import { createEngineCapReader } from './engineCapReader.js';
|
|
3
|
+
import { capForDisplay } from './fleetTaskDesc.js';
|
|
4
|
+
function ownRead(o, key) {
|
|
5
|
+
return Object.hasOwn(o, key) ? o[key] : undefined;
|
|
6
|
+
}
|
|
3
7
|
export function projectDeviceExecutorManagementCapability(caps) {
|
|
4
8
|
if (caps === null || typeof caps !== 'object' || Array.isArray(caps))
|
|
5
9
|
return undefined;
|
|
@@ -14,14 +18,28 @@ export function projectDeviceExecutorManagementCapability(caps) {
|
|
|
14
18
|
if (d === null || typeof d !== 'object' || Array.isArray(d))
|
|
15
19
|
return undefined;
|
|
16
20
|
const o = d;
|
|
17
|
-
if (
|
|
18
|
-
return
|
|
19
|
-
const mgmt = o
|
|
21
|
+
if (ownRead(o, 'enabled') !== true)
|
|
22
|
+
return undefined;
|
|
23
|
+
const mgmt = ownRead(o, 'management');
|
|
24
|
+
let management;
|
|
20
25
|
if (mgmt === undefined)
|
|
21
|
-
|
|
22
|
-
if (
|
|
26
|
+
management = 'absent';
|
|
27
|
+
else if (mgmt === true)
|
|
28
|
+
management = 'present-true';
|
|
29
|
+
else if (mgmt === false)
|
|
30
|
+
management = 'present-false';
|
|
31
|
+
else
|
|
23
32
|
return undefined;
|
|
24
|
-
|
|
33
|
+
const pv = ownRead(o, 'protocolVersion');
|
|
34
|
+
const mi = ownRead(o, 'maxInflightPerDevice');
|
|
35
|
+
const ws = ownRead(o, 'wsPath');
|
|
36
|
+
return {
|
|
37
|
+
kind: 'present',
|
|
38
|
+
management,
|
|
39
|
+
...(typeof pv === 'number' && Number.isFinite(pv) ? { protocolVersion: pv } : {}),
|
|
40
|
+
...(typeof mi === 'number' && Number.isFinite(mi) && mi >= 0 ? { maxInflightPerDevice: mi } : {}),
|
|
41
|
+
...(typeof ws === 'string' && ws.length > 0 ? { wsPath: ws } : {}),
|
|
42
|
+
};
|
|
25
43
|
}
|
|
26
44
|
const reader = createEngineCapReader({
|
|
27
45
|
name: 'deviceExecutor.management',
|
|
@@ -35,26 +53,54 @@ export function observedDeviceExecutorManagement(baseUrl = engineWireTarget()?.b
|
|
|
35
53
|
return reader.observed(baseUrl);
|
|
36
54
|
}
|
|
37
55
|
export function deviceManagementVerbsAvailable(reading) {
|
|
56
|
+
if (reading.kind === 'present') {
|
|
57
|
+
if (reading.management === 'present-true')
|
|
58
|
+
return 'yes';
|
|
59
|
+
if (reading.management === 'present-false')
|
|
60
|
+
return 'no';
|
|
61
|
+
return 'unknown';
|
|
62
|
+
}
|
|
63
|
+
if (reading.kind === 'lane_absent')
|
|
64
|
+
return 'no';
|
|
65
|
+
return 'unknown';
|
|
66
|
+
}
|
|
67
|
+
export function deviceLaneOpen(reading) {
|
|
38
68
|
if (reading.kind === 'present')
|
|
39
|
-
return
|
|
69
|
+
return 'yes';
|
|
40
70
|
if (reading.kind === 'lane_absent')
|
|
41
71
|
return 'no';
|
|
42
72
|
return 'unknown';
|
|
43
73
|
}
|
|
74
|
+
const WS_PATH_DETAIL_MAX = 64;
|
|
75
|
+
function laneFactsSuffix(r) {
|
|
76
|
+
const parts = [];
|
|
77
|
+
if (r.protocolVersion !== undefined)
|
|
78
|
+
parts.push(`protocol ${r.protocolVersion}`);
|
|
79
|
+
if (r.maxInflightPerDevice !== undefined)
|
|
80
|
+
parts.push(`${r.maxInflightPerDevice} in flight per device`);
|
|
81
|
+
if (r.wsPath !== undefined)
|
|
82
|
+
parts.push(`ws path ${capForDisplay(r.wsPath, WS_PATH_DETAIL_MAX)}`);
|
|
83
|
+
return parts.length === 0 ? '' : ` (${parts.join(', ')})`;
|
|
84
|
+
}
|
|
44
85
|
export function deviceExecutorManagementDoctorDetail(reading) {
|
|
45
86
|
switch (reading.kind) {
|
|
46
87
|
case 'unobserved':
|
|
47
|
-
return 'device management face not observed — the engine reports it on /v1/capabilities (deviceExecutor.management); this process has no usable capabilities reading cached for it (none received, or the last one was
|
|
88
|
+
return 'device management face not observed — the engine reports it on /v1/capabilities (deviceExecutor.management); this process has no usable capabilities reading cached for it (none received, the last one was unreadable, or the last one was discarded when the engine connection was reset; this process cannot tell which)';
|
|
48
89
|
case 'not_reported':
|
|
49
|
-
return
|
|
50
|
-
? 'device management face not reported by this engine — the device lane is advertised but only newer engines say whether the /v1/devices management verbs exist; this does not say whether they exist, probe them directly'
|
|
51
|
-
: 'device executor capability not reported by this engine — only newer engines advertise the device lane at all; this does not say whether it exists';
|
|
90
|
+
return 'device executor capability not reported by this engine; this does not say whether a device lane exists';
|
|
52
91
|
case 'lane_absent':
|
|
53
92
|
return 'no device lane on this deployment — the /v1/devices management verbs are unavailable (capability.device_lane_required)';
|
|
54
|
-
case 'present':
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
93
|
+
case 'present': {
|
|
94
|
+
const facts = laneFactsSuffix(reading);
|
|
95
|
+
switch (reading.management) {
|
|
96
|
+
case 'present-true':
|
|
97
|
+
return `device management face on — the /v1/devices management verbs are available on this engine${facts}`;
|
|
98
|
+
case 'present-false':
|
|
99
|
+
return `device lane on but the /v1/devices management verbs are off on this deployment${facts}`;
|
|
100
|
+
case 'absent':
|
|
101
|
+
return `device lane on, but this engine does not report the /v1/devices management face; this does not say whether the management verbs exist, probe them directly${facts}`;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
58
104
|
}
|
|
59
105
|
}
|
|
60
106
|
export function forgetDeviceExecutorManagementReading(baseUrl) {
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { HealthResponse } from './types/engineState.js';
|
|
2
|
+
export interface EngineConfigApplyState {
|
|
3
|
+
readonly configTargetOrdinal: number;
|
|
4
|
+
readonly configAppliedOrdinal: number;
|
|
5
|
+
readonly configTargetVersion?: number;
|
|
6
|
+
readonly configAppliedVersion?: number;
|
|
7
|
+
readonly configApplyStaleMs?: number;
|
|
8
|
+
}
|
|
9
|
+
export declare function readEngineConfigApplyState(health: unknown): EngineConfigApplyState | null;
|
|
10
|
+
export type ConfigDriftVerdict = 'skip' | 'in-sync' | 'ask' | 'advance-baseline';
|
|
11
|
+
export interface ConfigDriftHealthView extends Pick<HealthResponse, 'configHash' | 'instanceId' | 'restartRequired'> {
|
|
12
|
+
configTargetOrdinal?: number | undefined;
|
|
13
|
+
configAppliedOrdinal?: number | undefined;
|
|
14
|
+
}
|
|
15
|
+
export interface ConfigDriftInput {
|
|
16
|
+
baselineConfigHash?: string | undefined;
|
|
17
|
+
baselineInstanceId?: string | undefined;
|
|
18
|
+
health?: ConfigDriftHealthView | undefined;
|
|
19
|
+
}
|
|
20
|
+
export declare function configDriftVerdict(input: ConfigDriftInput): ConfigDriftVerdict;
|