@sema-agent/client-core 0.97.1 → 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 +607 -0
- package/README.md +96 -46
- package/dist/adapt/arms.d.ts +1 -0
- package/dist/adapt/arms.js +188 -53
- package/dist/adapt/ids.d.ts +12 -1
- package/dist/adapt/ids.js +59 -8
- package/dist/adapt/instanceLedger.d.ts +50 -0
- package/dist/adapt/instanceLedger.js +147 -0
- package/dist/adapt/panelTasks.d.ts +1 -1
- package/dist/adapt/panelTasks.js +2 -2
- package/dist/adapt/textStream.d.ts +1 -0
- package/dist/adapt/textStream.js +24 -7
- package/dist/adapt/toolCards.d.ts +27 -5
- package/dist/adapt/toolCards.js +39 -6
- package/dist/adapt/wireShapes.js +6 -2
- package/dist/adapt.d.ts +2 -0
- package/dist/adapt.js +8 -3
- package/dist/adapter/activeRunSelfHeal.d.ts +9 -3
- package/dist/adapter/activeRunSelfHeal.js +205 -313
- package/dist/adapter/downstream/eventToSdkMessage.d.ts +2 -5
- package/dist/adapter/downstream/eventToSdkMessage.js +77 -36
- package/dist/adapter/downstream/terminalToSdkResult.js +11 -4
- package/dist/adapter/downstream/turnUsageToModelUsage.d.ts +5 -2
- package/dist/adapter/downstream/turnUsageToModelUsage.js +2 -0
- package/dist/adapter/runStream.js +79 -48
- package/dist/adapter/types.d.ts +4 -4
- package/dist/adapter/types.js +2 -1
- package/dist/agentSession/backgroundView.js +2 -1
- package/dist/agentSession/engineAgentRegistryRead.d.ts +2 -2
- package/dist/agentSession/engineAgentRegistryRead.js +12 -13
- package/dist/agentSession/engineSessionBackgroundStop.js +16 -8
- package/dist/agentsWireCaps.d.ts +8 -11
- package/dist/agentsWireCaps.js +196 -194
- package/dist/approvalDecidedByCapability.d.ts +0 -4
- package/dist/approvalDecidedByCapability.js +0 -6
- package/dist/approvalsStreamLiveCapability.d.ts +0 -4
- package/dist/approvalsStreamLiveCapability.js +0 -6
- package/dist/assistantInbox.d.ts +34 -0
- package/dist/assistantInbox.js +118 -0
- package/dist/centerWiringCapability.js +9 -1
- package/dist/clientSlice.d.ts +0 -9
- package/dist/clientSlice.js +0 -3
- package/dist/cloudConfigWireCaps.d.ts +5 -3
- package/dist/cloudConfigWireCaps.js +106 -64
- package/dist/compensations.js +1 -1
- package/dist/connectorStatus.d.ts +21 -0
- package/dist/connectorStatus.js +112 -0
- package/dist/controlRouter.d.ts +18 -3
- package/dist/controlRouter.js +106 -67
- package/dist/coreValuePorts.d.ts +29 -4
- package/dist/coreValuePorts.js +10 -0
- package/dist/corruptSessionCopy.d.ts +2 -1
- package/dist/corruptSessionCopy.js +3 -3
- package/dist/decideReceipt.d.ts +2 -2
- package/dist/decideReceipt.js +5 -2
- package/dist/declared/supportFloorDeclared.js +3 -3
- package/dist/detachWire.js +3 -2
- package/dist/deviceExecutorManagementCapability.d.ts +0 -4
- package/dist/deviceExecutorManagementCapability.js +0 -6
- package/dist/deviceRebind.d.ts +49 -1
- package/dist/deviceRebind.js +221 -3
- package/dist/devicesFace.d.ts +34 -0
- package/dist/devicesFace.js +90 -0
- package/dist/displayUntrusted.d.ts +2 -0
- package/dist/displayUntrusted.js +253 -76
- package/dist/engineAgentAbsence.d.ts +1 -1
- package/dist/engineAgentPanelStore.d.ts +12 -4
- package/dist/engineAgentPanelStore.js +16 -11
- package/dist/engineCapReader.d.ts +2 -5
- package/dist/engineCapReader.js +8 -10
- package/dist/engineCapsCache.d.ts +12 -0
- package/dist/engineCapsCache.js +76 -18
- package/dist/engineCapsChange.d.ts +2 -0
- package/dist/engineCapsChange.js +9 -0
- package/dist/engineClosedSets.d.ts +1 -0
- package/dist/engineClosedSets.js +4 -1
- package/dist/engineErrorCodes.d.ts +11 -3
- package/dist/engineErrorCodes.js +11 -8
- package/dist/engineIdentity.d.ts +1 -0
- package/dist/engineIdentity.js +8 -0
- package/dist/engineRowRef.d.ts +28 -0
- package/dist/engineRowRef.js +114 -0
- package/dist/engineSessionMessages.d.ts +68 -0
- package/dist/engineSessionMessages.js +370 -0
- package/dist/engineTargetSeat.d.ts +27 -0
- package/dist/engineTargetSeat.js +199 -0
- package/dist/engineToolDirectory.d.ts +0 -9
- package/dist/engineToolDirectory.js +1 -94
- package/dist/engineUrl.d.ts +18 -0
- package/dist/engineUrl.js +52 -0
- package/dist/engineWireFor.js +3 -8
- package/dist/env/uiLanguage.d.ts +11 -1
- package/dist/env/uiLanguage.js +38 -2
- package/dist/eventLeg.d.ts +100 -0
- package/dist/eventLeg.js +305 -0
- package/dist/executionLaneCapability.d.ts +0 -4
- package/dist/executionLaneCapability.js +3 -16
- package/dist/fileHistoryCaptureCapability.d.ts +2 -5
- package/dist/fileHistoryCaptureCapability.js +13 -21
- package/dist/fileHistoryLegNotice.d.ts +2 -1
- package/dist/fileHistoryLegNotice.js +3 -3
- package/dist/fleet/fleetLedger.d.ts +0 -3
- package/dist/fleet/fleetLedger.js +21 -36
- package/dist/fleet/fleetProjection.d.ts +2 -2
- package/dist/fleet/fleetProjection.js +10 -8
- package/dist/frameBinding.d.ts +8 -0
- package/dist/frameBinding.js +35 -0
- package/dist/gateFailureCodes.d.ts +2 -0
- package/dist/gateFailureCodes.js +15 -0
- package/dist/gateOutcome.d.ts +3 -1
- package/dist/gateOutcome.js +41 -8
- package/dist/gateVocabulary.d.ts +10 -4
- package/dist/gateVocabulary.js +107 -47
- package/dist/generated/engineAskFaceTables.js +2 -2
- package/dist/generated/engineFactTables.d.ts +22 -3
- package/dist/generated/engineFactTables.js +51 -4
- package/dist/generated/engineNoticeTables.js +18 -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/generated/toolNameTables.d.ts +1 -0
- package/dist/generated/toolNameTables.js +1 -0
- package/dist/hitl/allowRuleShadow.d.ts +8 -2
- package/dist/hitl/allowRuleShadow.js +36 -29
- package/dist/hitl/approvalCardReading.d.ts +15 -0
- package/dist/hitl/approvalCardReading.js +154 -0
- package/dist/hitl/approvalCardReasons.d.ts +14 -0
- package/dist/hitl/approvalCardReasons.js +119 -0
- package/dist/hitl/approvalHolds.d.ts +50 -15
- package/dist/hitl/approvalHolds.js +177 -27
- package/dist/hitl/approvalResolution.d.ts +51 -26
- package/dist/hitl/approvalResolution.js +86 -122
- package/dist/hitl/approvalsFeed.js +6 -18
- package/dist/hitl/askClassPair.d.ts +2 -0
- package/dist/hitl/askClassPair.js +17 -0
- package/dist/hitl/askGateWire.d.ts +20 -2
- package/dist/hitl/askGateWire.js +50 -1
- package/dist/hitl/askParkRowRouting.d.ts +5 -0
- package/dist/hitl/askParkRowRouting.js +32 -1
- package/dist/hitl/askSettlementLine.d.ts +28 -0
- package/dist/hitl/askSettlementLine.js +99 -0
- package/dist/hitl/automaticAnswerVerdict.d.ts +3 -2
- package/dist/hitl/automaticAnswerVerdict.js +29 -13
- package/dist/hitl/crashConverged.d.ts +11 -20
- package/dist/hitl/crashConverged.js +56 -0
- package/dist/hitl/crashConvergedNotice.d.ts +6 -3
- package/dist/hitl/crashConvergedNotice.js +48 -24
- package/dist/hitl/decisionConflict.js +3 -10
- package/dist/hitl/decisionRefusal.d.ts +40 -1
- package/dist/hitl/decisionRefusal.js +199 -42
- package/dist/hitl/frameRouter.d.ts +5 -2
- package/dist/hitl/frameRouter.js +27 -24
- package/dist/hitl/gateLedger.d.ts +2 -0
- package/dist/hitl/gateLedger.js +50 -13
- package/dist/hitl/hitlBridge.d.ts +2 -2
- package/dist/hitl/hitlBridge.js +13 -10
- package/dist/hitl/livePendingAsk.d.ts +3 -3
- package/dist/hitl/livePendingAsk.js +7 -18
- package/dist/hitl/parkResolver.d.ts +2 -24
- package/dist/hitl/parkResolver.js +61 -97
- package/dist/hitl/persistedRulesWire.d.ts +25 -0
- package/dist/hitl/persistedRulesWire.js +104 -2
- package/dist/hitl/planReviewWire.d.ts +31 -13
- package/dist/hitl/planReviewWire.js +120 -78
- package/dist/hitl/refusedToolNameProse.d.ts +0 -1
- package/dist/hitl/refusedToolNameProse.js +0 -3
- package/dist/hitl/replayedApproval.d.ts +4 -3
- package/dist/hitl/replayedApproval.js +7 -4
- package/dist/hitl/sessionPolicyDeliverable.d.ts +2 -0
- package/dist/hitl/sessionPolicyDeliverable.js +48 -7
- package/dist/hitl/sessionPolicyWire.d.ts +34 -21
- package/dist/hitl/sessionPolicyWire.js +179 -70
- package/dist/hitl/standingRows.d.ts +20 -2
- package/dist/hitl/standingRows.js +69 -8
- package/dist/hitl/suspendedReopen.d.ts +2 -1
- package/dist/hitl/suspendedReopen.js +7 -10
- package/dist/hitl/toolApprovalWire.d.ts +103 -156
- package/dist/hitl/toolApprovalWire.js +661 -411
- package/dist/hookMatcherVerdict.d.ts +6 -1
- package/dist/hookMatcherVerdict.js +14 -7
- package/dist/hooksWireCaps.d.ts +2 -2
- package/dist/hooksWireCaps.js +174 -81
- 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 +703 -0
- package/dist/i18n/messages.en.js +701 -0
- package/dist/i18n/messages.zh.d.ts +3 -0
- package/dist/i18n/messages.zh.js +837 -0
- package/dist/i18n/translate.d.ts +25 -0
- package/dist/i18n/translate.js +127 -0
- package/dist/index.d.ts +78 -29
- package/dist/index.js +54 -18
- package/dist/inheritEnvCapability.d.ts +32 -0
- package/dist/inheritEnvCapability.js +104 -0
- package/dist/inheritEnvWire.d.ts +3 -2
- package/dist/inheritEnvWire.js +12 -14
- package/dist/interactiveHalt.js +17 -6
- package/dist/liveModelCatalog.d.ts +3 -3
- package/dist/liveModelCatalog.js +15 -13
- package/dist/liveQuestionStore.d.ts +2 -21
- package/dist/mcpLiveness.d.ts +2 -1
- 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 +9 -2
- package/dist/mcpProbeWire.js +6 -1
- package/dist/mcpWireCaps.d.ts +47 -2
- package/dist/mcpWireCaps.js +164 -16
- package/dist/memoryEntriesWire.d.ts +4 -9
- package/dist/memoryEntriesWire.js +5 -10
- package/dist/model/modelSupplyRules.d.ts +0 -2
- package/dist/model/modelSupplyRules.js +3 -12
- package/dist/model/modelsPolicy.d.ts +0 -5
- package/dist/model/modelsPolicy.js +6 -36
- package/dist/model/onboardJudgement.d.ts +93 -0
- package/dist/model/onboardJudgement.js +415 -0
- package/dist/model/subagentModelWord.d.ts +31 -0
- package/dist/model/subagentModelWord.js +261 -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/notifications.d.ts +6 -0
- package/dist/notifications.js +71 -23
- package/dist/outputStyleSeatCapability.d.ts +0 -3
- package/dist/outputStyleSeatCapability.js +0 -3
- package/dist/ownKey.d.ts +22 -0
- package/dist/ownKey.js +94 -3
- package/dist/panelReduce.d.ts +21 -10
- package/dist/panelReduce.js +728 -550
- package/dist/panelStateHolder.d.ts +3 -7
- package/dist/panelStateHolder.js +14 -130
- package/dist/peerLaneCapability.d.ts +0 -4
- package/dist/peerLaneCapability.js +0 -6
- package/dist/permissionRuleIssue.js +2 -0
- package/dist/permissionRulesWriteCapability.d.ts +2 -5
- package/dist/permissionRulesWriteCapability.js +8 -12
- package/dist/permissionWireCaps.d.ts +2 -2
- package/dist/permissionWireCaps.js +2 -0
- package/dist/permissionsAllowGrantCapability.d.ts +0 -4
- package/dist/permissionsAllowGrantCapability.js +0 -6
- package/dist/permissionsDeclaration.d.ts +0 -11
- package/dist/permissionsDeclaration.js +60 -53
- package/dist/pluginHooksWire.d.ts +46 -3
- package/dist/pluginHooksWire.js +219 -16
- package/dist/preemptWire.d.ts +44 -0
- package/dist/preemptWire.js +83 -0
- package/dist/printModelStatus.d.ts +63 -0
- package/dist/printModelStatus.js +155 -0
- package/dist/printToolResultFrame.js +15 -4
- package/dist/replayBody.d.ts +3 -0
- package/dist/replayBody.js +14 -0
- package/dist/request/taskRequest.d.ts +11 -6
- package/dist/request/taskRequest.js +112 -19
- package/dist/resumeRefusalCopy.d.ts +13 -9
- package/dist/resumeRefusalCopy.js +81 -118
- package/dist/retryStatus.d.ts +45 -0
- package/dist/retryStatus.js +185 -1
- package/dist/rewindArchiveCapability.d.ts +0 -4
- package/dist/rewindArchiveCapability.js +2 -10
- package/dist/rewindArchiveReading.d.ts +0 -1
- package/dist/rewindArchiveReading.js +0 -3
- package/dist/runCancelContext.d.ts +2 -1
- package/dist/runCancelContext.js +4 -2
- package/dist/runReattachPolicy.d.ts +31 -0
- package/dist/runReattachPolicy.js +46 -0
- package/dist/runTerminal.d.ts +3 -6
- package/dist/runTerminal.js +8 -9
- package/dist/sandboxWire.d.ts +3 -1
- package/dist/sandboxWire.js +76 -27
- package/dist/scenarioRefusal.d.ts +9 -0
- package/dist/scenarioRefusal.js +111 -0
- package/dist/scenarioWire.js +1 -1
- package/dist/seam.d.ts +48 -2
- package/dist/seam.js +25 -4
- package/dist/seatContract.d.ts +311 -18
- package/dist/seatContract.js +824 -100
- 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 -5
- package/dist/sessionPolicyCapability.js +8 -12
- package/dist/sessionSyncFileHistoryCapability.d.ts +0 -3
- package/dist/sessionSyncFileHistoryCapability.js +0 -3
- package/dist/settingsHooksSalvage.d.ts +44 -0
- package/dist/settingsHooksSalvage.js +211 -0
- package/dist/skillToolListsCapability.d.ts +2 -4
- package/dist/skillToolListsCapability.js +8 -9
- package/dist/sqlEngineCapability.d.ts +0 -4
- package/dist/sqlEngineCapability.js +0 -6
- package/dist/sseIdleTriage.js +3 -2
- package/dist/steerPriorityCapability.d.ts +0 -3
- package/dist/steerPriorityCapability.js +0 -3
- package/dist/streamDrainingLegs.d.ts +4 -0
- package/dist/streamDrainingLegs.js +6 -1
- package/dist/subagent/engineCompactWire.d.ts +0 -1
- package/dist/subagent/engineCompactWire.js +7 -5
- package/dist/subagent/engineSubagentResume.js +15 -9
- package/dist/subagent/engineTaskHandleWire.js +4 -7
- package/dist/subagentContentStore.d.ts +3 -0
- package/dist/subagentContentStore.js +22 -10
- package/dist/submitReopen.d.ts +24 -0
- package/dist/submitReopen.js +75 -0
- package/dist/terminalStatuses.d.ts +3 -0
- package/dist/terminalStatuses.js +10 -2
- package/dist/toolHistoryMismatch.js +3 -2
- package/dist/toolResult.d.ts +10 -1
- package/dist/toolResult.js +34 -6
- package/dist/toolRoster.d.ts +3 -4
- package/dist/toolRoster.js +21 -22
- package/dist/turnFailurePresentation.d.ts +39 -0
- package/dist/turnFailurePresentation.js +402 -0
- 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 -4
- package/dist/userInvokedSkillsCapability.js +31 -10
- package/dist/webSearchBackendCapability.d.ts +0 -4
- package/dist/webSearchBackendCapability.js +0 -6
- package/dist/wireErrorTriage.d.ts +7 -0
- package/dist/wireErrorTriage.js +26 -23
- package/dist/wireFailureShape.d.ts +62 -5
- package/dist/wireFailureShape.js +106 -5
- package/dist/wireRefusalCopy.d.ts +25 -3
- package/dist/wireRefusalCopy.js +74 -80
- package/dist/workflowsJournalCapability.d.ts +2 -5
- package/dist/workflowsJournalCapability.js +8 -12
- package/dist/writeProtectionCapability.d.ts +0 -4
- package/dist/writeProtectionCapability.js +0 -6
- package/docs/INTEGRATION-CLIENTS.md +1775 -56
- package/package.json +6 -5
- package/dist/attachmentSeatCapability.d.ts +0 -12
- package/dist/attachmentSeatCapability.js +0 -23
- package/dist/hitl/approvalOutcomeNote.d.ts +0 -10
- package/dist/hitl/approvalOutcomeNote.js +0 -29
- package/dist/sessionReadRedactionCapability.d.ts +0 -13
- package/dist/sessionReadRedactionCapability.js +0 -35
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
|
|
@@ -12,12 +15,11 @@ const nested = (prefix, verdict) => {
|
|
|
12
15
|
const reason = verdict.reason.startsWith(`${prefix}:`) ? verdict.reason : `${prefix}: ${verdict.reason}`;
|
|
13
16
|
return bad(reason, path);
|
|
14
17
|
};
|
|
15
|
-
const isObject = (v) => typeof v === "object" && v !== null;
|
|
16
18
|
const isPlainRecord = (v) => {
|
|
17
|
-
if (
|
|
19
|
+
if (typeof v !== "object" || v === null || Array.isArray(v))
|
|
18
20
|
return false;
|
|
19
21
|
const proto = Object.getPrototypeOf(v);
|
|
20
|
-
return proto ===
|
|
22
|
+
return proto === null || (typeof proto === "object" && Object.getPrototypeOf(proto) === null);
|
|
21
23
|
};
|
|
22
24
|
const isAbsent = (v) => typeof v === "undefined";
|
|
23
25
|
const optionalString = (v) => isAbsent(v) || typeof v === "string";
|
|
@@ -90,6 +92,124 @@ const seatCheckAt = (fn) => (v, field) => {
|
|
|
90
92
|
return key !== undefined ? bad(NOT_PLAIN_DATA, `${field}.${key}`) : bad("payload could not be read", field);
|
|
91
93
|
}
|
|
92
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
|
+
});
|
|
93
213
|
export const TOOL_PERMISSION_REQUEST_ID_DOMAINS = Object.freeze([
|
|
94
214
|
"live:",
|
|
95
215
|
"durable:",
|
|
@@ -128,6 +248,7 @@ const SEAT_EVENT_TYPE_TUPLE = [
|
|
|
128
248
|
"chrome_event",
|
|
129
249
|
"error",
|
|
130
250
|
"tool_permission_resolved",
|
|
251
|
+
"subagent_content",
|
|
131
252
|
];
|
|
132
253
|
export const SEAT_EVENT_TYPES = Object.freeze(SEAT_EVENT_TYPE_TUPLE);
|
|
133
254
|
const CHROME_EVENT_KIND_TUPLE = [
|
|
@@ -137,6 +258,14 @@ const CHROME_EVENT_KIND_TUPLE = [
|
|
|
137
258
|
"subagent_lifecycle",
|
|
138
259
|
"text_segment_end",
|
|
139
260
|
"thinking_segment_end",
|
|
261
|
+
"retry_status",
|
|
262
|
+
"context_usage",
|
|
263
|
+
"last_turn_usage",
|
|
264
|
+
"bgshell_register",
|
|
265
|
+
"bgshell_settle",
|
|
266
|
+
"memory_saved",
|
|
267
|
+
"result_replayed",
|
|
268
|
+
"tool_parked",
|
|
140
269
|
];
|
|
141
270
|
export const CHROME_EVENT_KINDS = Object.freeze(CHROME_EVENT_KIND_TUPLE);
|
|
142
271
|
const LANE_PROOF_LANE_TUPLE = ["main", "subagent", "workflow"];
|
|
@@ -151,7 +280,54 @@ export const HITL_RESOLUTION_OUTCOMES = [
|
|
|
151
280
|
"decline",
|
|
152
281
|
"cancel",
|
|
153
282
|
];
|
|
154
|
-
export const
|
|
283
|
+
export const SEAT_STREAM_DELTA_TYPE_OF_CHANNEL = Object.freeze({ text: "text_delta", thinking: "thinking_delta" });
|
|
284
|
+
export function seatStreamDeltaMessage(event, ids) {
|
|
285
|
+
try {
|
|
286
|
+
const channel = ownDataField(event, "channel");
|
|
287
|
+
const text = ownDataField(event, "text");
|
|
288
|
+
const uuid = ownDataField(ids, "uuid");
|
|
289
|
+
const sessionId = ownDataField(ids, "sessionId");
|
|
290
|
+
if (typeof channel !== "string" || !Object.hasOwn(SEAT_STREAM_DELTA_TYPE_OF_CHANNEL, channel))
|
|
291
|
+
return undefined;
|
|
292
|
+
if (typeof text !== "string")
|
|
293
|
+
return undefined;
|
|
294
|
+
if (typeof uuid !== "string" || uuid.length === 0 || typeof sessionId !== "string" || sessionId.length === 0)
|
|
295
|
+
return undefined;
|
|
296
|
+
return {
|
|
297
|
+
type: "stream_event",
|
|
298
|
+
uuid,
|
|
299
|
+
session_id: sessionId,
|
|
300
|
+
event: { type: SEAT_STREAM_DELTA_TYPE_OF_CHANNEL[channel], delta: text },
|
|
301
|
+
parent_tool_use_id: null,
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
catch {
|
|
305
|
+
return undefined;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
export function readSeatStreamDelta(message) {
|
|
309
|
+
try {
|
|
310
|
+
if (typeof message !== "object" || message === null)
|
|
311
|
+
return Object.freeze({ kind: "not_stream_event" });
|
|
312
|
+
if (ownDataField(message, "type") !== "stream_event")
|
|
313
|
+
return Object.freeze({ kind: "not_stream_event" });
|
|
314
|
+
const inner = ownDataField(message, "event");
|
|
315
|
+
if (typeof inner !== "object" || inner === null)
|
|
316
|
+
return Object.freeze({ kind: "malformed" });
|
|
317
|
+
const innerType = ownDataField(inner, "type");
|
|
318
|
+
if (typeof innerType !== "string")
|
|
319
|
+
return Object.freeze({ kind: "malformed" });
|
|
320
|
+
const channel = Object.keys(SEAT_STREAM_DELTA_TYPE_OF_CHANNEL).find((c) => SEAT_STREAM_DELTA_TYPE_OF_CHANNEL[c] === innerType);
|
|
321
|
+
if (channel === undefined)
|
|
322
|
+
return Object.freeze({ kind: "unknown_event" });
|
|
323
|
+
const delta = ownDataField(inner, "delta");
|
|
324
|
+
return typeof delta === "string" ? Object.freeze({ kind: "delta", channel, delta }) : Object.freeze({ kind: "malformed" });
|
|
325
|
+
}
|
|
326
|
+
catch {
|
|
327
|
+
return Object.freeze({ kind: "malformed" });
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
export const SEAT_CAPABILITY_NAMES = Object.freeze(["pickFolder", "rewind", "recents", "patchSession", "devices", "engineTarget", "onboard"]);
|
|
155
331
|
const notReported = () => Object.freeze({ kind: "not_reported" });
|
|
156
332
|
const malformedReading = () => Object.freeze({ kind: "malformed" });
|
|
157
333
|
const reported = (available) => Object.freeze({ kind: "reported", available });
|
|
@@ -159,10 +335,7 @@ export function seatCapability(state, name) {
|
|
|
159
335
|
if (state === undefined)
|
|
160
336
|
return notReported();
|
|
161
337
|
try {
|
|
162
|
-
if (
|
|
163
|
-
return malformedReading();
|
|
164
|
-
const proto = Object.getPrototypeOf(state);
|
|
165
|
-
if (proto !== Object.prototype && proto !== null)
|
|
338
|
+
if (!isPlainRecord(state))
|
|
166
339
|
return malformedReading();
|
|
167
340
|
const desc = Object.getOwnPropertyDescriptor(state, name);
|
|
168
341
|
if (desc === undefined)
|
|
@@ -226,6 +399,9 @@ const SEAT_CAPABILITY_PHRASES = Object.freeze({
|
|
|
226
399
|
pickFolder: Object.freeze({ action: "Opening a folder", ability: "show a folder picker", support: "folder picker support" }),
|
|
227
400
|
rewind: Object.freeze({ action: "Rewinding to an earlier message", ability: "rewind this session", support: "rewind support" }),
|
|
228
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" }),
|
|
229
405
|
});
|
|
230
406
|
export function seatCapabilityUnavailableDetail(name, reading) {
|
|
231
407
|
const phrase = Object.hasOwn(SEAT_CAPABILITY_PHRASES, name)
|
|
@@ -354,9 +530,381 @@ export const ATTACHMENT_UPLOAD_REQUEST_KEYS = ["name", "mimeType", "bytes"];
|
|
|
354
530
|
export const SESSION_ROW_PATCH_REQUEST_KEYS = Object.freeze(["sessionId", "title", "pinned"]);
|
|
355
531
|
export const SESSION_SEARCH_RESULT_KEYS = ["sessionId", "title", "matches"];
|
|
356
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
|
+
});
|
|
357
905
|
const checkLocalSessionRecord = seatCheck((s) => {
|
|
358
|
-
if (!
|
|
359
|
-
return bad("session record is not
|
|
906
|
+
if (!isPlainRecord(s))
|
|
907
|
+
return bad("session record is not a plain object");
|
|
360
908
|
if (typeof own(s, "sessionId") !== "string")
|
|
361
909
|
return bad("sessionId must be a string", "sessionId");
|
|
362
910
|
if (!optionalString(own(s, "engineSessionId")))
|
|
@@ -377,7 +925,7 @@ const checkLocalSessionRecord = seatCheck((s) => {
|
|
|
377
925
|
return bad("lastActivityAt must be a string when present", "lastActivityAt");
|
|
378
926
|
const q = own(s, "queuedMessages");
|
|
379
927
|
if (!isAbsent(q)) {
|
|
380
|
-
const okQueue = Array.isArray(q) && ownItems(q).every((row) =>
|
|
928
|
+
const okQueue = Array.isArray(q) && ownItems(q).every((row) => isPlainRecord(row) && typeof own(row, "uuid") === "string" && typeof own(row, "text") === "string");
|
|
381
929
|
if (!okQueue)
|
|
382
930
|
return bad("queuedMessages must be an array of {uuid,text}", "queuedMessages");
|
|
383
931
|
}
|
|
@@ -395,8 +943,8 @@ export function isLocalSessionRecord(s) {
|
|
|
395
943
|
return checkLocalSessionRecord(s) === true;
|
|
396
944
|
}
|
|
397
945
|
const checkToctouBinding = seatCheck((v) => {
|
|
398
|
-
if (!
|
|
399
|
-
return bad("toctouBinding must be
|
|
946
|
+
if (!isPlainRecord(v))
|
|
947
|
+
return bad("toctouBinding must be a plain object", "toctouBinding");
|
|
400
948
|
if (typeof own(v, "callId") !== "string")
|
|
401
949
|
return bad("toctouBinding.callId must be a string", "toctouBinding.callId");
|
|
402
950
|
if (typeof own(v, "inputHash") !== "string")
|
|
@@ -404,8 +952,8 @@ const checkToctouBinding = seatCheck((v) => {
|
|
|
404
952
|
return true;
|
|
405
953
|
});
|
|
406
954
|
const checkToolPermissionRequest = seatCheck((r) => {
|
|
407
|
-
if (!
|
|
408
|
-
return bad("tool permission request is not
|
|
955
|
+
if (!isPlainRecord(r))
|
|
956
|
+
return bad("tool permission request is not a plain object");
|
|
409
957
|
const requestId = own(r, "requestId");
|
|
410
958
|
if (typeof requestId !== "string")
|
|
411
959
|
return bad("requestId must be a string", "requestId");
|
|
@@ -440,8 +988,8 @@ export function isToolPermissionRequest(r) {
|
|
|
440
988
|
return checkToolPermissionRequest(r) === true;
|
|
441
989
|
}
|
|
442
990
|
const checkLaneProof = seatCheckAt((v, field) => {
|
|
443
|
-
if (!
|
|
444
|
-
return bad("laneProof must be
|
|
991
|
+
if (!isPlainRecord(v))
|
|
992
|
+
return bad("laneProof must be a plain object", field);
|
|
445
993
|
const lane = own(v, "lane");
|
|
446
994
|
if (typeof lane !== "string" || !inTuple(LANE_PROOF_LANE_TUPLE, lane)) {
|
|
447
995
|
return bad(`laneProof.lane must be one of ${LANE_PROOF_LANE_TUPLE.join("|")}`, `${field}.lane`);
|
|
@@ -454,20 +1002,111 @@ const checkLaneProof = seatCheckAt((v, field) => {
|
|
|
454
1002
|
}
|
|
455
1003
|
return true;
|
|
456
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 }) };
|
|
457
1090
|
const checkSeatChromeEnvelope = seatCheckAt((v, field) => {
|
|
458
|
-
if (!
|
|
459
|
-
return bad("chrome must be
|
|
1091
|
+
if (!isPlainRecord(v))
|
|
1092
|
+
return bad("chrome must be a plain object", field);
|
|
460
1093
|
const kind = own(v, "kind");
|
|
461
1094
|
if (typeof kind !== "string")
|
|
462
1095
|
return bad("chrome.kind must be a string", `${field}.kind`);
|
|
463
1096
|
if (!inTuple(CHROME_EVENT_KIND_TUPLE, kind)) {
|
|
464
1097
|
return bad(`chrome.kind is not a renderer-wired arm (${CHROME_EVENT_KIND_TUPLE.join("|")})`, `${field}.kind`);
|
|
465
1098
|
}
|
|
466
|
-
|
|
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;
|
|
467
1106
|
});
|
|
468
1107
|
const checkLocalSessionEvent = seatCheck((v) => {
|
|
469
|
-
if (!
|
|
470
|
-
return bad("event is not
|
|
1108
|
+
if (!isPlainRecord(v))
|
|
1109
|
+
return bad("event is not a plain object");
|
|
471
1110
|
const type = own(v, "type");
|
|
472
1111
|
if (typeof type !== "string")
|
|
473
1112
|
return bad("type must be a string", "type");
|
|
@@ -476,9 +1115,6 @@ const checkLocalSessionEvent = seatCheck((v) => {
|
|
|
476
1115
|
}
|
|
477
1116
|
if (typeof own(v, "sessionId") !== "string")
|
|
478
1117
|
return bad("sessionId must be a string", "sessionId");
|
|
479
|
-
const messages = own(v, "messages");
|
|
480
|
-
if (!isAbsent(messages) && !Array.isArray(messages))
|
|
481
|
-
return bad("messages must be an array", "messages");
|
|
482
1118
|
if (!optionalString(own(v, "error")))
|
|
483
1119
|
return bad("error must be a string when present", "error");
|
|
484
1120
|
if (!optionalString(own(v, "errorCategory")))
|
|
@@ -486,26 +1122,6 @@ const checkLocalSessionEvent = seatCheck((v) => {
|
|
|
486
1122
|
const code = own(v, "code");
|
|
487
1123
|
if (!isAbsent(code) && typeof code !== "number")
|
|
488
1124
|
return bad("code must be a number when present", "code");
|
|
489
|
-
const request = own(v, "request");
|
|
490
|
-
if (!isAbsent(request)) {
|
|
491
|
-
const verdict = checkToolPermissionRequest(request);
|
|
492
|
-
if (verdict !== true)
|
|
493
|
-
return nested("request", verdict);
|
|
494
|
-
}
|
|
495
|
-
if (!optionalString(own(v, "data")))
|
|
496
|
-
return bad("data must be a string when present", "data");
|
|
497
|
-
const sources = own(v, "sources");
|
|
498
|
-
if (!isAbsent(sources)) {
|
|
499
|
-
const okSources = Array.isArray(sources) && ownItems(sources).every((t) => typeof t === "string");
|
|
500
|
-
if (!okSources)
|
|
501
|
-
return bad("sources must be a string[]", "sources");
|
|
502
|
-
}
|
|
503
|
-
const mode = own(v, "permissionMode");
|
|
504
|
-
if (!isAbsent(mode)) {
|
|
505
|
-
if (typeof mode !== "string" || !inTuple(PERMISSION_MODE_INTENTS, mode)) {
|
|
506
|
-
return bad(`permissionMode must be one of ${PERMISSION_MODE_INTENTS.join("|")}`, "permissionMode");
|
|
507
|
-
}
|
|
508
|
-
}
|
|
509
1125
|
const session = own(v, "session");
|
|
510
1126
|
if (!isAbsent(session)) {
|
|
511
1127
|
const verdict = checkLocalSessionRecord(session);
|
|
@@ -514,10 +1130,6 @@ const checkLocalSessionEvent = seatCheck((v) => {
|
|
|
514
1130
|
}
|
|
515
1131
|
if (!optionalString(own(v, "userMessageUuid")))
|
|
516
1132
|
return bad("userMessageUuid must be a string when present", "userMessageUuid");
|
|
517
|
-
const hasPreClearSession = own(v, "hasPreClearSession");
|
|
518
|
-
if (!isAbsent(hasPreClearSession) && typeof hasPreClearSession !== "boolean") {
|
|
519
|
-
return bad("hasPreClearSession must be a boolean when present", "hasPreClearSession");
|
|
520
|
-
}
|
|
521
1133
|
if (!optionalString(own(v, "requestId")))
|
|
522
1134
|
return bad("requestId must be a string when present", "requestId");
|
|
523
1135
|
const outcome = own(v, "outcome");
|
|
@@ -537,14 +1149,49 @@ const checkLocalSessionEvent = seatCheck((v) => {
|
|
|
537
1149
|
if (verdict !== true)
|
|
538
1150
|
return nested("chrome", verdict);
|
|
539
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
|
+
}
|
|
540
1163
|
return true;
|
|
541
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
|
+
}
|
|
542
1189
|
export function isLocalSessionEvent(v) {
|
|
543
1190
|
return checkLocalSessionEvent(v) === true;
|
|
544
1191
|
}
|
|
545
1192
|
const checkAttachmentUploadReceipt = seatCheck((v) => {
|
|
546
|
-
if (!
|
|
547
|
-
return bad("upload receipt is not
|
|
1193
|
+
if (!isPlainRecord(v))
|
|
1194
|
+
return bad("upload receipt is not a plain object");
|
|
548
1195
|
if (typeof own(v, "id") !== "string")
|
|
549
1196
|
return bad("id must be a string", "id");
|
|
550
1197
|
if (typeof own(v, "name") !== "string")
|
|
@@ -560,43 +1207,62 @@ const checkAttachmentUploadReceipt = seatCheck((v) => {
|
|
|
560
1207
|
export function isAttachmentUploadReceipt(v) {
|
|
561
1208
|
return checkAttachmentUploadReceipt(v) === true;
|
|
562
1209
|
}
|
|
1210
|
+
export const APPLY_MODEL_CONFIG_REASONS = Object.freeze([
|
|
1211
|
+
"shadowed_by_models_json",
|
|
1212
|
+
"cheap_provider_unsupported",
|
|
1213
|
+
"invalid_request",
|
|
1214
|
+
"write_failed",
|
|
1215
|
+
"unavailable",
|
|
1216
|
+
]);
|
|
1217
|
+
const APPLY_MODEL_CONFIG_REASON_DETAILS = Object.freeze({
|
|
1218
|
+
shadowed_by_models_json: "Models are managed in the local engine setup window on this device — open it to change the model (Engine ▸ Set up local engine…). Nothing was saved here.",
|
|
1219
|
+
cheap_provider_unsupported: "The cheap model has to use the default model's provider on this desktop seat (same base URL, API and key). Nothing was saved.",
|
|
1220
|
+
invalid_request: "The model configuration was not valid, so it was not applied.",
|
|
1221
|
+
write_failed: "The model configuration could not be saved.",
|
|
1222
|
+
unavailable: "The model configuration can't be changed from this app right now. Nothing was saved.",
|
|
1223
|
+
});
|
|
1224
|
+
export function applyModelConfigReasonDetail(reason) {
|
|
1225
|
+
if (typeof reason === "string" && inTuple(APPLY_MODEL_CONFIG_REASONS, reason))
|
|
1226
|
+
return APPLY_MODEL_CONFIG_REASON_DETAILS[reason];
|
|
1227
|
+
return "The seat rejected this configuration.";
|
|
1228
|
+
}
|
|
563
1229
|
const checkApplyModelConfigResult = seatCheck((v) => {
|
|
564
|
-
if (!
|
|
565
|
-
return bad("applyModelConfig result is not
|
|
1230
|
+
if (!isPlainRecord(v))
|
|
1231
|
+
return bad("applyModelConfig result is not a plain object");
|
|
566
1232
|
const ok = own(v, "ok");
|
|
567
1233
|
if (typeof ok !== "boolean")
|
|
568
1234
|
return bad("ok must be a boolean", "ok");
|
|
569
1235
|
if (typeof own(v, "requiresRestart") !== "boolean")
|
|
570
1236
|
return bad("requiresRestart must be a boolean", "requiresRestart");
|
|
571
1237
|
const reason = own(v, "reason");
|
|
572
|
-
if (
|
|
573
|
-
return bad(
|
|
1238
|
+
if (!isAbsent(reason) && (typeof reason !== "string" || !inTuple(APPLY_MODEL_CONFIG_REASONS, reason))) {
|
|
1239
|
+
return bad(`reason must be one of ${APPLY_MODEL_CONFIG_REASONS.join("|")} when present`, "reason");
|
|
574
1240
|
}
|
|
575
|
-
if (
|
|
576
|
-
return bad(
|
|
1241
|
+
if (ok === false && isAbsent(reason)) {
|
|
1242
|
+
return bad(`reason must be present when ok is false (one of ${APPLY_MODEL_CONFIG_REASONS.join("|")})`, "reason");
|
|
1243
|
+
}
|
|
1244
|
+
if (!optionalString(own(v, "detail")))
|
|
1245
|
+
return bad("detail must be a string when present", "detail");
|
|
577
1246
|
return true;
|
|
578
1247
|
});
|
|
579
1248
|
const checkLiveModelCatalog = seatCheck((v) => {
|
|
580
|
-
if (!
|
|
581
|
-
return bad("model catalog is not
|
|
1249
|
+
if (!isPlainRecord(v))
|
|
1250
|
+
return bad("model catalog is not a plain object");
|
|
582
1251
|
const models = own(v, "models");
|
|
583
1252
|
if (!Array.isArray(models))
|
|
584
1253
|
return bad("models must be an array", "models");
|
|
585
1254
|
const rows = ownItems(models);
|
|
586
1255
|
const names = new Set();
|
|
587
1256
|
for (let i = 0; i < rows.length; i += 1) {
|
|
588
|
-
const row = liveModelRowCopy(rows[i]);
|
|
1257
|
+
const row = isPlainRecord(rows[i]) ? liveModelRowCopy(rows[i]) : undefined;
|
|
589
1258
|
if (row === undefined)
|
|
590
|
-
return bad(`models[${i}] is not a catalog row (
|
|
1259
|
+
return bad(`models[${i}] is not a catalog row (a plain object whose name is a non-empty string, JSON values only)`, `models[${i}]`);
|
|
591
1260
|
if (names.has(row.name))
|
|
592
1261
|
return bad(`models[${i}] repeats the name of an earlier row`, `models[${i}].name`);
|
|
593
1262
|
names.add(row.name);
|
|
594
1263
|
}
|
|
595
|
-
const dflt = own(v, "default");
|
|
596
|
-
if (typeof dflt !== "string" || dflt.length === 0)
|
|
597
|
-
return bad("default must be a non-empty string", "default");
|
|
598
1264
|
const defaultModel = own(v, "defaultModel");
|
|
599
|
-
if (!isAbsent(defaultModel) && liveDefaultModelCopy(defaultModel) === undefined) {
|
|
1265
|
+
if (!isAbsent(defaultModel) && (!isPlainRecord(defaultModel) || liveDefaultModelCopy(defaultModel) === undefined)) {
|
|
600
1266
|
return bad("defaultModel must be {id: non-empty string, name?: non-empty string} when present", "defaultModel");
|
|
601
1267
|
}
|
|
602
1268
|
return true;
|
|
@@ -737,8 +1403,8 @@ export function isSessionRowPatchRequest(v) {
|
|
|
737
1403
|
return checkSessionRowPatchRequest(v) === true;
|
|
738
1404
|
}
|
|
739
1405
|
const checkSendMessageAck = seatCheck((v) => {
|
|
740
|
-
if (!
|
|
741
|
-
return bad("sendMessage ack is not
|
|
1406
|
+
if (!isPlainRecord(v))
|
|
1407
|
+
return bad("sendMessage ack is not a plain object");
|
|
742
1408
|
if (typeof own(v, "sessionId") !== "string")
|
|
743
1409
|
return bad("sessionId must be a string", "sessionId");
|
|
744
1410
|
if (typeof own(v, "userMessageUuid") !== "string")
|
|
@@ -751,13 +1417,13 @@ const checkSendMessageAck = seatCheck((v) => {
|
|
|
751
1417
|
export function isSendMessageAck(v) {
|
|
752
1418
|
return checkSendMessageAck(v) === true;
|
|
753
1419
|
}
|
|
754
|
-
const checkInterruptAck = seatCheck((v) =>
|
|
755
|
-
const checkStopAck = seatCheck((v) =>
|
|
756
|
-
const checkOkAck = seatCheck((v) =>
|
|
1420
|
+
const checkInterruptAck = seatCheck((v) => isPlainRecord(v) && typeof own(v, "interrupted") === "boolean" ? true : bad("interrupt ack needs a plain object with boolean `interrupted`", "interrupted"));
|
|
1421
|
+
const checkStopAck = seatCheck((v) => isPlainRecord(v) && typeof own(v, "stopped") === "boolean" ? true : bad("stop ack needs a plain object with boolean `stopped`", "stopped"));
|
|
1422
|
+
const checkOkAck = seatCheck((v) => isPlainRecord(v) && typeof own(v, "ok") === "boolean" ? true : bad("ack needs a plain object with boolean `ok`", "ok"));
|
|
757
1423
|
const checkBooleanAck = (v) => typeof v === "boolean" ? true : bad("expected a bare boolean result");
|
|
758
1424
|
const checkGetTranscriptResult = seatCheck((v) => {
|
|
759
|
-
if (!
|
|
760
|
-
return bad("transcript envelope is not
|
|
1425
|
+
if (!isPlainRecord(v))
|
|
1426
|
+
return bad("transcript envelope is not a plain object");
|
|
761
1427
|
if (typeof own(v, "sessionId") !== "string")
|
|
762
1428
|
return bad("sessionId must be a string", "sessionId");
|
|
763
1429
|
if (!Array.isArray(own(v, "messages")))
|
|
@@ -765,8 +1431,8 @@ const checkGetTranscriptResult = seatCheck((v) => {
|
|
|
765
1431
|
return true;
|
|
766
1432
|
});
|
|
767
1433
|
const checkSessionSearchResult = seatCheck((v) => {
|
|
768
|
-
if (!
|
|
769
|
-
return bad("search result row is not
|
|
1434
|
+
if (!isPlainRecord(v))
|
|
1435
|
+
return bad("search result row is not a plain object");
|
|
770
1436
|
if (typeof own(v, "sessionId") !== "string")
|
|
771
1437
|
return bad("sessionId must be a string", "sessionId");
|
|
772
1438
|
if (!optionalString(own(v, "title")))
|
|
@@ -774,14 +1440,14 @@ const checkSessionSearchResult = seatCheck((v) => {
|
|
|
774
1440
|
const matches = own(v, "matches");
|
|
775
1441
|
if (!Array.isArray(matches))
|
|
776
1442
|
return bad("matches must be an array", "matches");
|
|
777
|
-
const okMatches = ownItems(matches).every((m) =>
|
|
1443
|
+
const okMatches = ownItems(matches).every((m) => isPlainRecord(m) && typeof own(m, "snippet") === "string");
|
|
778
1444
|
if (!okMatches)
|
|
779
1445
|
return bad("matches must be {snippet:string}[]", "matches");
|
|
780
1446
|
return true;
|
|
781
1447
|
});
|
|
782
1448
|
const checkSessionSearchEnvelope = seatCheck((v) => {
|
|
783
|
-
if (!
|
|
784
|
-
return bad("search envelope is not
|
|
1449
|
+
if (!isPlainRecord(v))
|
|
1450
|
+
return bad("search envelope is not a plain object");
|
|
785
1451
|
const results = own(v, "results");
|
|
786
1452
|
if (!Array.isArray(results))
|
|
787
1453
|
return bad("results must be an array", "results");
|
|
@@ -794,8 +1460,8 @@ const checkSessionSearchEnvelope = seatCheck((v) => {
|
|
|
794
1460
|
return true;
|
|
795
1461
|
});
|
|
796
1462
|
const checkSessionsState = seatCheck((v) => {
|
|
797
|
-
if (!
|
|
798
|
-
return bad("sessions state is not
|
|
1463
|
+
if (!isPlainRecord(v))
|
|
1464
|
+
return bad("sessions state is not a plain object");
|
|
799
1465
|
const sessions = own(v, "sessions");
|
|
800
1466
|
if (!Array.isArray(sessions))
|
|
801
1467
|
return bad("sessions must be an array", "sessions");
|
|
@@ -808,8 +1474,8 @@ const checkSessionsState = seatCheck((v) => {
|
|
|
808
1474
|
return true;
|
|
809
1475
|
});
|
|
810
1476
|
const checkFocusedSessionState = seatCheck((v) => {
|
|
811
|
-
if (!
|
|
812
|
-
return bad("focused session state is not
|
|
1477
|
+
if (!isPlainRecord(v))
|
|
1478
|
+
return bad("focused session state is not a plain object");
|
|
813
1479
|
const sessionId = own(v, "sessionId");
|
|
814
1480
|
if (sessionId !== null && typeof sessionId !== "string") {
|
|
815
1481
|
return bad("sessionId must be a string or null", "sessionId");
|
|
@@ -855,10 +1521,7 @@ const checkRecentFoldersResult = seatCheck((v) => {
|
|
|
855
1521
|
return true;
|
|
856
1522
|
});
|
|
857
1523
|
const checkSeatCapabilitiesState = seatCheck((v) => {
|
|
858
|
-
if (!
|
|
859
|
-
return bad("seat capabilities state is not an object");
|
|
860
|
-
const proto = Object.getPrototypeOf(v);
|
|
861
|
-
if (proto !== Object.prototype && proto !== null)
|
|
1524
|
+
if (!isPlainRecord(v))
|
|
862
1525
|
return bad("seat capabilities state is not a plain object");
|
|
863
1526
|
for (const k of Reflect.ownKeys(v)) {
|
|
864
1527
|
const name = typeof k === "string" ? k : String(k);
|
|
@@ -893,6 +1556,21 @@ export const LOCAL_SESSIONS_SPEC = {
|
|
|
893
1556
|
pickFolder: { kind: "invoke", check: checkPickFolderResult },
|
|
894
1557
|
listRecentFolders: { kind: "invoke", check: checkRecentFoldersResult },
|
|
895
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 },
|
|
896
1574
|
onEvent: { kind: "event", check: checkLocalSessionEvent },
|
|
897
1575
|
onToolPermissionRequest: { kind: "event", check: checkToolPermissionRequest },
|
|
898
1576
|
},
|
|
@@ -901,6 +1579,7 @@ export const LOCAL_SESSIONS_SPEC = {
|
|
|
901
1579
|
focusedSessionState: { check: checkFocusedSessionState },
|
|
902
1580
|
settingsState: { check: checkSettingsState },
|
|
903
1581
|
seatCapabilitiesState: { check: checkSeatCapabilitiesState },
|
|
1582
|
+
engineTargetState: { check: checkEngineTargetState },
|
|
904
1583
|
},
|
|
905
1584
|
};
|
|
906
1585
|
export const SEAT_METHOD_NAMES = [
|
|
@@ -922,6 +1601,21 @@ export const SEAT_METHOD_NAMES = [
|
|
|
922
1601
|
"pickFolder",
|
|
923
1602
|
"listRecentFolders",
|
|
924
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",
|
|
925
1619
|
"onEvent",
|
|
926
1620
|
"onToolPermissionRequest",
|
|
927
1621
|
];
|
|
@@ -930,27 +1624,24 @@ export const SEAT_STORE_PROPS = [
|
|
|
930
1624
|
"focusedSessionStateStore",
|
|
931
1625
|
"settingsStateStore",
|
|
932
1626
|
"seatCapabilitiesStateStore",
|
|
1627
|
+
"engineTargetStateStore",
|
|
933
1628
|
];
|
|
934
1629
|
export const SEAT_EVENT_METHOD_NAMES = ["onEvent", "onToolPermissionRequest"];
|
|
935
1630
|
export const LOCAL_SESSION_EVENT_KEYS = [
|
|
936
1631
|
"type",
|
|
937
1632
|
"sessionId",
|
|
938
1633
|
"message",
|
|
939
|
-
"messages",
|
|
940
1634
|
"error",
|
|
941
1635
|
"errorCategory",
|
|
942
1636
|
"code",
|
|
943
|
-
"request",
|
|
944
|
-
"data",
|
|
945
|
-
"sources",
|
|
946
|
-
"permissionMode",
|
|
947
1637
|
"session",
|
|
948
1638
|
"userMessageUuid",
|
|
949
|
-
"hasPreClearSession",
|
|
950
1639
|
"requestId",
|
|
951
1640
|
"outcome",
|
|
952
1641
|
"parked",
|
|
953
1642
|
"chrome",
|
|
1643
|
+
"_sema_turnFailure",
|
|
1644
|
+
"subagentContent",
|
|
954
1645
|
];
|
|
955
1646
|
export const TOOL_PERMISSION_REQUEST_KEYS = [
|
|
956
1647
|
"requestId",
|
|
@@ -1083,27 +1774,26 @@ export const SEAT_VALIDATOR_KEY_COVERAGE = {
|
|
|
1083
1774
|
validated: [
|
|
1084
1775
|
"type",
|
|
1085
1776
|
"sessionId",
|
|
1086
|
-
"messages",
|
|
1087
1777
|
"error",
|
|
1088
1778
|
"errorCategory",
|
|
1089
1779
|
"code",
|
|
1090
|
-
"request",
|
|
1091
|
-
"data",
|
|
1092
|
-
"sources",
|
|
1093
|
-
"permissionMode",
|
|
1094
1780
|
"session",
|
|
1095
1781
|
"userMessageUuid",
|
|
1096
|
-
"hasPreClearSession",
|
|
1097
1782
|
"requestId",
|
|
1098
1783
|
"outcome",
|
|
1099
1784
|
"parked",
|
|
1100
1785
|
"chrome",
|
|
1786
|
+
"subagentContent",
|
|
1101
1787
|
],
|
|
1102
1788
|
unchecked: [
|
|
1103
1789
|
{
|
|
1104
1790
|
key: "message",
|
|
1105
1791
|
why: "transcript 面直通位(CC fQe 逐字姿态:SDKMessage 体不做 schema 校验)—— 校它 = 引擎加一种消息体的那天整条转录被门吃掉。",
|
|
1106
1792
|
},
|
|
1793
|
+
{
|
|
1794
|
+
key: "_sema_turnFailure",
|
|
1795
|
+
why: "turn 失败的呈现判决(CC-378 TK-9),核形在包读口 readSeatTurnFailure(坏形 / 表外类别词 ⇒ undefined、渲染端只渲 error 文本);出站门为它拒掉整条 error 事件 = 宿主 settle 照走、渲染端把失败轮渲成完成,所以门只登键不拒。",
|
|
1796
|
+
},
|
|
1107
1797
|
],
|
|
1108
1798
|
},
|
|
1109
1799
|
AttachmentUploadReceipt: {
|
|
@@ -1114,7 +1804,7 @@ export const SEAT_VALIDATOR_KEY_COVERAGE = {
|
|
|
1114
1804
|
},
|
|
1115
1805
|
LiveModelCatalog: {
|
|
1116
1806
|
check: checkLiveModelCatalog,
|
|
1117
|
-
validated: ["models", "
|
|
1807
|
+
validated: ["models", "defaultModel"],
|
|
1118
1808
|
unchecked: [
|
|
1119
1809
|
{
|
|
1120
1810
|
key: "droppedEntries",
|
|
@@ -1154,7 +1844,7 @@ export const SEAT_VALIDATOR_KEY_COVERAGE = {
|
|
|
1154
1844
|
},
|
|
1155
1845
|
ApplyModelConfigResult: {
|
|
1156
1846
|
check: checkApplyModelConfigResult,
|
|
1157
|
-
validated: ["ok", "requiresRestart", "reason"],
|
|
1847
|
+
validated: ["ok", "requiresRestart", "reason", "detail"],
|
|
1158
1848
|
unchecked: [],
|
|
1159
1849
|
},
|
|
1160
1850
|
SendMessageAck: {
|
|
@@ -1205,7 +1895,7 @@ export const SEAT_VALIDATOR_KEY_COVERAGE = {
|
|
|
1205
1895
|
},
|
|
1206
1896
|
SeatCapabilitiesState: {
|
|
1207
1897
|
check: checkSeatCapabilitiesState,
|
|
1208
|
-
validated: ["pickFolder", "rewind", "recents", "patchSession"],
|
|
1898
|
+
validated: ["pickFolder", "rewind", "recents", "patchSession", "devices", "engineTarget", "onboard"],
|
|
1209
1899
|
unchecked: [],
|
|
1210
1900
|
},
|
|
1211
1901
|
RecentFoldersResult: {
|
|
@@ -1238,8 +1928,39 @@ export const SEAT_VALIDATOR_KEY_COVERAGE = {
|
|
|
1238
1928
|
validated: ["kind", "laneProof"],
|
|
1239
1929
|
unchecked: [],
|
|
1240
1930
|
},
|
|
1931
|
+
SessionMcpPanelResult: {
|
|
1932
|
+
check: checkSessionMcpPanelResult,
|
|
1933
|
+
validated: ["kind", "why", "detail", "asOf", "servers", "lastLegMcp", "lastLegMcpUnreadable", "degraded", "scenarioRefusal"],
|
|
1934
|
+
unchecked: [],
|
|
1935
|
+
},
|
|
1241
1936
|
};
|
|
1242
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
|
+
})),
|
|
1243
1964
|
{
|
|
1244
1965
|
label: "PickFolderResult",
|
|
1245
1966
|
check: checkPickFolderResult,
|
|
@@ -1282,5 +2003,8 @@ const _seatContractPins = [
|
|
|
1282
2003
|
true, true,
|
|
1283
2004
|
true, true, true, true,
|
|
1284
2005
|
true, true, true, true, true, true,
|
|
2006
|
+
true, true,
|
|
2007
|
+
true, true, true, true,
|
|
2008
|
+
true, true, true,
|
|
1285
2009
|
];
|
|
1286
2010
|
void _seatContractPins;
|