@sema-agent/client-core 0.98.0 → 0.99.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/CHANGELOG.md +199 -0
- package/README.md +35 -22
- package/dist/adapt/arms.js +61 -20
- package/dist/adapt/panelTasks.d.ts +1 -1
- package/dist/adapt/panelTasks.js +2 -2
- package/dist/adapter/activeRunSelfHeal.d.ts +4 -3
- package/dist/adapter/activeRunSelfHeal.js +162 -293
- package/dist/adapter/downstream/eventToSdkMessage.js +52 -4
- package/dist/adapter/runStream.js +52 -37
- package/dist/adapter/types.js +2 -1
- package/dist/agentSession/engineSessionBackgroundStop.js +16 -8
- package/dist/agentsWireCaps.d.ts +0 -3
- package/dist/agentsWireCaps.js +33 -24
- package/dist/cloudConfigWireCaps.d.ts +1 -1
- package/dist/cloudConfigWireCaps.js +26 -4
- package/dist/controlRouter.d.ts +4 -2
- package/dist/controlRouter.js +39 -51
- package/dist/coreValuePorts.d.ts +26 -1
- package/dist/coreValuePorts.js +10 -0
- package/dist/corruptSessionCopy.d.ts +2 -1
- package/dist/corruptSessionCopy.js +3 -3
- package/dist/declared/supportFloorDeclared.js +1 -1
- package/dist/detachWire.js +3 -2
- package/dist/devicesFace.d.ts +34 -0
- package/dist/devicesFace.js +90 -0
- package/dist/displayUntrusted.d.ts +1 -0
- package/dist/displayUntrusted.js +3 -0
- package/dist/engineAgentPanelStore.d.ts +7 -0
- package/dist/engineAgentPanelStore.js +14 -0
- package/dist/engineCapReader.d.ts +2 -1
- package/dist/engineCapReader.js +7 -5
- package/dist/engineCapsCache.d.ts +8 -0
- package/dist/engineCapsCache.js +59 -6
- package/dist/engineCapsChange.d.ts +2 -0
- package/dist/engineCapsChange.js +9 -0
- package/dist/engineErrorCodes.d.ts +2 -1
- package/dist/engineErrorCodes.js +2 -7
- package/dist/engineRowRef.js +3 -0
- package/dist/engineSessionMessages.d.ts +1 -0
- package/dist/engineSessionMessages.js +7 -1
- package/dist/engineTargetSeat.d.ts +27 -0
- package/dist/engineTargetSeat.js +199 -0
- package/dist/engineWireFor.js +3 -8
- package/dist/env/uiLanguage.d.ts +2 -1
- package/dist/env/uiLanguage.js +3 -2
- package/dist/eventLeg.d.ts +8 -0
- package/dist/eventLeg.js +61 -41
- package/dist/fileHistoryCaptureCapability.d.ts +2 -1
- package/dist/fileHistoryCaptureCapability.js +12 -18
- package/dist/fileHistoryLegNotice.d.ts +2 -1
- package/dist/fileHistoryLegNotice.js +3 -3
- package/dist/frameBinding.d.ts +3 -0
- package/dist/frameBinding.js +12 -0
- package/dist/gateOutcome.js +16 -2
- package/dist/gateVocabulary.d.ts +8 -7
- package/dist/gateVocabulary.js +71 -73
- package/dist/generated/engineFactTables.d.ts +17 -1
- package/dist/generated/engineFactTables.js +29 -0
- package/dist/generated/engineNoticeTables.js +9 -3
- package/dist/generated/settingsSchemaFns.d.ts +6 -0
- package/dist/generated/settingsSchemaFns.js +57 -0
- package/dist/generated/settingsSchemaHooksClassifier.d.ts +2 -0
- package/dist/generated/settingsSchemaHooksClassifier.js +254 -0
- package/dist/generated/settingsSchemaTables.d.ts +1 -0
- package/dist/generated/settingsSchemaTables.js +4 -0
- package/dist/generated/settingsSchemaTypes.d.ts +105 -0
- package/dist/generated/settingsSchemaTypes.js +1 -0
- package/dist/hitl/allowRuleShadow.d.ts +2 -1
- package/dist/hitl/allowRuleShadow.js +17 -14
- package/dist/hitl/approvalCardReasons.d.ts +3 -2
- package/dist/hitl/approvalCardReasons.js +27 -28
- package/dist/hitl/approvalHolds.d.ts +3 -0
- package/dist/hitl/approvalHolds.js +73 -29
- package/dist/hitl/askClassPair.d.ts +1 -1
- package/dist/hitl/askClassPair.js +16 -0
- package/dist/hitl/askGateWire.js +2 -1
- package/dist/hitl/askSettlementLine.d.ts +14 -4
- package/dist/hitl/askSettlementLine.js +67 -47
- package/dist/hitl/automaticAnswerVerdict.d.ts +2 -1
- package/dist/hitl/automaticAnswerVerdict.js +8 -8
- package/dist/hitl/crashConvergedNotice.d.ts +5 -4
- package/dist/hitl/crashConvergedNotice.js +28 -41
- package/dist/hitl/frameRouter.js +7 -8
- package/dist/hitl/hitlBridge.d.ts +1 -0
- package/dist/hitl/hitlBridge.js +3 -3
- package/dist/hitl/persistedRulesWire.d.ts +6 -5
- package/dist/hitl/persistedRulesWire.js +55 -73
- package/dist/hitl/planReviewWire.d.ts +5 -0
- package/dist/hitl/planReviewWire.js +8 -0
- package/dist/hitl/sessionPolicyDeliverable.d.ts +2 -0
- package/dist/hitl/sessionPolicyDeliverable.js +46 -3
- package/dist/hitl/sessionPolicyWire.d.ts +2 -1
- package/dist/hitl/sessionPolicyWire.js +23 -24
- package/dist/hitl/suspendedReopen.d.ts +2 -1
- package/dist/hitl/suspendedReopen.js +7 -10
- package/dist/hitl/toolApprovalWire.d.ts +17 -5
- package/dist/hitl/toolApprovalWire.js +79 -40
- package/dist/hooksWireCaps.js +145 -56
- package/dist/host.d.ts +21 -0
- package/dist/hostTurnSettings.d.ts +71 -0
- package/dist/hostTurnSettings.js +291 -0
- package/dist/humanTurn.d.ts +14 -1
- package/dist/humanTurn.js +100 -12
- package/dist/humanTurnRead.d.ts +2 -0
- package/dist/humanTurnRead.js +22 -1
- package/dist/i18n/messages.en.d.ts +582 -0
- package/dist/i18n/messages.en.js +582 -0
- package/dist/i18n/messages.zh.js +718 -1
- package/dist/index.d.ts +29 -13
- package/dist/index.js +18 -9
- package/dist/inheritEnvCapability.d.ts +3 -2
- package/dist/inheritEnvCapability.js +3 -3
- package/dist/inheritEnvWire.d.ts +3 -2
- package/dist/inheritEnvWire.js +12 -14
- package/dist/interactiveHalt.js +17 -6
- package/dist/liveModelCatalog.d.ts +2 -1
- package/dist/liveModelCatalog.js +14 -8
- package/dist/mcpPanel.d.ts +10 -1
- package/dist/mcpPanel.js +40 -13
- package/dist/mcpProbeCapability.d.ts +2 -1
- package/dist/mcpProbeCapability.js +7 -11
- package/dist/mcpProbeWire.d.ts +3 -1
- package/dist/mcpProbeWire.js +5 -0
- package/dist/mcpWireCaps.d.ts +34 -0
- package/dist/mcpWireCaps.js +117 -17
- package/dist/memoryEntriesWire.js +5 -10
- package/dist/model/onboardJudgement.d.ts +93 -0
- package/dist/model/onboardJudgement.js +415 -0
- package/dist/model/tierVocabulary.d.ts +2 -0
- package/dist/model/tierVocabulary.js +17 -5
- package/dist/modelCapabilityProbe.d.ts +64 -0
- package/dist/modelCapabilityProbe.js +600 -0
- package/dist/modelIdentityResolvability.d.ts +3 -0
- package/dist/modelIdentityResolvability.js +26 -17
- package/dist/ownKey.d.ts +7 -0
- package/dist/ownKey.js +34 -0
- package/dist/panelReduce.d.ts +6 -1
- package/dist/panelReduce.js +50 -3
- package/dist/permissionRuleIssue.js +2 -0
- package/dist/permissionRulesWriteCapability.d.ts +2 -1
- package/dist/permissionRulesWriteCapability.js +8 -6
- package/dist/pluginHooksWire.d.ts +46 -3
- package/dist/pluginHooksWire.js +217 -11
- package/dist/printModelStatus.d.ts +63 -0
- package/dist/printModelStatus.js +155 -0
- package/dist/request/taskRequest.d.ts +11 -5
- package/dist/request/taskRequest.js +112 -16
- package/dist/resumeRefusalCopy.d.ts +12 -9
- package/dist/resumeRefusalCopy.js +70 -143
- package/dist/retryStatus.d.ts +37 -0
- package/dist/retryStatus.js +79 -0
- package/dist/scenarioRefusal.d.ts +9 -0
- package/dist/scenarioRefusal.js +111 -0
- package/dist/seam.d.ts +25 -1
- package/dist/seam.js +10 -1
- package/dist/seatContract.d.ts +260 -10
- package/dist/seatContract.js +692 -19
- package/dist/selfOrchestrationDenial.js +7 -19
- package/dist/sessionIdSegment.d.ts +6 -0
- package/dist/sessionIdSegment.js +24 -0
- package/dist/sessionMemoryStatus.js +6 -11
- package/dist/sessionPolicyCapability.d.ts +2 -1
- package/dist/sessionPolicyCapability.js +8 -6
- package/dist/settingsHooksSalvage.d.ts +44 -0
- package/dist/settingsHooksSalvage.js +211 -0
- package/dist/skillToolListsCapability.d.ts +2 -1
- package/dist/skillToolListsCapability.js +8 -6
- package/dist/sseIdleTriage.js +3 -2
- package/dist/subagent/engineSubagentResume.js +15 -9
- package/dist/subagentContentStore.d.ts +3 -0
- package/dist/subagentContentStore.js +22 -0
- package/dist/toolHistoryMismatch.js +3 -2
- package/dist/toolRoster.d.ts +3 -2
- package/dist/toolRoster.js +21 -20
- package/dist/turnFailurePresentation.d.ts +12 -1
- package/dist/turnFailurePresentation.js +212 -15
- package/dist/usageAnalytics.js +6 -11
- package/dist/userAttachmentEnvelope.d.ts +1 -0
- package/dist/userAttachmentEnvelope.js +37 -7
- package/dist/userAttachmentSeat.d.ts +21 -0
- package/dist/userAttachmentSeat.js +75 -0
- package/dist/userInvokedSkillsCapability.d.ts +11 -1
- package/dist/userInvokedSkillsCapability.js +31 -7
- package/dist/wireErrorTriage.d.ts +7 -0
- package/dist/wireErrorTriage.js +23 -1
- package/dist/wireFailureShape.js +2 -1
- package/dist/wireRefusalCopy.d.ts +13 -1
- package/dist/wireRefusalCopy.js +24 -28
- package/dist/workflowsJournalCapability.d.ts +2 -1
- package/dist/workflowsJournalCapability.js +8 -6
- package/docs/INTEGRATION-CLIENTS.md +542 -30
- package/package.json +5 -5
package/dist/seatContract.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { PERMISSION_MODE_WORDS, REASONING_EFFORT_WORDS } from "./taskRequestWords.js";
|
|
2
2
|
import { liveDefaultModelCopy, liveModelRowCopy } from "./model/liveCatalogShape.js";
|
|
3
3
|
import { REWIND_MODES } from "./rewindWireCaps.js";
|
|
4
|
+
import { SETTINGS_MODEL_API_WORDS } from "./generated/settingsSchemaTables.js";
|
|
5
|
+
import { PROBE_VERDICTS } from "./modelCapabilityProbe.js";
|
|
4
6
|
import { guardedRead, ownDataField, ownDataRefusalKeyOf, ownSendableField, readOwnDataValue } from "./ownKey.js";
|
|
7
|
+
import { MCP_LIVENESS_STATES } from "./mcpLiveness.js";
|
|
5
8
|
const bad = (reason, field) => field === undefined ? { reason } : { reason, field };
|
|
6
9
|
const nested = (prefix, verdict) => {
|
|
7
10
|
const path = verdict.field === undefined
|
|
@@ -89,6 +92,124 @@ const seatCheckAt = (fn) => (v, field) => {
|
|
|
89
92
|
return key !== undefined ? bad(NOT_PLAIN_DATA, `${field}.${key}`) : bad("payload could not be read", field);
|
|
90
93
|
}
|
|
91
94
|
};
|
|
95
|
+
const pathAt = (path, key) => (path === "" ? key : `${path}.${key}`);
|
|
96
|
+
const reqF = (rule) => ({ opt: false, rule });
|
|
97
|
+
const optF = (rule) => ({ opt: true, rule });
|
|
98
|
+
const ruleOf = (label, pred) => ({
|
|
99
|
+
label,
|
|
100
|
+
test: (v, path) => (pred(v) ? true : bad(`bad value (${label})`, path === "" ? undefined : path)),
|
|
101
|
+
});
|
|
102
|
+
function shapeVerdict(spec, v, path, disc) {
|
|
103
|
+
if (!isPlainRecord(v))
|
|
104
|
+
return bad("not object", path === "" ? undefined : path);
|
|
105
|
+
for (const k of sendableKeysOf(v)) {
|
|
106
|
+
if (k !== disc && !Object.hasOwn(spec, k))
|
|
107
|
+
return bad("unknown key", pathAt(path, k));
|
|
108
|
+
}
|
|
109
|
+
for (const k of Object.keys(spec)) {
|
|
110
|
+
const s = spec[k];
|
|
111
|
+
const val = own(v, k);
|
|
112
|
+
if (isAbsent(val)) {
|
|
113
|
+
if (!s.opt)
|
|
114
|
+
return bad("missing key", pathAt(path, k));
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
const verdict = s.rule.test(val, pathAt(path, k));
|
|
118
|
+
if (verdict !== true)
|
|
119
|
+
return verdict;
|
|
120
|
+
}
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
const shapeRule = (label, spec) => ({ label, test: (v, path) => shapeVerdict(spec, v, path) });
|
|
124
|
+
const armsRule = (label, disc, arms) => ({
|
|
125
|
+
label,
|
|
126
|
+
test: (v, path) => {
|
|
127
|
+
if (!isPlainRecord(v))
|
|
128
|
+
return bad("not object", path === "" ? undefined : path);
|
|
129
|
+
const d = own(v, disc);
|
|
130
|
+
if (typeof d !== "string" || !Object.hasOwn(arms, d))
|
|
131
|
+
return bad("unknown arm", pathAt(path, disc));
|
|
132
|
+
return shapeVerdict(arms[d], v, path, disc);
|
|
133
|
+
},
|
|
134
|
+
});
|
|
135
|
+
const isArraySlotKey = (k, n) => k === "length" || (/^(0|[1-9][0-9]*)$/.test(k) && Number(k) < n);
|
|
136
|
+
const arrayRule = (item, nonEmpty = false) => ({
|
|
137
|
+
label: `${item.label}[]`,
|
|
138
|
+
test: (v, path) => {
|
|
139
|
+
if (!Array.isArray(v))
|
|
140
|
+
return bad(`bad value (${item.label}[])`, path === "" ? undefined : path);
|
|
141
|
+
const n = ownDataField(v, "length");
|
|
142
|
+
for (const k of Reflect.ownKeys(v)) {
|
|
143
|
+
if (typeof k === "string" && !isArraySlotKey(k, typeof n === "number" ? n : 0))
|
|
144
|
+
return bad("unknown key", pathAt(path, k));
|
|
145
|
+
}
|
|
146
|
+
const rows = ownItems(v);
|
|
147
|
+
if (nonEmpty && rows.length === 0)
|
|
148
|
+
return bad(`bad value (${item.label}[])`, path === "" ? undefined : path);
|
|
149
|
+
for (let i = 0; i < rows.length; i += 1) {
|
|
150
|
+
const verdict = item.test(rows[i], `${path}[${i}]`);
|
|
151
|
+
if (verdict !== true)
|
|
152
|
+
return verdict;
|
|
153
|
+
}
|
|
154
|
+
return true;
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
const oneOfRule = (label, words) => ruleOf(label, (v) => typeof v === "string" && words.includes(v));
|
|
158
|
+
const R_STR = ruleOf("string", (v) => typeof v === "string");
|
|
159
|
+
const R_NONEMPTY = ruleOf("non-empty string", (v) => typeof v === "string" && v.length > 0);
|
|
160
|
+
const R_BOOL = ruleOf("boolean", (v) => typeof v === "boolean");
|
|
161
|
+
const R_TRUE = ruleOf("true", (v) => v === true);
|
|
162
|
+
const R_NUM = ruleOf("finite number", (v) => typeof v === "number" && Number.isFinite(v));
|
|
163
|
+
const R_INT0 = ruleOf("non-negative integer", (v) => typeof v === "number" && Number.isSafeInteger(v) && v >= 0);
|
|
164
|
+
const R_INT1 = ruleOf("positive integer", (v) => typeof v === "number" && Number.isSafeInteger(v) && v > 0);
|
|
165
|
+
const keyWords = (k) => k
|
|
166
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1 $2")
|
|
167
|
+
.toLowerCase()
|
|
168
|
+
.split(/[^a-z0-9]+/)
|
|
169
|
+
.filter((w) => w.length > 0);
|
|
170
|
+
const SECRET_KEY_WORDS = new Set(["token", "secret", "password", "passwd", "authorization", "bearer", "sealed"]);
|
|
171
|
+
const SECRET_KEY_PAIRS = new Set(["api key", "device code", "access key", "private key"]);
|
|
172
|
+
const isSecretKeyName = (k) => {
|
|
173
|
+
const words = keyWords(k);
|
|
174
|
+
for (let i = 0; i < words.length; i += 1) {
|
|
175
|
+
if (SECRET_KEY_WORDS.has(words[i]))
|
|
176
|
+
return true;
|
|
177
|
+
if (i + 1 < words.length && SECRET_KEY_PAIRS.has(`${words[i]} ${words[i + 1]}`))
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
return false;
|
|
181
|
+
};
|
|
182
|
+
const firstSecretKeyPath = (root, allow) => {
|
|
183
|
+
const seen = new Set();
|
|
184
|
+
const stack = [[root, ""]];
|
|
185
|
+
while (stack.length > 0) {
|
|
186
|
+
const [v, path] = stack.pop();
|
|
187
|
+
if (typeof v !== "object" || v === null || seen.has(v))
|
|
188
|
+
continue;
|
|
189
|
+
seen.add(v);
|
|
190
|
+
const isArr = Array.isArray(v);
|
|
191
|
+
for (const k of Reflect.ownKeys(v)) {
|
|
192
|
+
if (typeof k !== "string" || (isArr && k === "length"))
|
|
193
|
+
continue;
|
|
194
|
+
const d = Reflect.getOwnPropertyDescriptor(v, k);
|
|
195
|
+
if (d === undefined || !Object.hasOwn(d, "value"))
|
|
196
|
+
continue;
|
|
197
|
+
const at = isArr && /^[0-9]+$/.test(k) ? `${path}[${k}]` : pathAt(path, k);
|
|
198
|
+
if (isSecretKeyName(k) && !allow.has(at))
|
|
199
|
+
return at;
|
|
200
|
+
stack.push([d.value, at]);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return undefined;
|
|
204
|
+
};
|
|
205
|
+
const NO_SECRET_ALLOW = new Set();
|
|
206
|
+
const seatShapeCheck = (rule, allow = NO_SECRET_ALLOW) => seatCheck((v) => {
|
|
207
|
+
const verdict = rule.test(v, "");
|
|
208
|
+
if (verdict !== true)
|
|
209
|
+
return verdict;
|
|
210
|
+
const secret = firstSecretKeyPath(v, allow);
|
|
211
|
+
return secret === undefined ? true : bad("secret key", secret);
|
|
212
|
+
});
|
|
92
213
|
export const TOOL_PERMISSION_REQUEST_ID_DOMAINS = Object.freeze([
|
|
93
214
|
"live:",
|
|
94
215
|
"durable:",
|
|
@@ -127,6 +248,7 @@ const SEAT_EVENT_TYPE_TUPLE = [
|
|
|
127
248
|
"chrome_event",
|
|
128
249
|
"error",
|
|
129
250
|
"tool_permission_resolved",
|
|
251
|
+
"subagent_content",
|
|
130
252
|
];
|
|
131
253
|
export const SEAT_EVENT_TYPES = Object.freeze(SEAT_EVENT_TYPE_TUPLE);
|
|
132
254
|
const CHROME_EVENT_KIND_TUPLE = [
|
|
@@ -205,7 +327,7 @@ export function readSeatStreamDelta(message) {
|
|
|
205
327
|
return Object.freeze({ kind: "malformed" });
|
|
206
328
|
}
|
|
207
329
|
}
|
|
208
|
-
export const SEAT_CAPABILITY_NAMES = Object.freeze(["pickFolder", "rewind", "recents", "patchSession"]);
|
|
330
|
+
export const SEAT_CAPABILITY_NAMES = Object.freeze(["pickFolder", "rewind", "recents", "patchSession", "devices", "engineTarget", "onboard"]);
|
|
209
331
|
const notReported = () => Object.freeze({ kind: "not_reported" });
|
|
210
332
|
const malformedReading = () => Object.freeze({ kind: "malformed" });
|
|
211
333
|
const reported = (available) => Object.freeze({ kind: "reported", available });
|
|
@@ -277,6 +399,9 @@ const SEAT_CAPABILITY_PHRASES = Object.freeze({
|
|
|
277
399
|
pickFolder: Object.freeze({ action: "Opening a folder", ability: "show a folder picker", support: "folder picker support" }),
|
|
278
400
|
rewind: Object.freeze({ action: "Rewinding to an earlier message", ability: "rewind this session", support: "rewind support" }),
|
|
279
401
|
recents: Object.freeze({ action: "Remembering recent folders", ability: "remember recent folders", support: "recent folders support" }), patchSession: Object.freeze({ action: "Renaming or pinning a conversation", ability: "rename or pin conversations", support: "rename and pin support" }),
|
|
402
|
+
devices: Object.freeze({ action: "Managing devices", ability: "manage devices", support: "device support" }),
|
|
403
|
+
engineTarget: Object.freeze({ action: "Switching engines", ability: "switch engines", support: "engine-switching support" }),
|
|
404
|
+
onboard: Object.freeze({ action: "Model setup", ability: "add models", support: "model-setup support" }),
|
|
280
405
|
});
|
|
281
406
|
export function seatCapabilityUnavailableDetail(name, reading) {
|
|
282
407
|
const phrase = Object.hasOwn(SEAT_CAPABILITY_PHRASES, name)
|
|
@@ -405,6 +530,378 @@ export const ATTACHMENT_UPLOAD_REQUEST_KEYS = ["name", "mimeType", "bytes"];
|
|
|
405
530
|
export const SESSION_ROW_PATCH_REQUEST_KEYS = Object.freeze(["sessionId", "title", "pinned"]);
|
|
406
531
|
export const SESSION_SEARCH_RESULT_KEYS = ["sessionId", "title", "matches"];
|
|
407
532
|
export const GET_TRANSCRIPT_RESULT_KEYS = ["sessionId", "messages"];
|
|
533
|
+
const DEVICE_REFUSED_SPEC = { status: reqF(R_INT0), errorCode: optF(R_STR), message: optF(R_STR) };
|
|
534
|
+
const DEVICE_LANE_ABSENT_SPEC = { runStoreOnly: optF(R_TRUE) };
|
|
535
|
+
const DEVICE_TRANSPORT_SPEC = { detail: optF(R_STR) };
|
|
536
|
+
const DEVICE_UNREADABLE_SPEC = { why: reqF(R_STR) };
|
|
537
|
+
const DEVICE_UNCONFIRMED_SPEC = {
|
|
538
|
+
why: reqF(oneOfRule("unconfirmed why", ["accepted-unreadable", "transport", "server-error"])),
|
|
539
|
+
detail: optF(R_STR),
|
|
540
|
+
mayStillBeRunning: reqF(R_BOOL),
|
|
541
|
+
};
|
|
542
|
+
const DEVICE_RATE_LIMITED_SPEC = { retryAfterSec: optF(R_NUM) };
|
|
543
|
+
const DEVICE_ROSTER_ROW = shapeRule("device row", {
|
|
544
|
+
deviceId: reqF(R_NONEMPTY),
|
|
545
|
+
name: optF(R_STR),
|
|
546
|
+
status: reqF(oneOfRule("device status", ["online", "offline", "unknown"])),
|
|
547
|
+
lastSeenAt: optF(R_STR),
|
|
548
|
+
});
|
|
549
|
+
const DEVICE_BINDING = shapeRule("device binding", {
|
|
550
|
+
deviceId: reqF(R_NONEMPTY),
|
|
551
|
+
rev: reqF(R_INT0),
|
|
552
|
+
boundAt: optF(R_STR),
|
|
553
|
+
});
|
|
554
|
+
const checkDeviceListOutcome = seatShapeCheck(armsRule("listDevices outcome", "kind", {
|
|
555
|
+
ok: { devices: reqF(arrayRule(DEVICE_ROSTER_ROW)), dropped: reqF(R_INT0) },
|
|
556
|
+
unreadable: DEVICE_UNREADABLE_SPEC,
|
|
557
|
+
"lane-absent": DEVICE_LANE_ABSENT_SPEC,
|
|
558
|
+
refused: DEVICE_REFUSED_SPEC,
|
|
559
|
+
transport: DEVICE_TRANSPORT_SPEC,
|
|
560
|
+
unarmed: {},
|
|
561
|
+
}));
|
|
562
|
+
const checkDeviceSessionBindingOutcome = seatShapeCheck(armsRule("readSessionBinding outcome", "kind", {
|
|
563
|
+
ok: { rootSessionId: reqF(R_NONEMPTY), boundDevice: reqF(DEVICE_BINDING) },
|
|
564
|
+
"not-found": {},
|
|
565
|
+
unreadable: DEVICE_UNREADABLE_SPEC,
|
|
566
|
+
"lane-absent": DEVICE_LANE_ABSENT_SPEC,
|
|
567
|
+
refused: DEVICE_REFUSED_SPEC,
|
|
568
|
+
transport: DEVICE_TRANSPORT_SPEC,
|
|
569
|
+
unarmed: {},
|
|
570
|
+
}));
|
|
571
|
+
const checkDeviceRebindOutcome = seatShapeCheck(armsRule("rebindSession outcome", "kind", {
|
|
572
|
+
ok: { deviceId: reqF(R_NONEMPTY), rev: reqF(R_INT0), workspaceCarryover: optF(oneOfRule("carryover", ["none"])) },
|
|
573
|
+
"active-run": { activeTaskId: optF(R_STR) },
|
|
574
|
+
"rev-conflict": { currentRev: optF(R_INT0) },
|
|
575
|
+
"not-found": {},
|
|
576
|
+
unconfirmed: DEVICE_UNCONFIRMED_SPEC,
|
|
577
|
+
"lane-absent": DEVICE_LANE_ABSENT_SPEC,
|
|
578
|
+
refused: DEVICE_REFUSED_SPEC,
|
|
579
|
+
unarmed: {},
|
|
580
|
+
}));
|
|
581
|
+
const ENROLL_TOKEN_ALLOW = new Set(["token"]);
|
|
582
|
+
const checkDeviceEnrollTokenOutcome = seatShapeCheck(armsRule("issueEnrollToken outcome", "kind", {
|
|
583
|
+
ok: { token: reqF(R_NONEMPTY), expiresAt: optF(R_STR), ttlSec: optF(R_INT1) },
|
|
584
|
+
"rate-limited": DEVICE_RATE_LIMITED_SPEC,
|
|
585
|
+
unreadable: DEVICE_UNREADABLE_SPEC,
|
|
586
|
+
"lane-absent": DEVICE_LANE_ABSENT_SPEC,
|
|
587
|
+
refused: DEVICE_REFUSED_SPEC,
|
|
588
|
+
transport: DEVICE_TRANSPORT_SPEC,
|
|
589
|
+
unarmed: {},
|
|
590
|
+
}), ENROLL_TOKEN_ALLOW);
|
|
591
|
+
const checkDeviceRevokeOutcome = seatShapeCheck(armsRule("revokeDevice outcome", "kind", {
|
|
592
|
+
ok: { deviceId: reqF(R_NONEMPTY), revokedAt: optF(R_STR) },
|
|
593
|
+
"not-found": {},
|
|
594
|
+
unconfirmed: DEVICE_UNCONFIRMED_SPEC,
|
|
595
|
+
"lane-absent": DEVICE_LANE_ABSENT_SPEC,
|
|
596
|
+
refused: DEVICE_REFUSED_SPEC,
|
|
597
|
+
unarmed: {},
|
|
598
|
+
}));
|
|
599
|
+
export const checkSeatDeviceRebindRequest = seatShapeCheck(shapeRule("rebindSession request", {
|
|
600
|
+
sessionId: reqF(R_NONEMPTY),
|
|
601
|
+
toDeviceId: reqF(R_NONEMPTY),
|
|
602
|
+
expectedRev: reqF(R_INT0),
|
|
603
|
+
fromDeviceId: reqF(R_NONEMPTY),
|
|
604
|
+
}));
|
|
605
|
+
export const checkSeatDeviceRevokeRequest = seatShapeCheck(shapeRule("revokeDevice request", { deviceId: reqF(R_NONEMPTY), reason: optF(R_STR) }));
|
|
606
|
+
export const ENGINE_TARGET_REFUSALS = Object.freeze([
|
|
607
|
+
"busy",
|
|
608
|
+
"switching",
|
|
609
|
+
"not_configured",
|
|
610
|
+
"not_signed_in",
|
|
611
|
+
"probe_failed",
|
|
612
|
+
"org_policy",
|
|
613
|
+
"url_refused",
|
|
614
|
+
"login_failed",
|
|
615
|
+
"storage_unavailable",
|
|
616
|
+
"no_local_runtime",
|
|
617
|
+
"input",
|
|
618
|
+
]);
|
|
619
|
+
export const CLOUD_LOGIN_FAILURES = Object.freeze([
|
|
620
|
+
"access_denied",
|
|
621
|
+
"expired_token",
|
|
622
|
+
"invalid_grant",
|
|
623
|
+
"cancelled",
|
|
624
|
+
"transport",
|
|
625
|
+
"refused",
|
|
626
|
+
"no_tokens",
|
|
627
|
+
"other",
|
|
628
|
+
]);
|
|
629
|
+
const R_ISO = R_NONEMPTY;
|
|
630
|
+
const R_LOGIN_FAILURE = oneOfRule("login failure", CLOUD_LOGIN_FAILURES);
|
|
631
|
+
const R_DISPLAY_URL = ruleOf("display url", (v) => {
|
|
632
|
+
if (typeof v !== "string" || v.length === 0)
|
|
633
|
+
return false;
|
|
634
|
+
let u;
|
|
635
|
+
try {
|
|
636
|
+
u = new URL(v);
|
|
637
|
+
}
|
|
638
|
+
catch {
|
|
639
|
+
return false;
|
|
640
|
+
}
|
|
641
|
+
return (u.protocol === "https:" || u.protocol === "http:") && u.username === "" && u.password === "" && u.search === "" && u.hash === "";
|
|
642
|
+
});
|
|
643
|
+
const R_VERIFICATION_URI_COMPLETE = ruleOf("verification uri", (v) => {
|
|
644
|
+
if (typeof v !== "string" || v.length === 0)
|
|
645
|
+
return false;
|
|
646
|
+
let text = v;
|
|
647
|
+
for (let i = 0; i < 4; i += 1) {
|
|
648
|
+
let next;
|
|
649
|
+
try {
|
|
650
|
+
next = decodeURIComponent(text);
|
|
651
|
+
}
|
|
652
|
+
catch {
|
|
653
|
+
return false;
|
|
654
|
+
}
|
|
655
|
+
if (next === text)
|
|
656
|
+
break;
|
|
657
|
+
text = next;
|
|
658
|
+
}
|
|
659
|
+
return !/device[_-]?code/i.test(text);
|
|
660
|
+
});
|
|
661
|
+
const ENGINE_PROBE_READING = shapeRule("engine probe", {
|
|
662
|
+
ok: reqF(R_BOOL),
|
|
663
|
+
version: optF(R_STR),
|
|
664
|
+
detail: optF(R_STR),
|
|
665
|
+
at: reqF(R_ISO),
|
|
666
|
+
});
|
|
667
|
+
const SEAT_LOCAL_MCP_ROW = shapeRule("mcp row", {
|
|
668
|
+
name: reqF(R_NONEMPTY),
|
|
669
|
+
status: reqF(R_STR),
|
|
670
|
+
toolCount: optF(R_INT0),
|
|
671
|
+
liveness: optF(R_STR),
|
|
672
|
+
errorCode: optF(R_STR),
|
|
673
|
+
forcedAsk: optF(arrayRule(R_NONEMPTY, true)),
|
|
674
|
+
});
|
|
675
|
+
const SEAT_LOCAL_MCP_READING = armsRule("mcp reading", "status", {
|
|
676
|
+
listed: { servers: reqF(arrayRule(SEAT_LOCAL_MCP_ROW)), readAt: reqF(R_ISO), restartRequired: optF(R_TRUE) },
|
|
677
|
+
unreadable: { cause: reqF(R_NONEMPTY), detail: optF(R_STR), readAt: reqF(R_ISO), restartRequired: optF(R_TRUE) },
|
|
678
|
+
});
|
|
679
|
+
const ENGINE_TARGET_CLOUD = shapeRule("cloud", {
|
|
680
|
+
configured: reqF(R_BOOL),
|
|
681
|
+
url: optF(R_DISPLAY_URL),
|
|
682
|
+
label: optF(R_STR),
|
|
683
|
+
auth: optF(armsRule("cloud auth", "kind", {
|
|
684
|
+
registry: { registryUrl: reqF(R_DISPLAY_URL), principal: optF(R_STR), role: optF(R_STR), scope: optF(R_STR) },
|
|
685
|
+
token: {},
|
|
686
|
+
})),
|
|
687
|
+
login: optF(armsRule("cloud login", "state", {
|
|
688
|
+
pending: {
|
|
689
|
+
registryUrl: reqF(R_DISPLAY_URL),
|
|
690
|
+
userCode: reqF(R_NONEMPTY),
|
|
691
|
+
verificationUri: reqF(R_DISPLAY_URL),
|
|
692
|
+
verificationUriComplete: optF(R_VERIFICATION_URI_COMPLETE),
|
|
693
|
+
expiresAt: reqF(R_ISO),
|
|
694
|
+
},
|
|
695
|
+
failed: { failure: reqF(R_LOGIN_FAILURE), status: optF(R_INT0), at: reqF(R_ISO) },
|
|
696
|
+
})),
|
|
697
|
+
lastProbe: optF(ENGINE_PROBE_READING),
|
|
698
|
+
authError: optF(shapeRule("auth error", {
|
|
699
|
+
failure: reqF(R_LOGIN_FAILURE),
|
|
700
|
+
status: optF(R_INT0),
|
|
701
|
+
at: reqF(R_ISO),
|
|
702
|
+
})),
|
|
703
|
+
orgEngine: optF(shapeRule("org engine", { url: reqF(R_DISPLAY_URL), required: reqF(R_BOOL) })),
|
|
704
|
+
});
|
|
705
|
+
const ENGINE_TARGET_LOCAL = shapeRule("local", {
|
|
706
|
+
lastBootError: optF(R_STR),
|
|
707
|
+
mcp: optF(SEAT_LOCAL_MCP_READING),
|
|
708
|
+
});
|
|
709
|
+
const ENGINE_TARGET_STATE = shapeRule("engine target", {
|
|
710
|
+
mode: reqF(oneOfRule("engine mode", ["local", "cloud"])),
|
|
711
|
+
generation: reqF(R_INT0),
|
|
712
|
+
cloud: reqF(ENGINE_TARGET_CLOUD),
|
|
713
|
+
local: reqF(ENGINE_TARGET_LOCAL),
|
|
714
|
+
});
|
|
715
|
+
const checkEngineTargetState = seatShapeCheck(ENGINE_TARGET_STATE);
|
|
716
|
+
const okArmsRule = (label, okSpec, refusedSpec) => ({
|
|
717
|
+
label,
|
|
718
|
+
test: (v, path) => {
|
|
719
|
+
if (!isPlainRecord(v))
|
|
720
|
+
return bad("not object", path === "" ? undefined : path);
|
|
721
|
+
const ok = own(v, "ok");
|
|
722
|
+
if (ok === true)
|
|
723
|
+
return shapeVerdict(okSpec, v, path, "ok");
|
|
724
|
+
if (ok === false)
|
|
725
|
+
return shapeVerdict(refusedSpec, v, path, "ok");
|
|
726
|
+
return bad("unknown arm", pathAt(path, "ok"));
|
|
727
|
+
},
|
|
728
|
+
});
|
|
729
|
+
const ENGINE_TARGET_REFUSED_SPEC = {
|
|
730
|
+
refusal: reqF(oneOfRule("engineTarget refusal", ENGINE_TARGET_REFUSALS)),
|
|
731
|
+
failure: optF(R_LOGIN_FAILURE),
|
|
732
|
+
status: optF(R_INT0),
|
|
733
|
+
detail: optF(R_STR),
|
|
734
|
+
};
|
|
735
|
+
const checkEngineTargetResult = seatShapeCheck(okArmsRule("engineTarget result", {}, ENGINE_TARGET_REFUSED_SPEC));
|
|
736
|
+
const checkCancelCloudLogin = seatShapeCheck(shapeRule("cancel ack", { ok: reqF(R_BOOL) }));
|
|
737
|
+
const checkCloudLoginStart = seatShapeCheck(okArmsRule("startCloudLogin result", {
|
|
738
|
+
verificationUri: reqF(R_DISPLAY_URL),
|
|
739
|
+
verificationUriComplete: optF(R_VERIFICATION_URI_COMPLETE),
|
|
740
|
+
userCode: reqF(R_NONEMPTY),
|
|
741
|
+
expiresAt: reqF(R_ISO),
|
|
742
|
+
}, ENGINE_TARGET_REFUSED_SPEC));
|
|
743
|
+
const checkCloudConnectResult = seatShapeCheck(okArmsRule("connect result", {
|
|
744
|
+
probe: reqF(shapeRule("probe", { version: optF(R_STR) })),
|
|
745
|
+
}, ENGINE_TARGET_REFUSED_SPEC));
|
|
746
|
+
export const checkCloudLoginRequest = seatShapeCheck(shapeRule("startCloudLogin request", { registryUrl: reqF(R_DISPLAY_URL) }));
|
|
747
|
+
export const checkCloudEngineConnectRequest = seatShapeCheck(shapeRule("connectCloudEngine request", { url: reqF(R_DISPLAY_URL) }));
|
|
748
|
+
const CONFIGURE_TOKEN_ALLOW = new Set(["token"]);
|
|
749
|
+
export const checkCloudEngineConfigureRequest = seatShapeCheck(shapeRule("configureCloudEngine request", { url: reqF(R_DISPLAY_URL), token: reqF(R_NONEMPTY) }), CONFIGURE_TOKEN_ALLOW);
|
|
750
|
+
export const ONBOARD_REFUSALS = Object.freeze([
|
|
751
|
+
"input",
|
|
752
|
+
"probe_failed",
|
|
753
|
+
"probe_unverified",
|
|
754
|
+
"credential_unpaired",
|
|
755
|
+
"catalog_unreadable",
|
|
756
|
+
"write_conflict",
|
|
757
|
+
"write_failed",
|
|
758
|
+
"engine_is_remote",
|
|
759
|
+
"env_catalog_present",
|
|
760
|
+
]);
|
|
761
|
+
const R_API_WORD = oneOfRule("api", SETTINGS_MODEL_API_WORDS);
|
|
762
|
+
const ONBOARD_PROBE_RESULT = shapeRule("probe result", {
|
|
763
|
+
verdict: reqF(oneOfRule("probe verdict", PROBE_VERDICTS)),
|
|
764
|
+
detail: reqF(R_STR),
|
|
765
|
+
thinking: optF(R_NONEMPTY),
|
|
766
|
+
});
|
|
767
|
+
const ENGINE_UP_SPEC = { model: reqF(ruleOf("string|null", (x) => x === null || typeof x === "string")) };
|
|
768
|
+
const ENGINE_NOT_UP_SPEC = { reason: reqF(R_STR) };
|
|
769
|
+
const ENGINE_RESTART_OUTCOME = armsRule("engine restart", "state", {
|
|
770
|
+
started: ENGINE_UP_SPEC,
|
|
771
|
+
restarted: ENGINE_UP_SPEC,
|
|
772
|
+
pending: ENGINE_NOT_UP_SPEC,
|
|
773
|
+
failed: ENGINE_NOT_UP_SPEC,
|
|
774
|
+
skipped: ENGINE_NOT_UP_SPEC,
|
|
775
|
+
});
|
|
776
|
+
const ONBOARD_SOURCE = armsRule("onboard source", "kind", {
|
|
777
|
+
preset: { providerId: reqF(R_NONEMPTY) },
|
|
778
|
+
custom: {},
|
|
779
|
+
imported: { profileId: reqF(R_NONEMPTY) },
|
|
780
|
+
});
|
|
781
|
+
const ONBOARD_ENTRY_SPEC = {
|
|
782
|
+
source: reqF(ONBOARD_SOURCE),
|
|
783
|
+
modelId: reqF(R_NONEMPTY),
|
|
784
|
+
baseUrl: optF(R_NONEMPTY),
|
|
785
|
+
api: optF(R_API_WORD),
|
|
786
|
+
apiKey: optF(R_NONEMPTY),
|
|
787
|
+
contextWindow: optF(R_INT1),
|
|
788
|
+
maxTokens: optF(R_INT1),
|
|
789
|
+
};
|
|
790
|
+
const ONBOARD_KEY_ALLOW = new Set(["apiKey"]);
|
|
791
|
+
export const checkOnboardEntryRequest = seatShapeCheck(shapeRule("probeOnboardEntry request", ONBOARD_ENTRY_SPEC), ONBOARD_KEY_ALLOW);
|
|
792
|
+
export const checkOnboardApplyRequest = seatShapeCheck(shapeRule("applyOnboardEntry request", {
|
|
793
|
+
...ONBOARD_ENTRY_SPEC,
|
|
794
|
+
makeDefault: optF(R_BOOL),
|
|
795
|
+
acceptUnverified: optF(R_BOOL),
|
|
796
|
+
}), ONBOARD_KEY_ALLOW);
|
|
797
|
+
const checkOnboardProbeResult = seatShapeCheck(ONBOARD_PROBE_RESULT);
|
|
798
|
+
const checkOnboardApplyResult = seatShapeCheck(okArmsRule("applyOnboardEntry result", {
|
|
799
|
+
entryName: reqF(R_NONEMPTY),
|
|
800
|
+
modelId: reqF(R_NONEMPTY),
|
|
801
|
+
keyEnv: reqF(R_NONEMPTY),
|
|
802
|
+
updatedExisting: reqF(R_BOOL),
|
|
803
|
+
probe: reqF(ONBOARD_PROBE_RESULT),
|
|
804
|
+
otherIssues: reqF(arrayRule(shapeRule("catalog issue", {
|
|
805
|
+
name: reqF(R_NONEMPTY),
|
|
806
|
+
modelId: reqF(R_STR),
|
|
807
|
+
issue: reqF(R_NONEMPTY),
|
|
808
|
+
}))),
|
|
809
|
+
engine: reqF(ENGINE_RESTART_OUTCOME),
|
|
810
|
+
}, {
|
|
811
|
+
refusal: reqF(oneOfRule("onboard refusal", ONBOARD_REFUSALS)),
|
|
812
|
+
detail: optF(R_STR),
|
|
813
|
+
probe: optF(ONBOARD_PROBE_RESULT),
|
|
814
|
+
}));
|
|
815
|
+
const checkOnboardProvidersResult = seatShapeCheck(shapeRule("onboard providers", {
|
|
816
|
+
providers: reqF(arrayRule(shapeRule("provider row", {
|
|
817
|
+
id: reqF(R_NONEMPTY),
|
|
818
|
+
name: reqF(R_NONEMPTY),
|
|
819
|
+
baseUrl: reqF(R_NONEMPTY),
|
|
820
|
+
api: reqF(R_API_WORD),
|
|
821
|
+
keyAuth: reqF(R_BOOL),
|
|
822
|
+
authEnv: reqF(R_STR),
|
|
823
|
+
models: reqF(arrayRule(shapeRule("provider model", {
|
|
824
|
+
id: reqF(R_NONEMPTY),
|
|
825
|
+
contextWindow: reqF(R_INT1),
|
|
826
|
+
maxTokens: reqF(R_INT1),
|
|
827
|
+
}))),
|
|
828
|
+
consoleUrl: optF(R_STR),
|
|
829
|
+
}))),
|
|
830
|
+
importable: optF(arrayRule(shapeRule("importable profile", {
|
|
831
|
+
id: reqF(R_NONEMPTY),
|
|
832
|
+
name: reqF(R_STR),
|
|
833
|
+
baseUrl: reqF(R_NONEMPTY),
|
|
834
|
+
api: reqF(R_API_WORD),
|
|
835
|
+
hasKey: reqF(R_BOOL),
|
|
836
|
+
models: reqF(arrayRule(R_NONEMPTY)),
|
|
837
|
+
}))),
|
|
838
|
+
}));
|
|
839
|
+
const checkSessionMcpPanelFailure = seatShapeCheck(armsRule("readSessionMcpPanel failure", "kind", {
|
|
840
|
+
unreadable: DEVICE_UNREADABLE_SPEC,
|
|
841
|
+
transport: DEVICE_TRANSPORT_SPEC,
|
|
842
|
+
unarmed: {},
|
|
843
|
+
}));
|
|
844
|
+
function mcpPanelLivenessArms() {
|
|
845
|
+
const arms = {};
|
|
846
|
+
for (const state of MCP_LIVENESS_STATES)
|
|
847
|
+
arms[state] = state === "unreachable" ? { observedAt: reqF(R_NUM), errorCode: optF(R_NONEMPTY) } : { observedAt: reqF(R_NUM) };
|
|
848
|
+
const keysPin = [true, true];
|
|
849
|
+
void keysPin;
|
|
850
|
+
return arms;
|
|
851
|
+
}
|
|
852
|
+
const MCP_PANEL_LIVENESS_VIEW = armsRule("mcp liveness", "state", mcpPanelLivenessArms());
|
|
853
|
+
const MCP_PANEL_LEG_ENTRY = shapeRule("leg entry", {
|
|
854
|
+
name: reqF(R_NONEMPTY),
|
|
855
|
+
status: reqF(R_NONEMPTY),
|
|
856
|
+
source: optF(R_NONEMPTY),
|
|
857
|
+
errorCode: optF(R_NONEMPTY),
|
|
858
|
+
toolCount: optF(R_NUM),
|
|
859
|
+
delivered: optF(R_NONEMPTY),
|
|
860
|
+
httpStatus: optF(R_NUM),
|
|
861
|
+
liveness: optF(MCP_PANEL_LIVENESS_VIEW),
|
|
862
|
+
livenessUnreadable: optF(R_TRUE),
|
|
863
|
+
});
|
|
864
|
+
const MCP_PANEL_LAST_LEG = shapeRule("last leg", {
|
|
865
|
+
runId: reqF(R_NONEMPTY),
|
|
866
|
+
at: reqF(R_NONEMPTY),
|
|
867
|
+
mcp: reqF(arrayRule(MCP_PANEL_LEG_ENTRY)),
|
|
868
|
+
});
|
|
869
|
+
const MCP_PANEL_SERVER_ROW = shapeRule("panel server", {
|
|
870
|
+
name: reqF(R_NONEMPTY),
|
|
871
|
+
status: reqF(R_NONEMPTY),
|
|
872
|
+
serverInfo: optF(shapeRule("server info", {
|
|
873
|
+
name: reqF(R_STR),
|
|
874
|
+
version: reqF(R_STR),
|
|
875
|
+
})),
|
|
876
|
+
toolNames: optF(arrayRule(R_STR)),
|
|
877
|
+
error: optF(R_STR),
|
|
878
|
+
});
|
|
879
|
+
const MCP_PANEL_SCENARIO_REFUSAL = shapeRule("scenario refusal", {
|
|
880
|
+
errorCode: optF(R_NONEMPTY),
|
|
881
|
+
error: optF(R_STR),
|
|
882
|
+
scenario: optF(R_NONEMPTY),
|
|
883
|
+
source: optF(oneOfRule("refusal source", ["ruling", "deployment"])),
|
|
884
|
+
});
|
|
885
|
+
const checkSessionMcpPanelServersView = seatShapeCheck(shapeRule("servers view", {
|
|
886
|
+
asOf: reqF(R_NONEMPTY),
|
|
887
|
+
lastLegMcp: optF(MCP_PANEL_LAST_LEG),
|
|
888
|
+
lastLegMcpUnreadable: optF(R_TRUE),
|
|
889
|
+
servers: reqF(arrayRule(MCP_PANEL_SERVER_ROW)),
|
|
890
|
+
degraded: optF(R_TRUE),
|
|
891
|
+
}));
|
|
892
|
+
const checkSessionMcpPanelRefusalView = seatShapeCheck(shapeRule("refusal view", {
|
|
893
|
+
asOf: reqF(R_NONEMPTY),
|
|
894
|
+
lastLegMcp: optF(MCP_PANEL_LAST_LEG),
|
|
895
|
+
lastLegMcpUnreadable: optF(R_TRUE),
|
|
896
|
+
scenarioRefusal: reqF(MCP_PANEL_SCENARIO_REFUSAL),
|
|
897
|
+
}));
|
|
898
|
+
const checkSessionMcpPanelResult = seatCheck((v) => {
|
|
899
|
+
if (!isPlainRecord(v))
|
|
900
|
+
return bad("mcp panel result is not a plain object");
|
|
901
|
+
if (Object.hasOwn(v, "kind"))
|
|
902
|
+
return checkSessionMcpPanelFailure(v);
|
|
903
|
+
return Object.hasOwn(v, "scenarioRefusal") ? checkSessionMcpPanelRefusalView(v) : checkSessionMcpPanelServersView(v);
|
|
904
|
+
});
|
|
408
905
|
const checkLocalSessionRecord = seatCheck((s) => {
|
|
409
906
|
if (!isPlainRecord(s))
|
|
410
907
|
return bad("session record is not a plain object");
|
|
@@ -505,6 +1002,91 @@ const checkLaneProof = seatCheckAt((v, field) => {
|
|
|
505
1002
|
}
|
|
506
1003
|
return true;
|
|
507
1004
|
});
|
|
1005
|
+
const R_NEVER = ruleOf("absent", () => false);
|
|
1006
|
+
const RETRY_ERROR_PAYLOAD = shapeRule("retry error", {
|
|
1007
|
+
formatted: reqF(R_STR),
|
|
1008
|
+
isNetworkDown: optF(R_BOOL),
|
|
1009
|
+
connection: optF(shapeRule("connection", { isSSLError: optF(R_BOOL) })),
|
|
1010
|
+
rateLimits: optF({
|
|
1011
|
+
label: "rate limits",
|
|
1012
|
+
test: (v, path) => v === null
|
|
1013
|
+
? true
|
|
1014
|
+
: shapeVerdict({ resetsAt: optF(R_NUM), rateLimitType: optF(R_STR) }, v, path),
|
|
1015
|
+
}),
|
|
1016
|
+
});
|
|
1017
|
+
const RETRY_COMMON_SPEC = {
|
|
1018
|
+
deadline: reqF(R_NUM),
|
|
1019
|
+
attempt: optF(R_NUM),
|
|
1020
|
+
maxRetries: optF(R_NUM),
|
|
1021
|
+
errClass: optF(R_STR),
|
|
1022
|
+
retryAtMs: optF(R_NUM),
|
|
1023
|
+
errorStatus: optF(R_NUM),
|
|
1024
|
+
providerCondition: optF(R_STR),
|
|
1025
|
+
providerConditionSource: optF(R_STR),
|
|
1026
|
+
elapsedMs: optF(R_NUM),
|
|
1027
|
+
timeoutMs: optF(R_NUM),
|
|
1028
|
+
};
|
|
1029
|
+
const RETRY_STATUS = armsRule("retry status", "kind", {
|
|
1030
|
+
stalled: { ...RETRY_COMMON_SPEC, detail: optF(R_STR) },
|
|
1031
|
+
error: { ...RETRY_COMMON_SPEC, terminal: optF(R_TRUE), error: reqF(RETRY_ERROR_PAYLOAD) },
|
|
1032
|
+
waiting: { ...RETRY_COMMON_SPEC, terminal: optF(R_NEVER), error: reqF(RETRY_ERROR_PAYLOAD) },
|
|
1033
|
+
});
|
|
1034
|
+
const ENGINE_TURN_USAGE = shapeRule("engine usage", {
|
|
1035
|
+
inputTokens: reqF(R_NUM),
|
|
1036
|
+
totalInputTokens: reqF(R_NUM),
|
|
1037
|
+
outputTokens: reqF(R_NUM),
|
|
1038
|
+
cacheReadTokens: reqF(R_NUM),
|
|
1039
|
+
cacheWriteTokens: reqF(R_NUM),
|
|
1040
|
+
costMicroUsd: reqF(R_NUM),
|
|
1041
|
+
});
|
|
1042
|
+
const SEMA_MODEL_USAGE = shapeRule("model usage", {
|
|
1043
|
+
inputTokens: reqF(R_NUM),
|
|
1044
|
+
outputTokens: reqF(R_NUM),
|
|
1045
|
+
cacheReadInputTokens: reqF(R_NUM),
|
|
1046
|
+
cacheCreationInputTokens: reqF(R_NUM),
|
|
1047
|
+
webSearchRequests: reqF(R_NUM),
|
|
1048
|
+
costUSD: reqF(R_NUM),
|
|
1049
|
+
contextWindow: reqF(R_NUM),
|
|
1050
|
+
maxOutputTokens: reqF(R_NUM),
|
|
1051
|
+
canonicalModel: optF(R_STR),
|
|
1052
|
+
provider: optF(R_STR),
|
|
1053
|
+
_sema_cost_absent: optF(R_TRUE),
|
|
1054
|
+
_sema_web_search_requests_absent: optF(R_TRUE),
|
|
1055
|
+
_sema_context_window_absent: optF(R_TRUE),
|
|
1056
|
+
_sema_max_output_tokens_absent: optF(R_TRUE),
|
|
1057
|
+
});
|
|
1058
|
+
const SEAT_CHROME_PAYLOAD_SPECS = {
|
|
1059
|
+
retry_status: { status: reqF({ label: "retry status", test: (v, path) => (v === null ? true : RETRY_STATUS.test(v, path)) }) },
|
|
1060
|
+
context_usage: {
|
|
1061
|
+
usedTokens: optF(R_NUM),
|
|
1062
|
+
windowTokens: optF(R_NUM),
|
|
1063
|
+
compactAtTokens: optF(R_NUM),
|
|
1064
|
+
sections: optF(arrayRule(shapeRule("section", { id: reqF(R_STR), tokens: reqF(R_NUM), kind: optF(R_STR) }))),
|
|
1065
|
+
eventId: optF(R_NONEMPTY),
|
|
1066
|
+
},
|
|
1067
|
+
last_turn_usage: {
|
|
1068
|
+
usage: reqF(SEMA_MODEL_USAGE),
|
|
1069
|
+
engineUsage: optF(ENGINE_TURN_USAGE),
|
|
1070
|
+
engineUsageUnknownKeys: optF(R_INT1),
|
|
1071
|
+
usageMissing: optF(R_TRUE),
|
|
1072
|
+
stopReason: optF(R_STR),
|
|
1073
|
+
responseModel: optF(R_NONEMPTY),
|
|
1074
|
+
},
|
|
1075
|
+
bgshell_register: {
|
|
1076
|
+
taskId: reqF(R_NONEMPTY),
|
|
1077
|
+
registration: reqF(shapeRule("registration", {
|
|
1078
|
+
kind: reqF(oneOfRule("registration kind", ["register"])),
|
|
1079
|
+
taskId: reqF(R_NONEMPTY),
|
|
1080
|
+
command: reqF(R_STR),
|
|
1081
|
+
description: optF(R_STR),
|
|
1082
|
+
receipt: reqF(R_STR),
|
|
1083
|
+
source: reqF(oneOfRule("registration source", ["bash", "monitor"])),
|
|
1084
|
+
})),
|
|
1085
|
+
},
|
|
1086
|
+
bgshell_settle: { taskId: reqF(R_NONEMPTY), status: reqF(R_STR), outputPath: optF(R_STR) },
|
|
1087
|
+
memory_saved: { id: reqF(R_NONEMPTY), notes: reqF(arrayRule(R_NONEMPTY, true)) },
|
|
1088
|
+
};
|
|
1089
|
+
const ENVELOPE_ROWS = { kind: reqF({ label: "kind", test: () => true }), laneProof: reqF({ label: "laneProof", test: () => true }) };
|
|
508
1090
|
const checkSeatChromeEnvelope = seatCheckAt((v, field) => {
|
|
509
1091
|
if (!isPlainRecord(v))
|
|
510
1092
|
return bad("chrome must be a plain object", field);
|
|
@@ -514,7 +1096,13 @@ const checkSeatChromeEnvelope = seatCheckAt((v, field) => {
|
|
|
514
1096
|
if (!inTuple(CHROME_EVENT_KIND_TUPLE, kind)) {
|
|
515
1097
|
return bad(`chrome.kind is not a renderer-wired arm (${CHROME_EVENT_KIND_TUPLE.join("|")})`, `${field}.kind`);
|
|
516
1098
|
}
|
|
517
|
-
|
|
1099
|
+
const lane = checkLaneProof(own(v, "laneProof"), `${field}.laneProof`);
|
|
1100
|
+
if (lane !== true)
|
|
1101
|
+
return lane;
|
|
1102
|
+
if (Object.hasOwn(SEAT_CHROME_PAYLOAD_SPECS, kind)) {
|
|
1103
|
+
return shapeVerdict({ ...ENVELOPE_ROWS, ...SEAT_CHROME_PAYLOAD_SPECS[kind] }, v, field);
|
|
1104
|
+
}
|
|
1105
|
+
return true;
|
|
518
1106
|
});
|
|
519
1107
|
const checkLocalSessionEvent = seatCheck((v) => {
|
|
520
1108
|
if (!isPlainRecord(v))
|
|
@@ -534,18 +1122,6 @@ const checkLocalSessionEvent = seatCheck((v) => {
|
|
|
534
1122
|
const code = own(v, "code");
|
|
535
1123
|
if (!isAbsent(code) && typeof code !== "number")
|
|
536
1124
|
return bad("code must be a number when present", "code");
|
|
537
|
-
const request = own(v, "request");
|
|
538
|
-
if (!isAbsent(request)) {
|
|
539
|
-
const verdict = checkToolPermissionRequest(request);
|
|
540
|
-
if (verdict !== true)
|
|
541
|
-
return nested("request", verdict);
|
|
542
|
-
}
|
|
543
|
-
const sources = own(v, "sources");
|
|
544
|
-
if (!isAbsent(sources)) {
|
|
545
|
-
const okSources = Array.isArray(sources) && ownItems(sources).every((t) => typeof t === "string");
|
|
546
|
-
if (!okSources)
|
|
547
|
-
return bad("sources must be a string[]", "sources");
|
|
548
|
-
}
|
|
549
1125
|
const session = own(v, "session");
|
|
550
1126
|
if (!isAbsent(session)) {
|
|
551
1127
|
const verdict = checkLocalSessionRecord(session);
|
|
@@ -573,8 +1149,43 @@ const checkLocalSessionEvent = seatCheck((v) => {
|
|
|
573
1149
|
if (verdict !== true)
|
|
574
1150
|
return nested("chrome", verdict);
|
|
575
1151
|
}
|
|
1152
|
+
const sub = own(v, "subagentContent");
|
|
1153
|
+
if (type === "subagent_content") {
|
|
1154
|
+
if (isAbsent(sub))
|
|
1155
|
+
return bad("missing key", "subagentContent");
|
|
1156
|
+
const verdict = SUBAGENT_CONTENT_SHAPE.test(sub, "subagentContent");
|
|
1157
|
+
if (verdict !== true)
|
|
1158
|
+
return verdict;
|
|
1159
|
+
}
|
|
1160
|
+
else if (!isAbsent(sub)) {
|
|
1161
|
+
return bad("unexpected key", "subagentContent");
|
|
1162
|
+
}
|
|
576
1163
|
return true;
|
|
577
1164
|
});
|
|
1165
|
+
const SUBAGENT_CONTENT_SHAPE = shapeRule("subagent content", {
|
|
1166
|
+
type: reqF(oneOfRule("content type", ["text_delta", "reasoning_delta", "text", "reasoning", "tool_start", "tool_end"])),
|
|
1167
|
+
taskId: reqF(R_NONEMPTY),
|
|
1168
|
+
parentToolCallId: reqF(R_NONEMPTY),
|
|
1169
|
+
delta: optF(R_STR),
|
|
1170
|
+
text: optF(R_STR),
|
|
1171
|
+
eventId: optF(R_STR),
|
|
1172
|
+
toolCallId: optF(R_STR),
|
|
1173
|
+
toolName: optF(R_STR),
|
|
1174
|
+
args: optF({ label: "passthrough", test: () => true }),
|
|
1175
|
+
output: optF(R_STR),
|
|
1176
|
+
isError: optF(R_BOOL),
|
|
1177
|
+
});
|
|
1178
|
+
export function readSeatSubagentContent(event) {
|
|
1179
|
+
try {
|
|
1180
|
+
if (checkLocalSessionEvent(event) !== true || own(event, "type") !== "subagent_content")
|
|
1181
|
+
return undefined;
|
|
1182
|
+
const sub = own(event, "subagentContent");
|
|
1183
|
+
return { ...sub };
|
|
1184
|
+
}
|
|
1185
|
+
catch {
|
|
1186
|
+
return undefined;
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
578
1189
|
export function isLocalSessionEvent(v) {
|
|
579
1190
|
return checkLocalSessionEvent(v) === true;
|
|
580
1191
|
}
|
|
@@ -945,6 +1556,21 @@ export const LOCAL_SESSIONS_SPEC = {
|
|
|
945
1556
|
pickFolder: { kind: "invoke", check: checkPickFolderResult },
|
|
946
1557
|
listRecentFolders: { kind: "invoke", check: checkRecentFoldersResult },
|
|
947
1558
|
noteRecentFolder: { kind: "invoke", check: checkOkAck }, patchSession: { kind: "invoke", check: checkLocalSessionRecord },
|
|
1559
|
+
listDevices: { kind: "invoke", check: checkDeviceListOutcome },
|
|
1560
|
+
readSessionBinding: { kind: "invoke", check: checkDeviceSessionBindingOutcome },
|
|
1561
|
+
rebindSession: { kind: "invoke", check: checkDeviceRebindOutcome },
|
|
1562
|
+
issueEnrollToken: { kind: "invoke", check: checkDeviceEnrollTokenOutcome },
|
|
1563
|
+
revokeDevice: { kind: "invoke", check: checkDeviceRevokeOutcome },
|
|
1564
|
+
setEngineMode: { kind: "invoke", check: checkEngineTargetResult },
|
|
1565
|
+
startCloudLogin: { kind: "invoke", check: checkCloudLoginStart },
|
|
1566
|
+
cancelCloudLogin: { kind: "invoke", check: checkCancelCloudLogin },
|
|
1567
|
+
connectCloudEngine: { kind: "invoke", check: checkCloudConnectResult },
|
|
1568
|
+
configureCloudEngine: { kind: "invoke", check: checkCloudConnectResult },
|
|
1569
|
+
clearCloudEngine: { kind: "invoke", check: checkEngineTargetResult },
|
|
1570
|
+
listOnboardProviders: { kind: "invoke", check: checkOnboardProvidersResult },
|
|
1571
|
+
probeOnboardEntry: { kind: "invoke", check: checkOnboardProbeResult },
|
|
1572
|
+
applyOnboardEntry: { kind: "invoke", check: checkOnboardApplyResult },
|
|
1573
|
+
readSessionMcpPanel: { kind: "invoke", check: checkSessionMcpPanelResult },
|
|
948
1574
|
onEvent: { kind: "event", check: checkLocalSessionEvent },
|
|
949
1575
|
onToolPermissionRequest: { kind: "event", check: checkToolPermissionRequest },
|
|
950
1576
|
},
|
|
@@ -953,6 +1579,7 @@ export const LOCAL_SESSIONS_SPEC = {
|
|
|
953
1579
|
focusedSessionState: { check: checkFocusedSessionState },
|
|
954
1580
|
settingsState: { check: checkSettingsState },
|
|
955
1581
|
seatCapabilitiesState: { check: checkSeatCapabilitiesState },
|
|
1582
|
+
engineTargetState: { check: checkEngineTargetState },
|
|
956
1583
|
},
|
|
957
1584
|
};
|
|
958
1585
|
export const SEAT_METHOD_NAMES = [
|
|
@@ -974,6 +1601,21 @@ export const SEAT_METHOD_NAMES = [
|
|
|
974
1601
|
"pickFolder",
|
|
975
1602
|
"listRecentFolders",
|
|
976
1603
|
"noteRecentFolder", "patchSession",
|
|
1604
|
+
"listDevices",
|
|
1605
|
+
"readSessionBinding",
|
|
1606
|
+
"rebindSession",
|
|
1607
|
+
"issueEnrollToken",
|
|
1608
|
+
"revokeDevice",
|
|
1609
|
+
"setEngineMode",
|
|
1610
|
+
"startCloudLogin",
|
|
1611
|
+
"cancelCloudLogin",
|
|
1612
|
+
"connectCloudEngine",
|
|
1613
|
+
"configureCloudEngine",
|
|
1614
|
+
"clearCloudEngine",
|
|
1615
|
+
"listOnboardProviders",
|
|
1616
|
+
"probeOnboardEntry",
|
|
1617
|
+
"applyOnboardEntry",
|
|
1618
|
+
"readSessionMcpPanel",
|
|
977
1619
|
"onEvent",
|
|
978
1620
|
"onToolPermissionRequest",
|
|
979
1621
|
];
|
|
@@ -982,6 +1624,7 @@ export const SEAT_STORE_PROPS = [
|
|
|
982
1624
|
"focusedSessionStateStore",
|
|
983
1625
|
"settingsStateStore",
|
|
984
1626
|
"seatCapabilitiesStateStore",
|
|
1627
|
+
"engineTargetStateStore",
|
|
985
1628
|
];
|
|
986
1629
|
export const SEAT_EVENT_METHOD_NAMES = ["onEvent", "onToolPermissionRequest"];
|
|
987
1630
|
export const LOCAL_SESSION_EVENT_KEYS = [
|
|
@@ -991,8 +1634,6 @@ export const LOCAL_SESSION_EVENT_KEYS = [
|
|
|
991
1634
|
"error",
|
|
992
1635
|
"errorCategory",
|
|
993
1636
|
"code",
|
|
994
|
-
"request",
|
|
995
|
-
"sources",
|
|
996
1637
|
"session",
|
|
997
1638
|
"userMessageUuid",
|
|
998
1639
|
"requestId",
|
|
@@ -1000,6 +1641,7 @@ export const LOCAL_SESSION_EVENT_KEYS = [
|
|
|
1000
1641
|
"parked",
|
|
1001
1642
|
"chrome",
|
|
1002
1643
|
"_sema_turnFailure",
|
|
1644
|
+
"subagentContent",
|
|
1003
1645
|
];
|
|
1004
1646
|
export const TOOL_PERMISSION_REQUEST_KEYS = [
|
|
1005
1647
|
"requestId",
|
|
@@ -1135,14 +1777,13 @@ export const SEAT_VALIDATOR_KEY_COVERAGE = {
|
|
|
1135
1777
|
"error",
|
|
1136
1778
|
"errorCategory",
|
|
1137
1779
|
"code",
|
|
1138
|
-
"request",
|
|
1139
|
-
"sources",
|
|
1140
1780
|
"session",
|
|
1141
1781
|
"userMessageUuid",
|
|
1142
1782
|
"requestId",
|
|
1143
1783
|
"outcome",
|
|
1144
1784
|
"parked",
|
|
1145
1785
|
"chrome",
|
|
1786
|
+
"subagentContent",
|
|
1146
1787
|
],
|
|
1147
1788
|
unchecked: [
|
|
1148
1789
|
{
|
|
@@ -1254,7 +1895,7 @@ export const SEAT_VALIDATOR_KEY_COVERAGE = {
|
|
|
1254
1895
|
},
|
|
1255
1896
|
SeatCapabilitiesState: {
|
|
1256
1897
|
check: checkSeatCapabilitiesState,
|
|
1257
|
-
validated: ["pickFolder", "rewind", "recents", "patchSession"],
|
|
1898
|
+
validated: ["pickFolder", "rewind", "recents", "patchSession", "devices", "engineTarget", "onboard"],
|
|
1258
1899
|
unchecked: [],
|
|
1259
1900
|
},
|
|
1260
1901
|
RecentFoldersResult: {
|
|
@@ -1287,8 +1928,39 @@ export const SEAT_VALIDATOR_KEY_COVERAGE = {
|
|
|
1287
1928
|
validated: ["kind", "laneProof"],
|
|
1288
1929
|
unchecked: [],
|
|
1289
1930
|
},
|
|
1931
|
+
SessionMcpPanelResult: {
|
|
1932
|
+
check: checkSessionMcpPanelResult,
|
|
1933
|
+
validated: ["kind", "why", "detail", "asOf", "servers", "lastLegMcp", "lastLegMcpUnreadable", "degraded", "scenarioRefusal"],
|
|
1934
|
+
unchecked: [],
|
|
1935
|
+
},
|
|
1290
1936
|
};
|
|
1291
1937
|
export const SEAT_VALIDATOR_COVERAGE_EXEMPT = [
|
|
1938
|
+
...[
|
|
1939
|
+
["DeviceListOutcome", checkDeviceListOutcome],
|
|
1940
|
+
["DeviceSessionBindingOutcome", checkDeviceSessionBindingOutcome],
|
|
1941
|
+
["DeviceRebindOutcome", checkDeviceRebindOutcome],
|
|
1942
|
+
["DeviceEnrollTokenOutcome", checkDeviceEnrollTokenOutcome],
|
|
1943
|
+
["DeviceRevokeOutcome", checkDeviceRevokeOutcome],
|
|
1944
|
+
["SeatDeviceRebindRequest", checkSeatDeviceRebindRequest],
|
|
1945
|
+
["SeatDeviceRevokeRequest", checkSeatDeviceRevokeRequest],
|
|
1946
|
+
["EngineTargetState", checkEngineTargetState],
|
|
1947
|
+
["EngineTargetResult", checkEngineTargetResult],
|
|
1948
|
+
["CloudLoginStart", checkCloudLoginStart],
|
|
1949
|
+
["CloudLoginCancelAck", checkCancelCloudLogin],
|
|
1950
|
+
["CloudConnectResult", checkCloudConnectResult],
|
|
1951
|
+
["CloudLoginRequest", checkCloudLoginRequest],
|
|
1952
|
+
["CloudEngineConnectRequest", checkCloudEngineConnectRequest],
|
|
1953
|
+
["CloudEngineConfigureRequest", checkCloudEngineConfigureRequest],
|
|
1954
|
+
["OnboardProvidersResult", checkOnboardProvidersResult],
|
|
1955
|
+
["OnboardProbeResult", checkOnboardProbeResult],
|
|
1956
|
+
["OnboardApplyResult", checkOnboardApplyResult],
|
|
1957
|
+
["OnboardEntryRequest", checkOnboardEntryRequest],
|
|
1958
|
+
["OnboardApplyRequest", checkOnboardApplyRequest],
|
|
1959
|
+
].map(([label, check]) => ({
|
|
1960
|
+
label,
|
|
1961
|
+
check,
|
|
1962
|
+
why: "座位闭形规则铸的判官(规格表型由对象型派生,键集与必选性编译期两向钉);逐臂逐键投毒在三只席位门(见上方注)。",
|
|
1963
|
+
})),
|
|
1292
1964
|
{
|
|
1293
1965
|
label: "PickFolderResult",
|
|
1294
1966
|
check: checkPickFolderResult,
|
|
@@ -1333,5 +2005,6 @@ const _seatContractPins = [
|
|
|
1333
2005
|
true, true, true, true, true, true,
|
|
1334
2006
|
true, true,
|
|
1335
2007
|
true, true, true, true,
|
|
2008
|
+
true, true, true,
|
|
1336
2009
|
];
|
|
1337
2010
|
void _seatContractPins;
|