@sema-agent/client-core 0.94.0 → 0.95.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 +341 -0
- package/README.md +70 -47
- package/dist/adapt/arms.js +5 -6
- package/dist/adapt/panelTasks.js +4 -10
- package/dist/adapt/toolCards.js +2 -2
- package/dist/adapt/wireShapes.js +3 -8
- package/dist/adapter/activeRunSelfHeal.d.ts +8 -3
- package/dist/adapter/activeRunSelfHeal.js +20 -12
- package/dist/adapter/downstream/eventToSdkMessage.js +24 -17
- package/dist/adapter/downstream/terminalToSdkResult.js +11 -3
- package/dist/adapter/runStream.js +2 -1
- package/dist/adapter/types.d.ts +7 -0
- package/dist/adapter/types.js +15 -0
- package/dist/agentSession/backgroundView.js +5 -1
- package/dist/agentSession/engineAgentRegistryRead.js +2 -1
- package/dist/agentSession/engineSessionBackgroundStop.js +3 -2
- package/dist/agentsWireCaps.d.ts +2 -0
- package/dist/approvalDecidedByCapability.d.ts +0 -1
- package/dist/approvalDecidedByCapability.js +2 -7
- package/dist/approvalsStreamLiveCapability.d.ts +0 -1
- package/dist/approvalsStreamLiveCapability.js +2 -6
- package/dist/atMostOnce.d.ts +8 -0
- package/dist/atMostOnce.js +36 -0
- package/dist/attachmentSeatCapability.d.ts +0 -1
- package/dist/attachmentSeatCapability.js +0 -3
- package/dist/attachmentsWireCaps.js +11 -6
- package/dist/bashExitReading.d.ts +10 -0
- package/dist/bashExitReading.js +12 -0
- package/dist/callerCwdCapability.d.ts +0 -1
- package/dist/callerCwdCapability.js +2 -7
- package/dist/centerWiringCapability.d.ts +1 -3
- package/dist/centerWiringCapability.js +18 -21
- package/dist/classifierStatus.js +4 -4
- package/dist/cloudConfigWireCaps.js +43 -21
- package/dist/compensations.js +1 -1
- package/dist/cycleOrder.d.ts +15 -0
- package/dist/cycleOrder.js +45 -0
- package/dist/decideFailureNote.js +4 -1
- package/dist/decideReceipt.d.ts +2 -1
- package/dist/decideReceipt.js +41 -13
- package/dist/declared/supportFloorDeclared.d.ts +1 -0
- package/dist/declared/supportFloorDeclared.js +5 -0
- package/dist/deviceExecutorManagementCapability.d.ts +0 -1
- package/dist/deviceExecutorManagementCapability.js +7 -16
- package/dist/deviceRebind.d.ts +88 -0
- package/dist/deviceRebind.js +242 -0
- package/dist/displayUntrusted.d.ts +1 -0
- package/dist/displayUntrusted.js +313 -11
- package/dist/engineAgentAbsence.d.ts +2 -2
- package/dist/engineAgentPanelStore.d.ts +8 -18
- package/dist/engineAgentPanelStore.js +19 -537
- package/dist/engineCapReader.d.ts +6 -6
- package/dist/engineCapReader.js +30 -43
- package/dist/engineCapsCache.d.ts +7 -2
- package/dist/engineCapsCache.js +64 -26
- package/dist/engineCredentialRequirement.d.ts +9 -0
- package/dist/engineCredentialRequirement.js +23 -0
- package/dist/engineEnvSourcing.d.ts +53 -0
- package/dist/engineEnvSourcing.js +81 -0
- package/dist/engineErrorCodes.d.ts +14 -3
- package/dist/engineErrorCodes.js +31 -10
- package/dist/engineIdentity.js +2 -0
- package/dist/engineWireSdk.js +2 -2
- package/dist/executionLaneCapability.d.ts +2 -3
- package/dist/executionLaneCapability.js +18 -23
- package/dist/fileHistoryCaptureCapability.d.ts +0 -1
- package/dist/fileHistoryCaptureCapability.js +2 -6
- package/dist/fileHistoryLegNotice.d.ts +3 -2
- package/dist/fileHistoryLegNotice.js +51 -2
- package/dist/fleet/fleetLedger.d.ts +2 -0
- package/dist/fleet/fleetLedger.js +69 -52
- package/dist/fleet/fleetProjection.d.ts +0 -3
- package/dist/fleet/fleetProjection.js +9 -16
- package/dist/fleetAgentPanelProjection.d.ts +4 -17
- package/dist/fleetAgentPanelProjection.js +7 -197
- package/dist/fleetAgentRowLike.d.ts +16 -0
- package/dist/fleetAgentRowLike.js +1 -0
- package/dist/gateOutcome.js +30 -18
- package/dist/generated/sdkFactTables.d.ts +2 -0
- package/dist/generated/sdkFactTables.js +17 -0
- package/dist/generated/settingsSchemaFns.d.ts +10 -0
- package/dist/generated/settingsSchemaFns.js +22 -0
- package/dist/headlessPermissionModeWire.d.ts +1 -1
- package/dist/headlessPermissionModeWire.js +1 -1
- package/dist/headlessReconnectWire.js +49 -20
- package/dist/hitl/allowRuleShadow.d.ts +1 -1
- package/dist/hitl/allowRuleShadow.js +49 -8
- package/dist/hitl/approvalCompleteParked.d.ts +1 -0
- package/dist/hitl/approvalCompleteParked.js +14 -0
- package/dist/hitl/approvalEndingCause.d.ts +5 -0
- package/dist/hitl/approvalEndingCause.js +61 -0
- package/dist/hitl/approvalHolds.d.ts +12 -2
- package/dist/hitl/approvalHolds.js +53 -2
- package/dist/hitl/approvalsFeed.js +23 -11
- package/dist/hitl/askGateWire.d.ts +2 -1
- package/dist/hitl/askGateWire.js +26 -1
- package/dist/hitl/automaticAnswerVerdict.js +2 -2
- package/dist/hitl/crashConverged.js +2 -0
- package/dist/hitl/decisionConflict.d.ts +3 -0
- package/dist/hitl/decisionConflict.js +43 -0
- package/dist/hitl/decisionRefusal.d.ts +4 -0
- package/dist/hitl/decisionRefusal.js +26 -1
- package/dist/hitl/frameRouter.js +26 -43
- package/dist/hitl/gateLedger.d.ts +5 -0
- package/dist/hitl/gateLedger.js +21 -0
- package/dist/hitl/hitlBridge.d.ts +12 -1
- package/dist/hitl/hitlBridge.js +68 -53
- package/dist/hitl/hitlHostSurface.js +3 -11
- package/dist/hitl/livePendingAsk.d.ts +16 -6
- package/dist/hitl/livePendingAsk.js +36 -4
- package/dist/hitl/parkExpiryJudgements.d.ts +19 -0
- package/dist/hitl/parkExpiryJudgements.js +46 -0
- package/dist/hitl/parkResolver.d.ts +3 -7
- package/dist/hitl/parkResolver.js +50 -26
- package/dist/hitl/persistedRulesWire.js +5 -1
- package/dist/hitl/planReviewWire.d.ts +2 -2
- package/dist/hitl/planReviewWire.js +56 -30
- package/dist/hitl/replayedApproval.d.ts +8 -0
- package/dist/hitl/replayedApproval.js +125 -10
- package/dist/hitl/resumeRunningCard.d.ts +2 -0
- package/dist/hitl/resumeRunningCard.js +15 -4
- package/dist/hitl/toolApprovalWire.d.ts +24 -4
- package/dist/hitl/toolApprovalWire.js +115 -38
- package/dist/hooksWireCaps.js +38 -6
- package/dist/host.d.ts +5 -0
- package/dist/host.js +3 -1
- package/dist/hostCallbackGuard.d.ts +1 -0
- package/dist/hostCallbackGuard.js +25 -0
- package/dist/index.d.ts +30 -11
- package/dist/index.js +20 -8
- package/dist/interactiveInterrupt.d.ts +8 -0
- package/dist/interactiveInterrupt.js +54 -0
- package/dist/limitsWire.d.ts +5 -0
- package/dist/limitsWire.js +49 -3
- package/dist/liveModelCatalog.d.ts +95 -0
- package/dist/liveModelCatalog.js +297 -32
- package/dist/mcpEngineLeg.d.ts +25 -0
- package/dist/mcpEngineLeg.js +71 -15
- package/dist/mcpPanel.js +2 -1
- package/dist/mcpProbeCapability.d.ts +0 -1
- package/dist/mcpProbeCapability.js +2 -6
- package/dist/mcpReconnect.d.ts +1 -3
- package/dist/mcpReconnect.js +10 -5
- package/dist/memoryComplianceCapability.d.ts +0 -1
- package/dist/memoryComplianceCapability.js +2 -6
- package/dist/memoryOriginCapability.d.ts +0 -1
- package/dist/memoryOriginCapability.js +2 -6
- package/dist/memoryVerbsWire.d.ts +1 -1
- package/dist/memoryVerbsWire.js +4 -0
- package/dist/model/liveCatalogShape.d.ts +14 -0
- package/dist/model/liveCatalogShape.js +71 -0
- package/dist/model/modelSupplyRules.d.ts +1 -0
- package/dist/model/modelSupplyRules.js +30 -9
- package/dist/model/modelsPolicy.d.ts +21 -0
- package/dist/model/modelsPolicy.js +90 -0
- package/dist/modelIdentityResolvability.d.ts +1 -1
- package/dist/modelIdentityResolvability.js +5 -12
- package/dist/modelSwitchFallback.d.ts +69 -0
- package/dist/modelSwitchFallback.js +206 -0
- package/dist/notifications.js +12 -11
- package/dist/outputStyleSeatCapability.d.ts +0 -1
- package/dist/outputStyleSeatCapability.js +2 -7
- package/dist/ownKey.d.ts +6 -0
- package/dist/ownKey.js +48 -0
- package/dist/panelReduce.d.ts +114 -0
- package/dist/panelReduce.js +1135 -0
- package/dist/panelStateHolder.d.ts +17 -0
- package/dist/panelStateHolder.js +201 -0
- package/dist/peerLaneCapability.d.ts +0 -1
- package/dist/peerLaneCapability.js +2 -6
- package/dist/permissionModesCapability.d.ts +0 -1
- package/dist/permissionModesCapability.js +5 -10
- package/dist/permissionRulesWriteCapability.d.ts +0 -1
- package/dist/permissionRulesWriteCapability.js +2 -6
- package/dist/permissionsAllowGrantCapability.d.ts +0 -1
- package/dist/permissionsAllowGrantCapability.js +3 -9
- package/dist/permissionsDeclaration.d.ts +6 -0
- package/dist/permissionsDeclaration.js +45 -0
- package/dist/printToolResultFrame.js +2 -10
- package/dist/promptDelivery.js +0 -8
- package/dist/resumeRefusalCopy.d.ts +18 -1
- package/dist/resumeRefusalCopy.js +126 -15
- package/dist/rewindArchiveCapability.d.ts +2 -1
- package/dist/rewindArchiveCapability.js +15 -7
- package/dist/rewindEngineAction.d.ts +21 -0
- package/dist/rewindEngineAction.js +36 -0
- package/dist/rewindWireCaps.d.ts +2 -1
- package/dist/rewindWireCaps.js +1 -0
- package/dist/runTerminal.d.ts +0 -11
- package/dist/runTerminal.js +4 -27
- package/dist/sdkRegistryTransit.d.ts +2 -1
- package/dist/sdkRegistryTransit.js +1 -0
- package/dist/sealedKeyCapability.d.ts +0 -1
- package/dist/sealedKeyCapability.js +3 -9
- package/dist/seatContract.d.ts +54 -25
- package/dist/seatContract.js +394 -171
- package/dist/sessionIdSegment.d.ts +1 -0
- package/dist/sessionIdSegment.js +11 -0
- package/dist/sessionMemoryErase.d.ts +1 -1
- package/dist/sessionMemoryErase.js +6 -1
- package/dist/sessionMemoryStatus.js +3 -2
- package/dist/sessionPolicyCapability.d.ts +0 -1
- package/dist/sessionPolicyCapability.js +2 -6
- package/dist/sessionReadRedactionCapability.d.ts +0 -1
- package/dist/sessionReadRedactionCapability.js +2 -7
- package/dist/sessionSyncFileHistoryCapability.d.ts +0 -1
- package/dist/sessionSyncFileHistoryCapability.js +2 -6
- package/dist/skillToolListsCapability.d.ts +0 -1
- package/dist/skillToolListsCapability.js +2 -6
- package/dist/skillsWireCaps.d.ts +4 -0
- package/dist/skillsWireCaps.js +66 -1
- package/dist/sqlEngineCapability.d.ts +0 -1
- package/dist/sqlEngineCapability.js +9 -14
- package/dist/steerPriorityCapability.d.ts +0 -1
- package/dist/steerPriorityCapability.js +3 -9
- package/dist/storePostureCapability.d.ts +1 -1
- package/dist/storePostureCapability.js +16 -16
- package/dist/streamDrainingLegs.d.ts +6 -0
- package/dist/streamDrainingLegs.js +23 -0
- package/dist/subagent/engineCompactWire.js +13 -38
- package/dist/subagent/engineDelegatedPrompt.js +10 -6
- package/dist/subagent/engineSubagentOutput.d.ts +0 -1
- package/dist/subagent/engineSubagentOutput.js +5 -20
- package/dist/subagent/engineSubagentTail.d.ts +0 -1
- package/dist/subagent/engineSubagentTail.js +7 -32
- package/dist/subagentContentStore.js +3 -3
- package/dist/supportFloor.js +2 -5
- package/dist/terminalStatuses.d.ts +30 -0
- package/dist/terminalStatuses.js +67 -0
- package/dist/toolResult.d.ts +5 -0
- package/dist/toolResult.js +88 -36
- package/dist/types/engineState.d.ts +2 -1
- package/dist/usageAnalytics.d.ts +146 -0
- package/dist/usageAnalytics.js +311 -0
- package/dist/userInvokedSkillsCapability.d.ts +0 -1
- package/dist/userInvokedSkillsCapability.js +2 -6
- package/dist/webSearchBackendCapability.d.ts +0 -1
- package/dist/webSearchBackendCapability.js +3 -7
- package/dist/webSearchWireCaps.js +3 -11
- package/dist/wireFailureShape.d.ts +4 -0
- package/dist/wireFailureShape.js +42 -2
- package/dist/wireRefusalCopy.js +2 -18
- package/dist/workflowClient.js +7 -11
- package/dist/workflowsJournalCapability.d.ts +0 -1
- package/dist/workflowsJournalCapability.js +2 -6
- package/dist/writeProtectionCapability.d.ts +0 -1
- package/dist/writeProtectionCapability.js +5 -10
- package/docs/INTEGRATION-CLIENTS.md +1033 -26
- package/package.json +5 -5
- package/dist/engineCapsGenerationGuard.d.ts +0 -4
- package/dist/engineCapsGenerationGuard.js +0 -19
- package/dist/panelRunningHistory.d.ts +0 -22
- package/dist/panelRunningHistory.js +0 -82
- package/dist/registryConflict.d.ts +0 -3
- package/dist/registryConflict.js +0 -44
package/dist/seatContract.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { PERMISSION_MODE_WORDS, REASONING_EFFORT_WORDS } from "./taskRequestWords.js";
|
|
2
|
+
import { liveDefaultModelCopy, liveModelRowCopy } from "./model/liveCatalogShape.js";
|
|
3
|
+
import { REWIND_MODES } from "./rewindWireCaps.js";
|
|
4
|
+
import { ownDataField, ownDataRefusalKeyOf, ownSendableField } from "./ownKey.js";
|
|
2
5
|
const bad = (reason, field) => field === undefined ? { reason } : { reason, field };
|
|
3
6
|
const nested = (prefix, verdict) => {
|
|
4
7
|
const path = verdict.field === undefined
|
|
@@ -13,6 +16,63 @@ const isObject = (v) => typeof v === "object" && v !== null;
|
|
|
13
16
|
const isAbsent = (v) => typeof v === "undefined";
|
|
14
17
|
const optionalString = (v) => isAbsent(v) || typeof v === "string";
|
|
15
18
|
const inTuple = (tuple, v) => tuple.includes(v);
|
|
19
|
+
const own = (o, k) => ownSendableField(o, k);
|
|
20
|
+
const ownItems = (a) => {
|
|
21
|
+
const n = ownDataField(a, "length");
|
|
22
|
+
const out = [];
|
|
23
|
+
if (typeof n !== "number")
|
|
24
|
+
return out;
|
|
25
|
+
for (let i = 0; i < n; i += 1)
|
|
26
|
+
out.push(own(a, String(i)));
|
|
27
|
+
return out;
|
|
28
|
+
};
|
|
29
|
+
const firstAccessorPath = (root) => {
|
|
30
|
+
const seen = new Set();
|
|
31
|
+
const stack = [[root, ""]];
|
|
32
|
+
while (stack.length > 0) {
|
|
33
|
+
const [v, path] = stack.pop();
|
|
34
|
+
if (typeof v !== "object" || v === null || seen.has(v))
|
|
35
|
+
continue;
|
|
36
|
+
seen.add(v);
|
|
37
|
+
for (const k of Reflect.ownKeys(v)) {
|
|
38
|
+
if (typeof k !== "string")
|
|
39
|
+
continue;
|
|
40
|
+
const d = Reflect.getOwnPropertyDescriptor(v, k);
|
|
41
|
+
if (d === undefined)
|
|
42
|
+
continue;
|
|
43
|
+
const at = path === "" ? k : `${path}.${k}`;
|
|
44
|
+
if (!Object.hasOwn(d, "value"))
|
|
45
|
+
return at;
|
|
46
|
+
stack.push([d.value, at]);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return undefined;
|
|
50
|
+
};
|
|
51
|
+
const NOT_PLAIN_DATA = "must be a plain enumerable data property (accessors are refused and never executed)";
|
|
52
|
+
const seatCheck = (fn) => (v) => {
|
|
53
|
+
try {
|
|
54
|
+
const at = firstAccessorPath(v);
|
|
55
|
+
if (at !== undefined)
|
|
56
|
+
return bad(NOT_PLAIN_DATA, at);
|
|
57
|
+
return fn(v);
|
|
58
|
+
}
|
|
59
|
+
catch (e) {
|
|
60
|
+
const key = ownDataRefusalKeyOf(e);
|
|
61
|
+
return key !== undefined ? bad(NOT_PLAIN_DATA, key) : bad("payload could not be read");
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
const seatCheckAt = (fn) => (v, field) => {
|
|
65
|
+
try {
|
|
66
|
+
const at = firstAccessorPath(v);
|
|
67
|
+
if (at !== undefined)
|
|
68
|
+
return bad(NOT_PLAIN_DATA, `${field}.${at}`);
|
|
69
|
+
return fn(v, field);
|
|
70
|
+
}
|
|
71
|
+
catch (e) {
|
|
72
|
+
const key = ownDataRefusalKeyOf(e);
|
|
73
|
+
return key !== undefined ? bad(NOT_PLAIN_DATA, `${field}.${key}`) : bad("payload could not be read", field);
|
|
74
|
+
}
|
|
75
|
+
};
|
|
16
76
|
export const TOOL_PERMISSION_REQUEST_ID_DOMAINS = Object.freeze([
|
|
17
77
|
"live:",
|
|
18
78
|
"durable:",
|
|
@@ -72,7 +132,7 @@ export const HITL_RESOLUTION_OUTCOMES = [
|
|
|
72
132
|
"decline",
|
|
73
133
|
"cancel",
|
|
74
134
|
];
|
|
75
|
-
export const SEAT_CAPABILITY_NAMES = Object.freeze(["pickFolder"]);
|
|
135
|
+
export const SEAT_CAPABILITY_NAMES = Object.freeze(["pickFolder", "rewind"]);
|
|
76
136
|
const notReported = () => Object.freeze({ kind: "not_reported" });
|
|
77
137
|
const malformedReading = () => Object.freeze({ kind: "malformed" });
|
|
78
138
|
const reported = (available) => Object.freeze({ kind: "reported", available });
|
|
@@ -145,6 +205,7 @@ export function watchSeatCapability(store, name, onReading) {
|
|
|
145
205
|
}
|
|
146
206
|
const SEAT_CAPABILITY_PHRASES = Object.freeze({
|
|
147
207
|
pickFolder: Object.freeze({ action: "Opening a folder", ability: "show a folder picker", support: "folder picker support" }),
|
|
208
|
+
rewind: Object.freeze({ action: "Rewinding to an earlier message", ability: "rewind this session", support: "rewind support" }),
|
|
148
209
|
});
|
|
149
210
|
export function seatCapabilityUnavailableDetail(name, reading) {
|
|
150
211
|
const phrase = Object.hasOwn(SEAT_CAPABILITY_PHRASES, name)
|
|
@@ -171,351 +232,484 @@ export const PERMISSION_MODE_INTENTS = [...PERMISSION_MODE_WORDS];
|
|
|
171
232
|
export const ATTACHMENT_IDS_PER_TASK_CAP = 16;
|
|
172
233
|
export const SEAT_REASONING_EFFORTS = [...REASONING_EFFORT_WORDS];
|
|
173
234
|
export const SEAT_TURN_SETTINGS_KEYS = ["ultracode"];
|
|
235
|
+
export const SEAT_TURN_SETTINGS_ORIGINS = Object.freeze({
|
|
236
|
+
ultracode: Object.freeze({ carriedBy: "renderer" }),
|
|
237
|
+
webSearch: Object.freeze({ hostSupplied: "联网检索的每请求配置来自宿主的设置源(可能带检索服务的凭据与私网地址);渲染端没有设置文件,也不该持有凭据" }),
|
|
238
|
+
hooks: Object.freeze({ hostSupplied: "hooks 表来自宿主的设置文件(宿主经设置端口与 hooksForWire 投影);渲染端没有设置文件、也不执行本机 hook" }),
|
|
239
|
+
resolved: Object.freeze({ hostSupplied: "设置解析器的生效快照(hooks / env / model / 已解析权限)由宿主跑解析器得出;渲染端没有设置源可解析" }),
|
|
240
|
+
outputStyle: Object.freeze({ hostSupplied: "输出风格正文由宿主的兜底层随请求带(风格文件在宿主);渲染端只选名字,不持正文" }),
|
|
241
|
+
});
|
|
242
|
+
export const SEAT_REWIND_INTENT_KEYS = ["mode", "targetMessageUuid"];
|
|
174
243
|
export const ATTACHMENT_UPLOAD_REQUEST_KEYS = ["name", "mimeType", "bytes"];
|
|
175
244
|
export const SESSION_SEARCH_RESULT_KEYS = ["sessionId", "title", "matches"];
|
|
176
245
|
export const GET_TRANSCRIPT_RESULT_KEYS = ["sessionId", "messages"];
|
|
177
|
-
const checkLocalSessionRecord = (s) => {
|
|
246
|
+
const checkLocalSessionRecord = seatCheck((s) => {
|
|
178
247
|
if (!isObject(s))
|
|
179
248
|
return bad("session record is not an object");
|
|
180
|
-
if (typeof s
|
|
249
|
+
if (typeof own(s, "sessionId") !== "string")
|
|
181
250
|
return bad("sessionId must be a string", "sessionId");
|
|
182
|
-
if (!optionalString(s
|
|
251
|
+
if (!optionalString(own(s, "engineSessionId")))
|
|
183
252
|
return bad("engineSessionId must be a string when present", "engineSessionId");
|
|
184
|
-
if (!optionalString(s
|
|
253
|
+
if (!optionalString(own(s, "model")))
|
|
185
254
|
return bad("model must be a string when present", "model");
|
|
186
|
-
if (!optionalString(s
|
|
255
|
+
if (!optionalString(own(s, "title")))
|
|
187
256
|
return bad("title must be a string when present", "title");
|
|
188
|
-
|
|
257
|
+
const cwd = own(s, "cwd");
|
|
258
|
+
if (!isAbsent(cwd) && (typeof cwd !== "string" || cwd.length === 0)) {
|
|
189
259
|
return bad("cwd must be a non-empty path string when present (absent = no folder chosen)", "cwd");
|
|
190
260
|
}
|
|
191
|
-
if (typeof s
|
|
261
|
+
if (typeof own(s, "isRunning") !== "boolean")
|
|
192
262
|
return bad("isRunning must be a boolean", "isRunning");
|
|
193
|
-
if (typeof s
|
|
263
|
+
if (typeof own(s, "createdAt") !== "string")
|
|
194
264
|
return bad("createdAt must be an ISO-8601 string", "createdAt");
|
|
195
|
-
if (!optionalString(s
|
|
265
|
+
if (!optionalString(own(s, "lastActivityAt")))
|
|
196
266
|
return bad("lastActivityAt must be a string when present", "lastActivityAt");
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
const okQueue = Array.isArray(q) && q.every((row) => isObject(row) && typeof row
|
|
267
|
+
const q = own(s, "queuedMessages");
|
|
268
|
+
if (!isAbsent(q)) {
|
|
269
|
+
const okQueue = Array.isArray(q) && ownItems(q).every((row) => isObject(row) && typeof own(row, "uuid") === "string" && typeof own(row, "text") === "string");
|
|
200
270
|
if (!okQueue)
|
|
201
271
|
return bad("queuedMessages must be an array of {uuid,text}", "queuedMessages");
|
|
202
272
|
}
|
|
203
|
-
|
|
273
|
+
const parked = own(s, "parked");
|
|
274
|
+
if (!isAbsent(parked) && typeof parked !== "boolean") {
|
|
204
275
|
return bad("parked must be a boolean when present", "parked");
|
|
205
276
|
}
|
|
206
277
|
return true;
|
|
207
|
-
};
|
|
278
|
+
});
|
|
208
279
|
export function isLocalSessionRecord(s) {
|
|
209
280
|
return checkLocalSessionRecord(s) === true;
|
|
210
281
|
}
|
|
211
|
-
const checkToctouBinding = (v) => {
|
|
282
|
+
const checkToctouBinding = seatCheck((v) => {
|
|
212
283
|
if (!isObject(v))
|
|
213
284
|
return bad("toctouBinding must be an object", "toctouBinding");
|
|
214
|
-
if (typeof v
|
|
285
|
+
if (typeof own(v, "callId") !== "string")
|
|
215
286
|
return bad("toctouBinding.callId must be a string", "toctouBinding.callId");
|
|
216
|
-
if (typeof v
|
|
287
|
+
if (typeof own(v, "inputHash") !== "string")
|
|
217
288
|
return bad("toctouBinding.inputHash must be a string", "toctouBinding.inputHash");
|
|
218
289
|
return true;
|
|
219
|
-
};
|
|
220
|
-
const checkToolPermissionRequest = (r) => {
|
|
290
|
+
});
|
|
291
|
+
const checkToolPermissionRequest = seatCheck((r) => {
|
|
221
292
|
if (!isObject(r))
|
|
222
293
|
return bad("tool permission request is not an object");
|
|
223
|
-
|
|
294
|
+
const requestId = own(r, "requestId");
|
|
295
|
+
if (typeof requestId !== "string")
|
|
224
296
|
return bad("requestId must be a string", "requestId");
|
|
225
|
-
if (toolPermissionRequestIdDomain(
|
|
297
|
+
if (toolPermissionRequestIdDomain(requestId) === undefined) {
|
|
226
298
|
return bad(`requestId must carry a registered domain prefix (${TOOL_PERMISSION_REQUEST_ID_DOMAINS.join("|")})`, "requestId");
|
|
227
299
|
}
|
|
228
|
-
if (typeof r
|
|
300
|
+
if (typeof own(r, "sessionId") !== "string")
|
|
229
301
|
return bad("sessionId must be a string", "sessionId");
|
|
230
|
-
|
|
302
|
+
const toolName = own(r, "toolName");
|
|
303
|
+
if (!isAbsent(toolName) && toolName !== null && typeof toolName !== "string") {
|
|
231
304
|
return bad("toolName must be a string or null when present", "toolName");
|
|
232
305
|
}
|
|
233
|
-
|
|
306
|
+
const toolCallId = own(r, "toolCallId");
|
|
307
|
+
if (!isAbsent(toolCallId) && toolCallId !== null && typeof toolCallId !== "string") {
|
|
234
308
|
return bad("toolCallId must be a string or null when present", "toolCallId");
|
|
235
309
|
}
|
|
236
|
-
if (!optionalString(r
|
|
310
|
+
if (!optionalString(own(r, "message")))
|
|
237
311
|
return bad("message must be a string when present", "message");
|
|
238
|
-
|
|
239
|
-
|
|
312
|
+
const toctouBinding = own(r, "toctouBinding");
|
|
313
|
+
if (!isAbsent(toctouBinding)) {
|
|
314
|
+
const verdict = checkToctouBinding(toctouBinding);
|
|
240
315
|
if (verdict !== true)
|
|
241
316
|
return verdict;
|
|
242
317
|
}
|
|
243
|
-
|
|
318
|
+
const createdAtMs = own(r, "createdAtMs");
|
|
319
|
+
if (!isAbsent(createdAtMs) && typeof createdAtMs !== "number") {
|
|
244
320
|
return bad("createdAtMs must be a number (epoch ms) when present", "createdAtMs");
|
|
245
321
|
}
|
|
246
322
|
return true;
|
|
247
|
-
};
|
|
323
|
+
});
|
|
248
324
|
export function isToolPermissionRequest(r) {
|
|
249
325
|
return checkToolPermissionRequest(r) === true;
|
|
250
326
|
}
|
|
251
|
-
const checkLaneProof = (v, field) => {
|
|
327
|
+
const checkLaneProof = seatCheckAt((v, field) => {
|
|
252
328
|
if (!isObject(v))
|
|
253
329
|
return bad("laneProof must be an object", field);
|
|
254
|
-
const lane = v
|
|
330
|
+
const lane = own(v, "lane");
|
|
255
331
|
if (typeof lane !== "string" || !inTuple(LANE_PROOF_LANE_TUPLE, lane)) {
|
|
256
332
|
return bad(`laneProof.lane must be one of ${LANE_PROOF_LANE_TUPLE.join("|")}`, `${field}.lane`);
|
|
257
333
|
}
|
|
258
|
-
if (lane === "subagent" && typeof v
|
|
334
|
+
if (lane === "subagent" && typeof own(v, "parentToolCallId") !== "string") {
|
|
259
335
|
return bad("subagent laneProof needs parentToolCallId", `${field}.parentToolCallId`);
|
|
260
336
|
}
|
|
261
|
-
if (lane === "workflow" && (typeof v
|
|
337
|
+
if (lane === "workflow" && (typeof own(v, "via") !== "string" || typeof own(v, "key") !== "string")) {
|
|
262
338
|
return bad("workflow laneProof needs via + key", `${field}.via`);
|
|
263
339
|
}
|
|
264
340
|
return true;
|
|
265
|
-
};
|
|
266
|
-
const checkSeatChromeEnvelope = (v, field) => {
|
|
341
|
+
});
|
|
342
|
+
const checkSeatChromeEnvelope = seatCheckAt((v, field) => {
|
|
267
343
|
if (!isObject(v))
|
|
268
344
|
return bad("chrome must be an object", field);
|
|
269
|
-
const kind = v
|
|
345
|
+
const kind = own(v, "kind");
|
|
270
346
|
if (typeof kind !== "string")
|
|
271
347
|
return bad("chrome.kind must be a string", `${field}.kind`);
|
|
272
348
|
if (!inTuple(CHROME_EVENT_KIND_TUPLE, kind)) {
|
|
273
349
|
return bad(`chrome.kind is not a renderer-wired arm (${CHROME_EVENT_KIND_TUPLE.join("|")})`, `${field}.kind`);
|
|
274
350
|
}
|
|
275
|
-
return checkLaneProof(v
|
|
276
|
-
};
|
|
277
|
-
const checkLocalSessionEvent = (v) => {
|
|
351
|
+
return checkLaneProof(own(v, "laneProof"), `${field}.laneProof`);
|
|
352
|
+
});
|
|
353
|
+
const checkLocalSessionEvent = seatCheck((v) => {
|
|
278
354
|
if (!isObject(v))
|
|
279
355
|
return bad("event is not an object");
|
|
280
|
-
const type = v
|
|
356
|
+
const type = own(v, "type");
|
|
281
357
|
if (typeof type !== "string")
|
|
282
358
|
return bad("type must be a string", "type");
|
|
283
359
|
if (!inTuple(SEAT_EVENT_TYPE_TUPLE, type)) {
|
|
284
360
|
return bad(`type is not a registered seat event name (${SEAT_EVENT_TYPE_TUPLE.join("|")})`, "type");
|
|
285
361
|
}
|
|
286
|
-
if (typeof v
|
|
362
|
+
if (typeof own(v, "sessionId") !== "string")
|
|
287
363
|
return bad("sessionId must be a string", "sessionId");
|
|
288
|
-
|
|
364
|
+
const messages = own(v, "messages");
|
|
365
|
+
if (!isAbsent(messages) && !Array.isArray(messages))
|
|
289
366
|
return bad("messages must be an array", "messages");
|
|
290
|
-
if (!optionalString(v
|
|
367
|
+
if (!optionalString(own(v, "error")))
|
|
291
368
|
return bad("error must be a string when present", "error");
|
|
292
|
-
if (!optionalString(v
|
|
369
|
+
if (!optionalString(own(v, "errorCategory")))
|
|
293
370
|
return bad("errorCategory must be a string when present", "errorCategory");
|
|
294
|
-
|
|
371
|
+
const code = own(v, "code");
|
|
372
|
+
if (!isAbsent(code) && typeof code !== "number")
|
|
295
373
|
return bad("code must be a number when present", "code");
|
|
296
|
-
|
|
297
|
-
|
|
374
|
+
const request = own(v, "request");
|
|
375
|
+
if (!isAbsent(request)) {
|
|
376
|
+
const verdict = checkToolPermissionRequest(request);
|
|
298
377
|
if (verdict !== true)
|
|
299
378
|
return nested("request", verdict);
|
|
300
379
|
}
|
|
301
|
-
if (!optionalString(v
|
|
380
|
+
if (!optionalString(own(v, "data")))
|
|
302
381
|
return bad("data must be a string when present", "data");
|
|
303
|
-
|
|
304
|
-
|
|
382
|
+
const sources = own(v, "sources");
|
|
383
|
+
if (!isAbsent(sources)) {
|
|
384
|
+
const okSources = Array.isArray(sources) && ownItems(sources).every((t) => typeof t === "string");
|
|
305
385
|
if (!okSources)
|
|
306
386
|
return bad("sources must be a string[]", "sources");
|
|
307
387
|
}
|
|
308
|
-
|
|
309
|
-
|
|
388
|
+
const mode = own(v, "permissionMode");
|
|
389
|
+
if (!isAbsent(mode)) {
|
|
310
390
|
if (typeof mode !== "string" || !inTuple(PERMISSION_MODE_INTENTS, mode)) {
|
|
311
391
|
return bad(`permissionMode must be one of ${PERMISSION_MODE_INTENTS.join("|")}`, "permissionMode");
|
|
312
392
|
}
|
|
313
393
|
}
|
|
314
|
-
|
|
315
|
-
|
|
394
|
+
const session = own(v, "session");
|
|
395
|
+
if (!isAbsent(session)) {
|
|
396
|
+
const verdict = checkLocalSessionRecord(session);
|
|
316
397
|
if (verdict !== true)
|
|
317
398
|
return nested("session", verdict);
|
|
318
399
|
}
|
|
319
|
-
if (!optionalString(v
|
|
400
|
+
if (!optionalString(own(v, "userMessageUuid")))
|
|
320
401
|
return bad("userMessageUuid must be a string when present", "userMessageUuid");
|
|
321
|
-
|
|
402
|
+
const hasPreClearSession = own(v, "hasPreClearSession");
|
|
403
|
+
if (!isAbsent(hasPreClearSession) && typeof hasPreClearSession !== "boolean") {
|
|
322
404
|
return bad("hasPreClearSession must be a boolean when present", "hasPreClearSession");
|
|
323
405
|
}
|
|
324
|
-
if (!optionalString(v
|
|
406
|
+
if (!optionalString(own(v, "requestId")))
|
|
325
407
|
return bad("requestId must be a string when present", "requestId");
|
|
326
|
-
|
|
408
|
+
const outcome = own(v, "outcome");
|
|
409
|
+
if (!optionalString(outcome))
|
|
327
410
|
return bad("outcome must be a string when present", "outcome");
|
|
328
|
-
|
|
329
|
-
|
|
411
|
+
const parked = own(v, "parked");
|
|
412
|
+
if (!isAbsent(parked)) {
|
|
413
|
+
if (parked !== true)
|
|
414
|
+
return bad("parked must be the literal true when present (absent = no park evidence)", "parked");
|
|
415
|
+
if (type !== "tool_permission_resolved" || outcome !== "expired") {
|
|
416
|
+
return bad('parked is only allowed on a tool_permission_resolved event whose outcome is "expired"', "parked");
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
const chrome = own(v, "chrome");
|
|
420
|
+
if (!isAbsent(chrome)) {
|
|
421
|
+
const verdict = checkSeatChromeEnvelope(chrome, "chrome");
|
|
330
422
|
if (verdict !== true)
|
|
331
423
|
return nested("chrome", verdict);
|
|
332
424
|
}
|
|
333
425
|
return true;
|
|
334
|
-
};
|
|
426
|
+
});
|
|
335
427
|
export function isLocalSessionEvent(v) {
|
|
336
428
|
return checkLocalSessionEvent(v) === true;
|
|
337
429
|
}
|
|
338
|
-
const checkAttachmentUploadReceipt = (v) => {
|
|
430
|
+
const checkAttachmentUploadReceipt = seatCheck((v) => {
|
|
339
431
|
if (!isObject(v))
|
|
340
432
|
return bad("upload receipt is not an object");
|
|
341
|
-
if (typeof v
|
|
433
|
+
if (typeof own(v, "id") !== "string")
|
|
342
434
|
return bad("id must be a string", "id");
|
|
343
|
-
if (typeof v
|
|
435
|
+
if (typeof own(v, "name") !== "string")
|
|
344
436
|
return bad("name must be a string", "name");
|
|
345
|
-
if (typeof v
|
|
437
|
+
if (typeof own(v, "mime") !== "string")
|
|
346
438
|
return bad("mime must be a string", "mime");
|
|
347
|
-
if (typeof v
|
|
439
|
+
if (typeof own(v, "sha256") !== "string")
|
|
348
440
|
return bad("sha256 must be a string", "sha256");
|
|
349
|
-
if (typeof v
|
|
441
|
+
if (typeof own(v, "sizeBytes") !== "number")
|
|
350
442
|
return bad("sizeBytes must be a number", "sizeBytes");
|
|
351
443
|
return true;
|
|
352
|
-
};
|
|
444
|
+
});
|
|
353
445
|
export function isAttachmentUploadReceipt(v) {
|
|
354
446
|
return checkAttachmentUploadReceipt(v) === true;
|
|
355
447
|
}
|
|
356
|
-
const
|
|
357
|
-
if (!isObject(m))
|
|
358
|
-
return bad(`models[${index}] is not an object`, "models");
|
|
359
|
-
if (typeof m.id !== "string")
|
|
360
|
-
return bad(`models[${index}].id must be a string`, "models");
|
|
361
|
-
if (!optionalString(m.name))
|
|
362
|
-
return bad(`models[${index}].name must be a string when present`, "models");
|
|
363
|
-
if (!optionalString(m.provider))
|
|
364
|
-
return bad(`models[${index}].provider must be a string when present`, "models");
|
|
365
|
-
if (!isAbsent(m.contextWindow) && typeof m.contextWindow !== "number") {
|
|
366
|
-
return bad(`models[${index}].contextWindow must be a number when present`, "models");
|
|
367
|
-
}
|
|
368
|
-
if (!isAbsent(m.maxOutputTokens) && typeof m.maxOutputTokens !== "number") {
|
|
369
|
-
return bad(`models[${index}].maxOutputTokens must be a number when present`, "models");
|
|
370
|
-
}
|
|
371
|
-
return true;
|
|
372
|
-
};
|
|
373
|
-
const checkApplyModelConfigResult = (v) => {
|
|
448
|
+
const checkApplyModelConfigResult = seatCheck((v) => {
|
|
374
449
|
if (!isObject(v))
|
|
375
450
|
return bad("applyModelConfig result is not an object");
|
|
376
|
-
|
|
451
|
+
const ok = own(v, "ok");
|
|
452
|
+
if (typeof ok !== "boolean")
|
|
377
453
|
return bad("ok must be a boolean", "ok");
|
|
378
|
-
if (typeof v
|
|
454
|
+
if (typeof own(v, "requiresRestart") !== "boolean")
|
|
379
455
|
return bad("requiresRestart must be a boolean", "requiresRestart");
|
|
380
|
-
|
|
456
|
+
const reason = own(v, "reason");
|
|
457
|
+
if (ok === false && (typeof reason !== "string" || reason.length === 0)) {
|
|
381
458
|
return bad("reason must be a non-empty string when ok is false", "reason");
|
|
382
459
|
}
|
|
383
|
-
if (
|
|
460
|
+
if (reason !== undefined && typeof reason !== "string")
|
|
384
461
|
return bad("reason must be a string when present", "reason");
|
|
385
462
|
return true;
|
|
386
|
-
};
|
|
387
|
-
const
|
|
388
|
-
if (!isObject(v))
|
|
463
|
+
});
|
|
464
|
+
const checkLiveModelCatalog = seatCheck((v) => {
|
|
465
|
+
if (!isObject(v) || Array.isArray(v))
|
|
389
466
|
return bad("model catalog is not an object");
|
|
390
|
-
const models = v
|
|
467
|
+
const models = own(v, "models");
|
|
391
468
|
if (!Array.isArray(models))
|
|
392
469
|
return bad("models must be an array", "models");
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
470
|
+
const rows = ownItems(models);
|
|
471
|
+
const names = new Set();
|
|
472
|
+
for (let i = 0; i < rows.length; i += 1) {
|
|
473
|
+
const row = liveModelRowCopy(rows[i]);
|
|
474
|
+
if (row === undefined)
|
|
475
|
+
return bad(`models[${i}] is not a catalog row (an object whose name is a non-empty string, JSON values only)`, `models[${i}]`);
|
|
476
|
+
if (names.has(row.name))
|
|
477
|
+
return bad(`models[${i}] repeats the name of an earlier row`, `models[${i}].name`);
|
|
478
|
+
names.add(row.name);
|
|
479
|
+
}
|
|
480
|
+
const dflt = own(v, "default");
|
|
481
|
+
if (typeof dflt !== "string" || dflt.length === 0)
|
|
482
|
+
return bad("default must be a non-empty string", "default");
|
|
483
|
+
const defaultModel = own(v, "defaultModel");
|
|
484
|
+
if (!isAbsent(defaultModel) && liveDefaultModelCopy(defaultModel) === undefined) {
|
|
485
|
+
return bad("defaultModel must be {id: non-empty string, name?: non-empty string} when present", "defaultModel");
|
|
397
486
|
}
|
|
398
|
-
if (!optionalString(v.defaultId))
|
|
399
|
-
return bad("defaultId must be a string when present", "defaultId");
|
|
400
487
|
return true;
|
|
401
|
-
};
|
|
402
|
-
|
|
403
|
-
|
|
488
|
+
});
|
|
489
|
+
const checkSeatRewindIntent = seatCheck((v) => {
|
|
490
|
+
if (!isObject(v) || Array.isArray(v))
|
|
491
|
+
return bad("rewind must be an object {mode, targetMessageUuid}");
|
|
492
|
+
for (const k of Object.keys(v)) {
|
|
493
|
+
if (!inTuple(SEAT_REWIND_INTENT_KEYS, k))
|
|
494
|
+
return bad(`unknown key (closed shape: ${SEAT_REWIND_INTENT_KEYS.join(", ")})`, k);
|
|
495
|
+
}
|
|
496
|
+
const mode = own(v, "mode");
|
|
497
|
+
if (typeof mode !== "string" || !inTuple(REWIND_MODES, mode))
|
|
498
|
+
return bad(`mode must be one of ${REWIND_MODES.join("|")}`, "mode");
|
|
499
|
+
const target = own(v, "targetMessageUuid");
|
|
500
|
+
if (typeof target !== "string" || target.length === 0) {
|
|
501
|
+
return bad("targetMessageUuid must be a non-empty string", "targetMessageUuid");
|
|
502
|
+
}
|
|
503
|
+
return true;
|
|
504
|
+
});
|
|
505
|
+
const checkSeatTurnSettings = seatCheck((v) => {
|
|
506
|
+
if (!isObject(v) || Array.isArray(v))
|
|
507
|
+
return bad("settings must be an object");
|
|
508
|
+
for (const k of Object.keys(v)) {
|
|
509
|
+
if (!inTuple(SEAT_TURN_SETTINGS_KEYS, k)) {
|
|
510
|
+
const host = Object.hasOwn(SEAT_TURN_SETTINGS_ORIGINS, k);
|
|
511
|
+
return bad(host ? "this settings key is supplied by the host, not carried by the seat" : `unknown key (closed shape: ${SEAT_TURN_SETTINGS_KEYS.join(", ")})`, k);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
const ultracode = own(v, "ultracode");
|
|
515
|
+
if (!isAbsent(ultracode) && typeof ultracode !== "boolean")
|
|
516
|
+
return bad("ultracode must be a boolean when present", "ultracode");
|
|
517
|
+
return true;
|
|
518
|
+
});
|
|
519
|
+
const checkRetainSubagentSessions = seatCheck((v) => {
|
|
520
|
+
if (typeof v === "boolean")
|
|
521
|
+
return true;
|
|
522
|
+
if (!isObject(v) || Array.isArray(v))
|
|
523
|
+
return bad("retainSubagentSessions must be a boolean or {ttlMs?, max?}");
|
|
524
|
+
for (const k of Object.keys(v)) {
|
|
525
|
+
if (k !== "ttlMs" && k !== "max")
|
|
526
|
+
return bad("unknown key (closed shape: ttlMs, max)", k);
|
|
527
|
+
const n = own(v, k);
|
|
528
|
+
if (!isAbsent(n) && (typeof n !== "number" || !Number.isSafeInteger(n) || n < 0))
|
|
529
|
+
return bad(`${k} must be a non-negative integer when present`, k);
|
|
530
|
+
}
|
|
531
|
+
return true;
|
|
532
|
+
});
|
|
533
|
+
export function checkSendMessageRequest(v) {
|
|
534
|
+
try {
|
|
535
|
+
if (!isObject(v) || Array.isArray(v))
|
|
536
|
+
return bad("sendMessage request is not an object");
|
|
537
|
+
const at = firstAccessorPath(v);
|
|
538
|
+
if (at !== undefined)
|
|
539
|
+
return bad(NOT_PLAIN_DATA, at);
|
|
540
|
+
const body = {};
|
|
541
|
+
for (const k of Object.keys(v)) {
|
|
542
|
+
if (!inTuple(SEND_MESSAGE_REQUEST_KEYS, k))
|
|
543
|
+
return bad(`unknown key (closed shape: ${SEND_MESSAGE_REQUEST_KEYS.join(", ")})`, k);
|
|
544
|
+
body[k] = own(v, k);
|
|
545
|
+
}
|
|
546
|
+
if (typeof body.sessionId !== "string" || body.sessionId.length === 0)
|
|
547
|
+
return bad("sessionId must be a non-empty string", "sessionId");
|
|
548
|
+
if (typeof body.text !== "string")
|
|
549
|
+
return bad("text must be a string", "text");
|
|
550
|
+
if (!optionalString(body.model))
|
|
551
|
+
return bad("model must be a string when present", "model");
|
|
552
|
+
if (!optionalString(body.userMessageUuid))
|
|
553
|
+
return bad("userMessageUuid must be a string when present", "userMessageUuid");
|
|
554
|
+
if (!isAbsent(body.permissionMode) && (typeof body.permissionMode !== "string" || !inTuple(PERMISSION_MODE_INTENTS, body.permissionMode))) {
|
|
555
|
+
return bad(`permissionMode must be one of ${PERMISSION_MODE_INTENTS.join("|")}`, "permissionMode");
|
|
556
|
+
}
|
|
557
|
+
if (!isAbsent(body.attachmentIds)) {
|
|
558
|
+
const raw = body.attachmentIds;
|
|
559
|
+
const ids = Array.isArray(raw) ? ownItems(raw) : undefined;
|
|
560
|
+
if (ids === undefined || !ids.every((id) => typeof id === "string" && id.length > 0)) {
|
|
561
|
+
return bad("attachmentIds must be an array of non-empty attachment ids", "attachmentIds");
|
|
562
|
+
}
|
|
563
|
+
if (ids.length > ATTACHMENT_IDS_PER_TASK_CAP)
|
|
564
|
+
return bad(`attachmentIds exceeds the per-task limit (${ATTACHMENT_IDS_PER_TASK_CAP})`, "attachmentIds");
|
|
565
|
+
}
|
|
566
|
+
if (!isAbsent(body.reasoningEffort) && (typeof body.reasoningEffort !== "string" || !inTuple(SEAT_REASONING_EFFORTS, body.reasoningEffort))) {
|
|
567
|
+
return bad(`reasoningEffort must be one of ${SEAT_REASONING_EFFORTS.join("|")}`, "reasoningEffort");
|
|
568
|
+
}
|
|
569
|
+
for (const k of ["retainBackgroundProcesses", "forwardSubagentEvents"]) {
|
|
570
|
+
if (!isAbsent(body[k]) && typeof body[k] !== "boolean")
|
|
571
|
+
return bad(`${k} must be a boolean when present`, k);
|
|
572
|
+
}
|
|
573
|
+
if (!isAbsent(body.retainSubagentSessions)) {
|
|
574
|
+
const verdict = checkRetainSubagentSessions(body.retainSubagentSessions);
|
|
575
|
+
if (verdict !== true)
|
|
576
|
+
return nested("retainSubagentSessions", verdict);
|
|
577
|
+
}
|
|
578
|
+
if (!isAbsent(body.settings)) {
|
|
579
|
+
const verdict = checkSeatTurnSettings(body.settings);
|
|
580
|
+
if (verdict !== true)
|
|
581
|
+
return nested("settings", verdict);
|
|
582
|
+
}
|
|
583
|
+
if (!optionalString(body.scenario))
|
|
584
|
+
return bad("scenario must be a string when present", "scenario");
|
|
585
|
+
if (!isAbsent(body.rewind)) {
|
|
586
|
+
const verdict = checkSeatRewindIntent(body.rewind);
|
|
587
|
+
if (verdict !== true)
|
|
588
|
+
return nested("rewind", verdict);
|
|
589
|
+
}
|
|
590
|
+
return true;
|
|
591
|
+
}
|
|
592
|
+
catch (e) {
|
|
593
|
+
const key = ownDataRefusalKeyOf(e);
|
|
594
|
+
return key !== undefined ? bad(NOT_PLAIN_DATA, key) : bad("sendMessage request could not be read");
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
export function isSendMessageRequest(v) {
|
|
598
|
+
return checkSendMessageRequest(v) === true;
|
|
404
599
|
}
|
|
405
|
-
const checkSendMessageAck = (v) => {
|
|
600
|
+
const checkSendMessageAck = seatCheck((v) => {
|
|
406
601
|
if (!isObject(v))
|
|
407
602
|
return bad("sendMessage ack is not an object");
|
|
408
|
-
if (typeof v
|
|
603
|
+
if (typeof own(v, "sessionId") !== "string")
|
|
409
604
|
return bad("sessionId must be a string", "sessionId");
|
|
410
|
-
if (typeof v
|
|
605
|
+
if (typeof own(v, "userMessageUuid") !== "string")
|
|
411
606
|
return bad("userMessageUuid must be a string", "userMessageUuid");
|
|
412
|
-
|
|
607
|
+
const queued = own(v, "queued");
|
|
608
|
+
if (!isAbsent(queued) && typeof queued !== "boolean")
|
|
413
609
|
return bad("queued must be a boolean when present", "queued");
|
|
414
610
|
return true;
|
|
415
|
-
};
|
|
611
|
+
});
|
|
416
612
|
export function isSendMessageAck(v) {
|
|
417
613
|
return checkSendMessageAck(v) === true;
|
|
418
614
|
}
|
|
419
|
-
const checkInterruptAck = (v) => isObject(v) && typeof v
|
|
420
|
-
const checkStopAck = (v) => isObject(v) && typeof v
|
|
421
|
-
const checkOkAck = (v) => isObject(v) && typeof v
|
|
615
|
+
const checkInterruptAck = seatCheck((v) => isObject(v) && typeof own(v, "interrupted") === "boolean" ? true : bad("interrupt ack needs boolean `interrupted`", "interrupted"));
|
|
616
|
+
const checkStopAck = seatCheck((v) => isObject(v) && typeof own(v, "stopped") === "boolean" ? true : bad("stop ack needs boolean `stopped`", "stopped"));
|
|
617
|
+
const checkOkAck = seatCheck((v) => isObject(v) && typeof own(v, "ok") === "boolean" ? true : bad("ack needs boolean `ok`", "ok"));
|
|
422
618
|
const checkBooleanAck = (v) => typeof v === "boolean" ? true : bad("expected a bare boolean result");
|
|
423
|
-
const checkGetTranscriptResult = (v) => {
|
|
619
|
+
const checkGetTranscriptResult = seatCheck((v) => {
|
|
424
620
|
if (!isObject(v))
|
|
425
621
|
return bad("transcript envelope is not an object");
|
|
426
|
-
if (typeof v
|
|
622
|
+
if (typeof own(v, "sessionId") !== "string")
|
|
427
623
|
return bad("sessionId must be a string", "sessionId");
|
|
428
|
-
if (!Array.isArray(v
|
|
624
|
+
if (!Array.isArray(own(v, "messages")))
|
|
429
625
|
return bad("messages must be an array", "messages");
|
|
430
626
|
return true;
|
|
431
|
-
};
|
|
432
|
-
const checkSessionSearchResult = (v) => {
|
|
627
|
+
});
|
|
628
|
+
const checkSessionSearchResult = seatCheck((v) => {
|
|
433
629
|
if (!isObject(v))
|
|
434
630
|
return bad("search result row is not an object");
|
|
435
|
-
if (typeof v
|
|
631
|
+
if (typeof own(v, "sessionId") !== "string")
|
|
436
632
|
return bad("sessionId must be a string", "sessionId");
|
|
437
|
-
if (!optionalString(v
|
|
633
|
+
if (!optionalString(own(v, "title")))
|
|
438
634
|
return bad("title must be a string when present", "title");
|
|
439
|
-
|
|
635
|
+
const matches = own(v, "matches");
|
|
636
|
+
if (!Array.isArray(matches))
|
|
440
637
|
return bad("matches must be an array", "matches");
|
|
441
|
-
const okMatches =
|
|
638
|
+
const okMatches = ownItems(matches).every((m) => isObject(m) && typeof own(m, "snippet") === "string");
|
|
442
639
|
if (!okMatches)
|
|
443
640
|
return bad("matches must be {snippet:string}[]", "matches");
|
|
444
641
|
return true;
|
|
445
|
-
};
|
|
446
|
-
const checkSessionSearchEnvelope = (v) => {
|
|
642
|
+
});
|
|
643
|
+
const checkSessionSearchEnvelope = seatCheck((v) => {
|
|
447
644
|
if (!isObject(v))
|
|
448
645
|
return bad("search envelope is not an object");
|
|
449
|
-
const results = v
|
|
646
|
+
const results = own(v, "results");
|
|
450
647
|
if (!Array.isArray(results))
|
|
451
648
|
return bad("results must be an array", "results");
|
|
452
|
-
|
|
453
|
-
|
|
649
|
+
const rows = ownItems(results);
|
|
650
|
+
for (let i = 0; i < rows.length; i += 1) {
|
|
651
|
+
const verdict = checkSessionSearchResult(rows[i]);
|
|
454
652
|
if (verdict !== true)
|
|
455
653
|
return nested(`results[${i}]`, verdict);
|
|
456
654
|
}
|
|
457
655
|
return true;
|
|
458
|
-
};
|
|
459
|
-
const checkSessionsState = (v) => {
|
|
656
|
+
});
|
|
657
|
+
const checkSessionsState = seatCheck((v) => {
|
|
460
658
|
if (!isObject(v))
|
|
461
659
|
return bad("sessions state is not an object");
|
|
462
|
-
const sessions = v
|
|
660
|
+
const sessions = own(v, "sessions");
|
|
463
661
|
if (!Array.isArray(sessions))
|
|
464
662
|
return bad("sessions must be an array", "sessions");
|
|
465
|
-
|
|
466
|
-
|
|
663
|
+
const rows = ownItems(sessions);
|
|
664
|
+
for (let i = 0; i < rows.length; i += 1) {
|
|
665
|
+
const verdict = checkLocalSessionRecord(rows[i]);
|
|
467
666
|
if (verdict !== true)
|
|
468
667
|
return nested(`sessions[${i}]`, verdict);
|
|
469
668
|
}
|
|
470
669
|
return true;
|
|
471
|
-
};
|
|
472
|
-
const checkFocusedSessionState = (v) => {
|
|
670
|
+
});
|
|
671
|
+
const checkFocusedSessionState = seatCheck((v) => {
|
|
473
672
|
if (!isObject(v))
|
|
474
673
|
return bad("focused session state is not an object");
|
|
475
|
-
|
|
674
|
+
const sessionId = own(v, "sessionId");
|
|
675
|
+
if (sessionId !== null && typeof sessionId !== "string") {
|
|
476
676
|
return bad("sessionId must be a string or null", "sessionId");
|
|
477
677
|
}
|
|
478
678
|
return true;
|
|
479
|
-
};
|
|
480
|
-
const checkSettingsState = (v) => {
|
|
679
|
+
});
|
|
680
|
+
const checkSettingsState = seatCheck((v) => {
|
|
481
681
|
if (!isObject(v))
|
|
482
682
|
return bad("settings state is not an object");
|
|
483
|
-
|
|
683
|
+
const defaultModel = own(v, "defaultModel");
|
|
684
|
+
if (defaultModel !== null && typeof defaultModel !== "string") {
|
|
484
685
|
return bad("defaultModel must be a string or null", "defaultModel");
|
|
485
686
|
}
|
|
486
|
-
if (!optionalString(v
|
|
687
|
+
if (!optionalString(own(v, "engineVersion")))
|
|
487
688
|
return bad("engineVersion must be a string when present", "engineVersion");
|
|
488
|
-
if (!optionalString(v
|
|
689
|
+
if (!optionalString(own(v, "dataRoot")))
|
|
489
690
|
return bad("dataRoot must be a string when present", "dataRoot");
|
|
490
691
|
return true;
|
|
491
|
-
};
|
|
692
|
+
});
|
|
492
693
|
const checkPickFolderResult = (v) => v === null || (typeof v === "string" && v.length > 0)
|
|
493
694
|
? true
|
|
494
695
|
: bad("pickFolder result must be null (cancelled) or a non-empty path string");
|
|
495
|
-
const checkSeatCapabilitiesState = (v) => {
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
return bad(`${name} is not a registered seat capability (${SEAT_CAPABILITY_NAMES.join("|")})`, name);
|
|
506
|
-
}
|
|
507
|
-
const desc = Object.getOwnPropertyDescriptor(v, k);
|
|
508
|
-
if (desc === undefined || !("value" in desc))
|
|
509
|
-
return bad(`${k} must be a plain data property (accessors are refused)`, k);
|
|
510
|
-
if (!isAbsent(desc.value) && typeof desc.value !== "boolean")
|
|
511
|
-
return bad(`${k} must be a boolean when present`, k);
|
|
696
|
+
const checkSeatCapabilitiesState = seatCheck((v) => {
|
|
697
|
+
if (!isObject(v) || Array.isArray(v))
|
|
698
|
+
return bad("seat capabilities state is not an object");
|
|
699
|
+
const proto = Object.getPrototypeOf(v);
|
|
700
|
+
if (proto !== Object.prototype && proto !== null)
|
|
701
|
+
return bad("seat capabilities state is not a plain object");
|
|
702
|
+
for (const k of Reflect.ownKeys(v)) {
|
|
703
|
+
const name = typeof k === "string" ? k : String(k);
|
|
704
|
+
if (typeof k !== "string" || !inTuple(SEAT_CAPABILITY_NAMES, k)) {
|
|
705
|
+
return bad(`${name} is not a registered seat capability (${SEAT_CAPABILITY_NAMES.join("|")})`, name);
|
|
512
706
|
}
|
|
513
|
-
|
|
707
|
+
const value = own(v, k);
|
|
708
|
+
if (!isAbsent(value) && typeof value !== "boolean")
|
|
709
|
+
return bad(`${k} must be a boolean when present`, k);
|
|
514
710
|
}
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
}
|
|
518
|
-
};
|
|
711
|
+
return true;
|
|
712
|
+
});
|
|
519
713
|
export const LOCAL_SESSIONS_SPEC = {
|
|
520
714
|
ns: "sema.web",
|
|
521
715
|
service: "LocalSessions",
|
|
@@ -533,7 +727,7 @@ export const LOCAL_SESSIONS_SPEC = {
|
|
|
533
727
|
getTranscript: { kind: "invoke", check: checkGetTranscriptResult },
|
|
534
728
|
searchSessions: { kind: "invoke", check: checkSessionSearchEnvelope },
|
|
535
729
|
uploadAttachment: { kind: "invoke", check: checkAttachmentUploadReceipt },
|
|
536
|
-
listModels: { kind: "invoke", check:
|
|
730
|
+
listModels: { kind: "invoke", check: checkLiveModelCatalog },
|
|
537
731
|
applyModelConfig: { kind: "invoke", check: checkApplyModelConfigResult },
|
|
538
732
|
pickFolder: { kind: "invoke", check: checkPickFolderResult },
|
|
539
733
|
onEvent: { kind: "event", check: checkLocalSessionEvent },
|
|
@@ -590,6 +784,7 @@ export const LOCAL_SESSION_EVENT_KEYS = [
|
|
|
590
784
|
"hasPreClearSession",
|
|
591
785
|
"requestId",
|
|
592
786
|
"outcome",
|
|
787
|
+
"parked",
|
|
593
788
|
"chrome",
|
|
594
789
|
];
|
|
595
790
|
export const TOOL_PERMISSION_REQUEST_KEYS = [
|
|
@@ -635,6 +830,7 @@ export const SEND_MESSAGE_REQUEST_KEYS = [
|
|
|
635
830
|
"retainSubagentSessions",
|
|
636
831
|
"settings",
|
|
637
832
|
"scenario",
|
|
833
|
+
"rewind",
|
|
638
834
|
];
|
|
639
835
|
export const SEAT_SEND_MESSAGE_KEY_ORIGINS = {
|
|
640
836
|
sessionId: { seatOnly: "座位会话句柄(渲染端持有的本地 id);引擎会话 id 由座位记录的 `engineSessionId` 承载 —— 与引擎请求体上的同名位**同名不同义**,绝不直传" },
|
|
@@ -649,6 +845,7 @@ export const SEAT_SEND_MESSAGE_KEY_ORIGINS = {
|
|
|
649
845
|
retainSubagentSessions: { taskRequestKey: "retainSubagentSessions" },
|
|
650
846
|
settings: { taskRequestKey: "settings" },
|
|
651
847
|
scenario: { taskRequestKey: "scenario" },
|
|
848
|
+
rewind: { projectedBy: "rewindSpecForMode", taskRequestKeys: ["resumeAt", "resumeAtMode", "restoreFiles", "rewindFilesTo"] },
|
|
652
849
|
};
|
|
653
850
|
export const TOOL_PERMISSION_DECISION_KEYS = [
|
|
654
851
|
"sessionId",
|
|
@@ -728,6 +925,7 @@ export const SEAT_VALIDATOR_KEY_COVERAGE = {
|
|
|
728
925
|
"hasPreClearSession",
|
|
729
926
|
"requestId",
|
|
730
927
|
"outcome",
|
|
928
|
+
"parked",
|
|
731
929
|
"chrome",
|
|
732
930
|
],
|
|
733
931
|
unchecked: [
|
|
@@ -743,10 +941,34 @@ export const SEAT_VALIDATOR_KEY_COVERAGE = {
|
|
|
743
941
|
validated: ["id", "name", "mime", "sha256", "sizeBytes"],
|
|
744
942
|
unchecked: [],
|
|
745
943
|
},
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
944
|
+
LiveModelCatalog: {
|
|
945
|
+
check: checkLiveModelCatalog,
|
|
946
|
+
validated: ["models", "default", "defaultModel"],
|
|
947
|
+
unchecked: [
|
|
948
|
+
{
|
|
949
|
+
key: "droppedEntries",
|
|
950
|
+
why: "诊断面(哪些目录条目没被引擎收下),三态读法归 droppedModelEntriesOf(含坏形 malformed);出站门为它拒掉整份目录 = 选单为一行诊断整个消失。",
|
|
951
|
+
},
|
|
952
|
+
],
|
|
953
|
+
},
|
|
954
|
+
SendMessageRequest: {
|
|
955
|
+
guard: "isSendMessageRequest",
|
|
956
|
+
check: checkSendMessageRequest,
|
|
957
|
+
validated: [
|
|
958
|
+
"sessionId",
|
|
959
|
+
"text",
|
|
960
|
+
"model",
|
|
961
|
+
"userMessageUuid",
|
|
962
|
+
"permissionMode",
|
|
963
|
+
"attachmentIds",
|
|
964
|
+
"reasoningEffort",
|
|
965
|
+
"retainBackgroundProcesses",
|
|
966
|
+
"forwardSubagentEvents",
|
|
967
|
+
"retainSubagentSessions",
|
|
968
|
+
"settings",
|
|
969
|
+
"scenario",
|
|
970
|
+
"rewind",
|
|
971
|
+
],
|
|
750
972
|
unchecked: [],
|
|
751
973
|
},
|
|
752
974
|
ApplyModelConfigResult: {
|
|
@@ -802,12 +1024,12 @@ export const SEAT_VALIDATOR_KEY_COVERAGE = {
|
|
|
802
1024
|
},
|
|
803
1025
|
SeatCapabilitiesState: {
|
|
804
1026
|
check: checkSeatCapabilitiesState,
|
|
805
|
-
validated: ["pickFolder"],
|
|
1027
|
+
validated: ["pickFolder", "rewind"],
|
|
806
1028
|
unchecked: [],
|
|
807
1029
|
},
|
|
808
|
-
|
|
809
|
-
check:
|
|
810
|
-
validated: ["
|
|
1030
|
+
SeatRewindIntent: {
|
|
1031
|
+
check: checkSeatRewindIntent,
|
|
1032
|
+
validated: ["mode", "targetMessageUuid"],
|
|
811
1033
|
unchecked: [],
|
|
812
1034
|
},
|
|
813
1035
|
SessionSearchResult: {
|
|
@@ -864,5 +1086,6 @@ const _seatContractPins = [
|
|
|
864
1086
|
true, true, true, true, true, true, true, true,
|
|
865
1087
|
true, true, true, true, true, true, true, true,
|
|
866
1088
|
true, true, true, true, true,
|
|
1089
|
+
true, true, true, true, true, true, true, true,
|
|
867
1090
|
];
|
|
868
1091
|
void _seatContractPins;
|