@sema-agent/client-core 0.94.0 → 0.96.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 +521 -0
- package/README.md +104 -57
- package/dist/adapt/arms.js +12 -7
- package/dist/adapt/panelTasks.js +4 -10
- package/dist/adapt/toolCards.d.ts +1 -0
- package/dist/adapt/toolCards.js +18 -5
- package/dist/adapt/wireShapes.js +5 -24
- package/dist/adapter/activeRunSelfHeal.d.ts +12 -3
- package/dist/adapter/activeRunSelfHeal.js +50 -16
- package/dist/adapter/downstream/eventToSdkMessage.js +33 -18
- package/dist/adapter/downstream/terminalToSdkResult.js +19 -12
- package/dist/adapter/runStream.js +30 -46
- 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 +7 -5
- package/dist/agentSession/engineSessionBackgroundStop.js +25 -17
- package/dist/agentsWireCaps.d.ts +2 -0
- package/dist/agentsWireCaps.js +13 -2
- 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 -5
- package/dist/callerCwdCapability.js +2 -13
- package/dist/centerWiringCapability.d.ts +1 -7
- package/dist/centerWiringCapability.js +18 -27
- package/dist/classifierStatus.js +4 -4
- package/dist/classifierVerdictWire.js +4 -16
- package/dist/clientSlice.js +1 -1
- package/dist/cloudConfigWireCaps.d.ts +3 -3
- package/dist/cloudConfigWireCaps.js +85 -43
- package/dist/compensations.js +1 -1
- package/dist/coreValuePorts.d.ts +11 -7
- package/dist/coreValuePorts.js +5 -8
- package/dist/credentialProvenance.d.ts +28 -0
- package/dist/credentialProvenance.js +76 -0
- package/dist/cycleOrder.d.ts +15 -0
- package/dist/cycleOrder.js +45 -0
- package/dist/decideFailureNote.js +7 -2
- package/dist/decideReceipt.d.ts +2 -1
- package/dist/decideReceipt.js +39 -14
- 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 +8 -3
- package/dist/displayUntrusted.js +661 -63
- 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 +13 -2
- package/dist/engineCapsCache.js +276 -44
- package/dist/engineCredentialRequirement.d.ts +9 -0
- package/dist/engineCredentialRequirement.js +23 -0
- package/dist/engineDirectory.d.ts +79 -0
- package/dist/engineDirectory.js +186 -0
- package/dist/engineEnvSourcing.d.ts +53 -0
- package/dist/engineEnvSourcing.js +81 -0
- package/dist/engineErrorCodes.d.ts +28 -4
- package/dist/engineErrorCodes.js +68 -25
- package/dist/engineIdentity.js +2 -0
- package/dist/engineNoticeCodes.d.ts +17 -0
- package/dist/engineNoticeCodes.js +57 -3
- package/dist/engineWireSdk.js +2 -2
- package/dist/engineWordRenames.d.ts +8 -0
- package/dist/engineWordRenames.js +13 -0
- package/dist/executionLaneCapability.d.ts +2 -3
- package/dist/executionLaneCapability.js +18 -23
- package/dist/fileHistoryCaptureCapability.d.ts +14 -1
- package/dist/fileHistoryCaptureCapability.js +72 -6
- package/dist/fileHistoryLegNotice.d.ts +3 -2
- package/dist/fileHistoryLegNotice.js +51 -2
- package/dist/fleet/bgSubagentRow.d.ts +15 -0
- package/dist/fleet/bgSubagentRow.js +67 -0
- package/dist/fleet/fleetLedger.d.ts +3 -0
- package/dist/fleet/fleetLedger.js +153 -122
- package/dist/fleet/fleetProjection.d.ts +1 -3
- package/dist/fleet/fleetProjection.js +19 -19
- 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/fleetTaskDesc.js +4 -17
- package/dist/gateOutcome.d.ts +12 -1
- package/dist/gateOutcome.js +87 -18
- package/dist/gateVocabulary.d.ts +7 -2
- package/dist/gateVocabulary.js +5 -1
- package/dist/generated/engineAskFaceTables.js +1 -1
- package/dist/generated/engineFactTables.d.ts +5 -3
- package/dist/generated/engineFactTables.js +17 -4
- package/dist/generated/engineNoticeTables.js +12 -3
- package/dist/generated/sdkFactTables.d.ts +2 -0
- package/dist/generated/sdkFactTables.js +17 -0
- package/dist/generated/settingsSchemaFns.d.ts +13 -0
- package/dist/generated/settingsSchemaFns.js +75 -0
- package/dist/generated/toolNameTables.d.ts +1 -0
- package/dist/generated/toolNameTables.js +1 -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 +7 -0
- package/dist/hitl/approvalEndingCause.js +71 -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/askParkRowRouting.js +1 -1
- package/dist/hitl/automaticAnswerVerdict.d.ts +1 -1
- package/dist/hitl/automaticAnswerVerdict.js +15 -10
- package/dist/hitl/crashConverged.js +2 -0
- package/dist/hitl/decisionConflict.d.ts +3 -0
- package/dist/hitl/decisionConflict.js +41 -0
- package/dist/hitl/decisionRefusal.d.ts +12 -0
- package/dist/hitl/decisionRefusal.js +63 -4
- package/dist/hitl/frameRouter.d.ts +0 -1
- package/dist/hitl/frameRouter.js +32 -57
- package/dist/hitl/gateLedger.d.ts +5 -0
- package/dist/hitl/gateLedger.js +21 -0
- package/dist/hitl/hitlBridge.d.ts +17 -2
- package/dist/hitl/hitlBridge.js +91 -55
- 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/localAllowRule.d.ts +1 -0
- package/dist/hitl/localAllowRule.js +2 -2
- package/dist/hitl/noAllowCause.d.ts +2 -1
- package/dist/hitl/noAllowCause.js +3 -2
- package/dist/hitl/parkExpiryJudgements.d.ts +19 -0
- package/dist/hitl/parkExpiryJudgements.js +46 -0
- package/dist/hitl/parkResolver.d.ts +4 -7
- package/dist/hitl/parkResolver.js +12 -34
- package/dist/hitl/parkRowBirthWait.d.ts +1 -0
- package/dist/hitl/parkRowBirthWait.js +2 -2
- package/dist/hitl/persistedRulesWire.js +5 -1
- package/dist/hitl/planReviewWire.d.ts +3 -2
- package/dist/hitl/planReviewWire.js +154 -50
- package/dist/hitl/replayedApproval.d.ts +9 -0
- package/dist/hitl/replayedApproval.js +139 -10
- package/dist/hitl/resumeRunningCard.d.ts +2 -0
- package/dist/hitl/resumeRunningCard.js +15 -4
- package/dist/hitl/sessionPolicyDeliverable.js +8 -6
- package/dist/hitl/standingRows.d.ts +18 -0
- package/dist/hitl/standingRows.js +127 -0
- package/dist/hitl/toolApprovalWire.d.ts +39 -7
- package/dist/hitl/toolApprovalWire.js +351 -61
- package/dist/hookMatcherVerdict.d.ts +1 -9
- package/dist/hookMatcherVerdict.js +21 -61
- package/dist/hooksWireCaps.js +40 -8
- package/dist/host.d.ts +5 -0
- package/dist/host.js +3 -1
- package/dist/hostCallbackGuard.d.ts +2 -0
- package/dist/hostCallbackGuard.js +31 -0
- package/dist/index.d.ts +48 -17
- package/dist/index.js +36 -15
- 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 -5
- package/dist/mcpProbeCapability.js +2 -12
- package/dist/mcpReconnect.d.ts +1 -3
- package/dist/mcpReconnect.js +10 -5
- package/dist/memoryComplianceCapability.d.ts +0 -5
- package/dist/memoryComplianceCapability.js +2 -12
- package/dist/memoryOriginCapability.d.ts +0 -5
- package/dist/memoryOriginCapability.js +2 -12
- package/dist/memorySpecWire.js +2 -2
- 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 +2 -2
- package/dist/modelIdentityResolvability.js +14 -12
- package/dist/modelSwitchFallback.d.ts +69 -0
- package/dist/modelSwitchFallback.js +206 -0
- package/dist/noticePresentation.d.ts +68 -0
- package/dist/noticePresentation.js +247 -0
- package/dist/notifications.js +12 -11
- package/dist/outputStyleSeatCapability.d.ts +0 -2
- package/dist/outputStyleSeatCapability.js +2 -10
- package/dist/ownKey.d.ts +8 -0
- package/dist/ownKey.js +66 -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/peerFrames.js +13 -9
- package/dist/peerLaneCapability.d.ts +0 -1
- package/dist/peerLaneCapability.js +2 -6
- package/dist/permissionModesCapability.d.ts +0 -5
- package/dist/permissionModesCapability.js +5 -16
- package/dist/permissionRuleIssue.js +0 -3
- 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 +8 -0
- package/dist/permissionsDeclaration.js +101 -41
- package/dist/printPermissionOutcome.d.ts +12 -0
- package/dist/printPermissionOutcome.js +50 -0
- package/dist/printToolResultFrame.d.ts +1 -0
- package/dist/printToolResultFrame.js +5 -17
- package/dist/promptBlockedCopy.d.ts +5 -0
- package/dist/promptBlockedCopy.js +35 -0
- package/dist/promptDelivery.js +0 -8
- package/dist/protocolSegment.d.ts +9 -6
- package/dist/protocolSegment.js +31 -21
- package/dist/providerRejection.d.ts +4 -0
- package/dist/providerRejection.js +75 -14
- package/dist/replayBody.d.ts +12 -0
- package/dist/replayBody.js +25 -0
- package/dist/resumeRefusalCopy.d.ts +18 -1
- package/dist/resumeRefusalCopy.js +127 -32
- package/dist/retryStatus.d.ts +9 -1
- package/dist/retryStatus.js +9 -2
- package/dist/rewindArchiveCapability.d.ts +5 -14
- package/dist/rewindArchiveCapability.js +18 -61
- package/dist/rewindArchiveReading.d.ts +15 -0
- package/dist/rewindArchiveReading.js +56 -0
- 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/ruleCompileVerdict.d.ts +9 -1
- package/dist/ruleCompileVerdict.js +29 -4
- package/dist/runTerminal.d.ts +15 -12
- package/dist/runTerminal.js +60 -35
- package/dist/sandboxWire.js +13 -0
- package/dist/sdkRegistryTransit.d.ts +2 -1
- package/dist/sdkRegistryTransit.js +1 -0
- package/dist/sealedKeyCapability.d.ts +0 -5
- package/dist/sealedKeyCapability.js +3 -15
- package/dist/seam.js +4 -2
- package/dist/seatContract.d.ts +125 -34
- package/dist/seatContract.js +583 -179
- 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 -5
- package/dist/sessionReadRedactionCapability.js +2 -13
- package/dist/sessionSyncFileHistory.d.ts +4 -0
- package/dist/sessionSyncFileHistory.js +66 -0
- package/dist/sessionSyncFileHistoryCapability.d.ts +0 -2
- package/dist/sessionSyncFileHistoryCapability.js +2 -9
- package/dist/skillToolListsCapability.d.ts +0 -2
- package/dist/skillToolListsCapability.js +2 -9
- 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 -2
- package/dist/steerPriorityCapability.js +3 -12
- package/dist/storePostureCapability.d.ts +1 -5
- package/dist/storePostureCapability.js +16 -22
- 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/engineSubagentSteer.js +7 -5
- package/dist/subagent/engineSubagentTail.d.ts +0 -1
- package/dist/subagent/engineSubagentTail.js +7 -32
- package/dist/subagentContentStore.js +7 -18
- package/dist/supportFloor.d.ts +1 -0
- package/dist/supportFloor.js +15 -14
- package/dist/systemReminderTag.d.ts +1 -0
- package/dist/systemReminderTag.js +8 -0
- package/dist/terminalStatuses.d.ts +30 -0
- package/dist/terminalStatuses.js +67 -0
- package/dist/toolHistoryMismatch.d.ts +0 -3
- package/dist/toolHistoryMismatch.js +3 -7
- package/dist/toolResult.d.ts +6 -1
- package/dist/toolResult.js +90 -37
- package/dist/toolResultContent.d.ts +2 -0
- package/dist/toolResultContent.js +63 -0
- package/dist/types/engineState.d.ts +2 -1
- package/dist/usageAnalytics.d.ts +146 -0
- package/dist/usageAnalytics.js +335 -0
- package/dist/userInvokedSkillsCapability.d.ts +0 -2
- package/dist/userInvokedSkillsCapability.js +2 -9
- package/dist/webSearchBackendCapability.d.ts +0 -1
- package/dist/webSearchBackendCapability.js +3 -7
- package/dist/webSearchWireCaps.js +3 -11
- package/dist/wireErrorTriage.d.ts +2 -0
- package/dist/wireErrorTriage.js +34 -5
- package/dist/wireFailureShape.d.ts +23 -2
- package/dist/wireFailureShape.js +88 -43
- 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 +2279 -27
- 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
|
@@ -14,7 +14,7 @@ export const CORE_ENGINE_NOTICE_CODES = Object.freeze([
|
|
|
14
14
|
"config.artifact_host_invalid",
|
|
15
15
|
"config.task_root_not_canonical",
|
|
16
16
|
"config.write_protection_target_view_absent",
|
|
17
|
-
"config.
|
|
17
|
+
"config.path_view_unresolved",
|
|
18
18
|
"config.execution_env_capability_invalid",
|
|
19
19
|
"config.tool_card_undeclared",
|
|
20
20
|
"config.tool_face_undeclared",
|
|
@@ -66,6 +66,9 @@ export const CORE_ENGINE_NOTICE_CODES = Object.freeze([
|
|
|
66
66
|
"route.base_url_changed_key_unchanged",
|
|
67
67
|
"route.response_model_mismatch",
|
|
68
68
|
"route.tool_call_id_folded",
|
|
69
|
+
"route.finish_reason_unknown",
|
|
70
|
+
"route.stream_end_ignored",
|
|
71
|
+
"route.extra_body_reserved_dropped",
|
|
69
72
|
"context.tool_turn_repaired",
|
|
70
73
|
"task.user_steer_undrained",
|
|
71
74
|
"task.user_followup_undrained",
|
|
@@ -103,7 +106,7 @@ export const CORE_NOTICE_AUDIENCE = Object.freeze({
|
|
|
103
106
|
"config.artifact_host_invalid": "operator",
|
|
104
107
|
"config.task_root_not_canonical": "operator",
|
|
105
108
|
"config.write_protection_target_view_absent": "operator",
|
|
106
|
-
"config.
|
|
109
|
+
"config.path_view_unresolved": "operator",
|
|
107
110
|
"config.execution_env_capability_invalid": "operator",
|
|
108
111
|
"config.tool_card_undeclared": "operator",
|
|
109
112
|
"config.tool_face_undeclared": "operator",
|
|
@@ -155,6 +158,9 @@ export const CORE_NOTICE_AUDIENCE = Object.freeze({
|
|
|
155
158
|
"route.base_url_changed_key_unchanged": "operator",
|
|
156
159
|
"route.response_model_mismatch": "operator",
|
|
157
160
|
"route.tool_call_id_folded": "operator",
|
|
161
|
+
"route.finish_reason_unknown": "user",
|
|
162
|
+
"route.stream_end_ignored": "user",
|
|
163
|
+
"route.extra_body_reserved_dropped": "operator",
|
|
158
164
|
"context.tool_turn_repaired": "operator",
|
|
159
165
|
"task.user_steer_undrained": "user",
|
|
160
166
|
"task.user_followup_undrained": "user",
|
|
@@ -198,7 +204,7 @@ export const CORE_NOTICE_MINTER = Object.freeze({
|
|
|
198
204
|
"config.artifact_host_invalid": "engine",
|
|
199
205
|
"config.task_root_not_canonical": "engine",
|
|
200
206
|
"config.write_protection_target_view_absent": "engine",
|
|
201
|
-
"config.
|
|
207
|
+
"config.path_view_unresolved": "engine",
|
|
202
208
|
"config.execution_env_capability_invalid": "engine",
|
|
203
209
|
"config.tool_card_undeclared": "engine",
|
|
204
210
|
"config.tool_face_undeclared": "engine",
|
|
@@ -250,6 +256,9 @@ export const CORE_NOTICE_MINTER = Object.freeze({
|
|
|
250
256
|
"route.base_url_changed_key_unchanged": "engine",
|
|
251
257
|
"route.response_model_mismatch": "engine",
|
|
252
258
|
"route.tool_call_id_folded": "engine",
|
|
259
|
+
"route.finish_reason_unknown": "engine",
|
|
260
|
+
"route.stream_end_ignored": "engine",
|
|
261
|
+
"route.extra_body_reserved_dropped": "engine",
|
|
253
262
|
"context.tool_turn_repaired": "engine",
|
|
254
263
|
"task.user_steer_undrained": "engine",
|
|
255
264
|
"task.user_followup_undrained": "engine",
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export declare const SDK_ABORT_CAUSES: readonly ["client_disconnected", "ask_park_grace_exhausted", "cancel_verb"];
|
|
2
2
|
export declare const SDK_STATUS_DERIVED_COARSE_CODES: readonly ["request.rejected", "auth.unauthorized", "auth.forbidden", "not_found.resource", "request.payload_too_large", "request.unprocessable", "limit.rate_exceeded", "capability.unavailable", "internal.error"];
|
|
3
3
|
export declare const SDK_DENY_REASON_ROUTING_FAILURE: "routing_failure_fail_closed";
|
|
4
|
+
export declare const SDK_ASK_ROW_ENDING_CAUSES: readonly ["routing_failure_fail_closed", "run_cancelled", "run_exited", "batch_aborted", "batch_sibling_withdrawn", "batch_bound_elsewhere", "adhoc_leg_no_durable_domain", "orphan_ttl_exceeded", "crashed_before_park", "shutdown_before_park"];
|
|
5
|
+
export declare const SDK_RUN_DEATH_VERDICT_CODES: readonly ["run.stalled", "run.orphaned", "approval.expired"];
|
|
@@ -15,3 +15,20 @@ export const SDK_STATUS_DERIVED_COARSE_CODES = Object.freeze([
|
|
|
15
15
|
"internal.error",
|
|
16
16
|
]);
|
|
17
17
|
export const SDK_DENY_REASON_ROUTING_FAILURE = "routing_failure_fail_closed";
|
|
18
|
+
export const SDK_ASK_ROW_ENDING_CAUSES = Object.freeze([
|
|
19
|
+
"routing_failure_fail_closed",
|
|
20
|
+
"run_cancelled",
|
|
21
|
+
"run_exited",
|
|
22
|
+
"batch_aborted",
|
|
23
|
+
"batch_sibling_withdrawn",
|
|
24
|
+
"batch_bound_elsewhere",
|
|
25
|
+
"adhoc_leg_no_durable_domain",
|
|
26
|
+
"orphan_ttl_exceeded",
|
|
27
|
+
"crashed_before_park",
|
|
28
|
+
"shutdown_before_park",
|
|
29
|
+
]);
|
|
30
|
+
export const SDK_RUN_DEATH_VERDICT_CODES = Object.freeze([
|
|
31
|
+
"run.stalled",
|
|
32
|
+
"run.orphaned",
|
|
33
|
+
"approval.expired",
|
|
34
|
+
]);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare const SETTINGS_AT_MENTION_MODES: readonly ["all", "none", "only"];
|
|
2
|
+
export type SettingsAtMention = {
|
|
3
|
+
readonly mode: Exclude<(typeof SETTINGS_AT_MENTION_MODES)[number], 'only'>;
|
|
4
|
+
} | {
|
|
5
|
+
readonly mode: 'only';
|
|
6
|
+
readonly models: readonly string[];
|
|
7
|
+
};
|
|
8
|
+
export type SettingsHookMatcherForm = "literal" | "regex" | "invalid";
|
|
9
|
+
export declare const SETTINGS_IS_LOOPBACK_AUTH_HOST: (host: string) => boolean;
|
|
10
|
+
export declare const SETTINGS_IS_HIERARCHICAL_URL: (raw: string) => boolean;
|
|
11
|
+
export declare const SETTINGS_NARROW_AT_MENTION: (atMention: SettingsAtMention, available: ReadonlySet<string>) => SettingsAtMention;
|
|
12
|
+
export declare const SETTINGS_HOOK_MATCHER_SELECTS: (matcher: string | undefined, name: string) => boolean | 'invalid';
|
|
13
|
+
export declare const SETTINGS_HOOK_MATCHER_FORM: (matcher: string | undefined) => SettingsHookMatcherForm;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
export const SETTINGS_AT_MENTION_MODES = Object.freeze([
|
|
2
|
+
"all",
|
|
3
|
+
"none",
|
|
4
|
+
"only",
|
|
5
|
+
]);
|
|
6
|
+
export const SETTINGS_IS_LOOPBACK_AUTH_HOST = function isLoopbackAuthHost(host) {
|
|
7
|
+
return host === "127.0.0.1" || host === "localhost" || host === "::1" || host === "[::1]" || host === "::ffff:127.0.0.1";
|
|
8
|
+
};
|
|
9
|
+
export const SETTINGS_IS_HIERARCHICAL_URL = function isHierarchicalUrl(raw) {
|
|
10
|
+
if (!URL.canParse(raw))
|
|
11
|
+
return false;
|
|
12
|
+
const u = new URL(raw);
|
|
13
|
+
return u.href.startsWith(`${u.protocol}//`);
|
|
14
|
+
};
|
|
15
|
+
export const SETTINGS_NARROW_AT_MENTION = function narrowAtMention(atMention, available) {
|
|
16
|
+
if (atMention.mode !== "only")
|
|
17
|
+
return atMention;
|
|
18
|
+
const kept = atMention.models.filter((n) => available.has(n));
|
|
19
|
+
if (kept.length === atMention.models.length)
|
|
20
|
+
return atMention;
|
|
21
|
+
return kept.length > 0 ? { mode: "only", models: kept } : { mode: "none" };
|
|
22
|
+
};
|
|
23
|
+
const HOOK_MATCHER_NAME_LIST = /^[a-zA-Z0-9_|, -]+$/;
|
|
24
|
+
const readHookMatcher = function readHookMatcher(matcher) {
|
|
25
|
+
if (matcher === undefined || matcher === "" || matcher === "*")
|
|
26
|
+
return { form: "all" };
|
|
27
|
+
if (HOOK_MATCHER_NAME_LIST.test(matcher)) {
|
|
28
|
+
return {
|
|
29
|
+
form: "names",
|
|
30
|
+
names: matcher
|
|
31
|
+
.split(/[|,]/)
|
|
32
|
+
.map((part) => part.trim())
|
|
33
|
+
.filter((part) => part !== ""),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
return { form: "regex", pattern: new RegExp(matcher) };
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return { form: "invalid" };
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
export const SETTINGS_HOOK_MATCHER_SELECTS = function hookMatcherSelects(matcher, name) {
|
|
44
|
+
const r = readHookMatcher(matcher);
|
|
45
|
+
switch (r.form) {
|
|
46
|
+
case "all":
|
|
47
|
+
return true;
|
|
48
|
+
case "names":
|
|
49
|
+
return r.names.includes(name);
|
|
50
|
+
case "regex":
|
|
51
|
+
return r.pattern.test(name);
|
|
52
|
+
case "invalid":
|
|
53
|
+
return "invalid";
|
|
54
|
+
default: {
|
|
55
|
+
const unhandled = r;
|
|
56
|
+
throw new Error(`hookMatcherSelects: unhandled matcher reading ${JSON.stringify(unhandled)}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
export const SETTINGS_HOOK_MATCHER_FORM = function hookMatcherForm(matcher) {
|
|
61
|
+
const r = readHookMatcher(matcher);
|
|
62
|
+
switch (r.form) {
|
|
63
|
+
case "all":
|
|
64
|
+
case "names":
|
|
65
|
+
return "literal";
|
|
66
|
+
case "regex":
|
|
67
|
+
return "regex";
|
|
68
|
+
case "invalid":
|
|
69
|
+
return "invalid";
|
|
70
|
+
default: {
|
|
71
|
+
const unhandled = r;
|
|
72
|
+
throw new Error(`hookMatcherForm: unhandled matcher reading ${JSON.stringify(unhandled)}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
};
|
|
@@ -3,7 +3,7 @@ import { type PermissionModesReading } from './permissionModesCapability.js';
|
|
|
3
3
|
import { type EnvLike } from './hostEnv.js';
|
|
4
4
|
export declare const HEADLESS_PERMISSION_MODE_ENV = "SEMA_HEADLESS_PERMISSION_MODE";
|
|
5
5
|
export declare const HEADLESS_PERMISSION_WIRE_MODES: readonly PermissionMode[];
|
|
6
|
-
export declare function normalizeShellPermissionModeForWire(mode: string | undefined
|
|
6
|
+
export declare function normalizeShellPermissionModeForWire(mode: string | undefined): string | undefined;
|
|
7
7
|
export type HeadlessPermissionResolution = {
|
|
8
8
|
fields: PermissionModeField;
|
|
9
9
|
source: 'flag' | 'env' | 'default';
|
|
@@ -7,7 +7,7 @@ import { readOwnDataValue } from './ownKey.js';
|
|
|
7
7
|
export const HEADLESS_PERMISSION_MODE_ENV = 'SEMA_HEADLESS_PERMISSION_MODE';
|
|
8
8
|
export const HEADLESS_PERMISSION_WIRE_MODES = [...PERMISSION_MODE_WORDS];
|
|
9
9
|
const SHELL_INTERNAL_MODE_TO_WIRE = new Map([['manual', 'default']]);
|
|
10
|
-
export function normalizeShellPermissionModeForWire(mode
|
|
10
|
+
export function normalizeShellPermissionModeForWire(mode) {
|
|
11
11
|
if (mode === undefined)
|
|
12
12
|
return undefined;
|
|
13
13
|
return SHELL_INTERNAL_MODE_TO_WIRE.get(mode) ?? mode;
|
|
@@ -1,23 +1,18 @@
|
|
|
1
1
|
import { isSseIdleError, probeEngineAlive } from './sseIdleTriage.js';
|
|
2
2
|
import { hostEnv } from './hostEnv.js';
|
|
3
|
+
import { isSdkRunFrameSynthesizable } from './terminalStatuses.js';
|
|
4
|
+
import { createStreamDrainingLegs } from './streamDrainingLegs.js';
|
|
5
|
+
import { abortableSleep } from './abortableSleep.js';
|
|
3
6
|
export const HEADLESS_RECONNECT_MAX = 2;
|
|
4
7
|
function debugLog(msg) {
|
|
5
8
|
if (hostEnv().SEMA_DEBUG) {
|
|
6
9
|
console.error(`[sema] headless reconnect: ${msg}`);
|
|
7
10
|
}
|
|
8
11
|
}
|
|
9
|
-
const RUN_ROW_TERMINAL_STATUSES = new Set([
|
|
10
|
-
'completed',
|
|
11
|
-
'failed',
|
|
12
|
-
'timeout',
|
|
13
|
-
'blocked',
|
|
14
|
-
'suspended',
|
|
15
|
-
'needs_review',
|
|
16
|
-
]);
|
|
17
12
|
export function terminalEventFromRunRow(row) {
|
|
18
13
|
if (!row || typeof row.status !== 'string')
|
|
19
14
|
return null;
|
|
20
|
-
if (
|
|
15
|
+
if (isSdkRunFrameSynthesizable(row.status)) {
|
|
21
16
|
if (row.result && typeof row.result === 'object') {
|
|
22
17
|
return { type: 'done', result: row.result };
|
|
23
18
|
}
|
|
@@ -49,6 +44,15 @@ export async function* withHeadlessR1Reconnect(live, deps) {
|
|
|
49
44
|
let lastSeenSeq;
|
|
50
45
|
const probe = deps.probeAlive ?? probeEngineAlive;
|
|
51
46
|
let isRecoverableTear;
|
|
47
|
+
const drains = createStreamDrainingLegs();
|
|
48
|
+
let drainReopenAfterMs;
|
|
49
|
+
const terminalFromRunRow = async (taskId) => {
|
|
50
|
+
const row = await deps.getRun(taskId).catch(() => null);
|
|
51
|
+
const terminal = terminalEventFromRunRow(row);
|
|
52
|
+
if (terminal)
|
|
53
|
+
debugLog(`run row terminal (${String(row?.status)}) — synthesizing the terminal frame (R1b)`);
|
|
54
|
+
return terminal;
|
|
55
|
+
};
|
|
52
56
|
for (;;) {
|
|
53
57
|
if (deps.signal?.aborted)
|
|
54
58
|
throw originalTearErr;
|
|
@@ -59,25 +63,37 @@ export async function* withHeadlessR1Reconnect(live, deps) {
|
|
|
59
63
|
const taskId = deps.getTaskId();
|
|
60
64
|
if (!taskId)
|
|
61
65
|
throw originalTearErr;
|
|
62
|
-
if (
|
|
63
|
-
|
|
64
|
-
|
|
66
|
+
if (drainReopenAfterMs !== undefined) {
|
|
67
|
+
const waitMs = drainReopenAfterMs;
|
|
68
|
+
drainReopenAfterMs = undefined;
|
|
69
|
+
await abortableSleep(waitMs, deps.signal ?? new AbortController().signal);
|
|
70
|
+
if (deps.signal?.aborted)
|
|
71
|
+
throw originalTearErr;
|
|
72
|
+
debugLog(`engine draining — reopening runs.events(${taskId}${lastSeenSeq !== undefined ? `, Last-Event-ID ${lastSeenSeq}` : ''}) after ${waitMs}ms (not counted against the reconnect budget)`);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
if (attempts >= HEADLESS_RECONNECT_MAX) {
|
|
76
|
+
debugLog(`budget exhausted (${attempts}/${HEADLESS_RECONNECT_MAX}) — falling to the honest death path`);
|
|
77
|
+
throw originalTearErr;
|
|
78
|
+
}
|
|
79
|
+
attempts++;
|
|
80
|
+
if (!(await probe(deps.baseUrl)))
|
|
81
|
+
throw originalTearErr;
|
|
82
|
+
debugLog(`attempt ${attempts}/${HEADLESS_RECONNECT_MAX} — switching to runs.events(${taskId}${lastSeenSeq !== undefined ? `, Last-Event-ID ${lastSeenSeq}` : ''})`);
|
|
65
83
|
}
|
|
66
|
-
attempts++;
|
|
67
|
-
if (!(await probe(deps.baseUrl)))
|
|
68
|
-
throw originalTearErr;
|
|
69
|
-
debugLog(`attempt ${attempts}/${HEADLESS_RECONNECT_MAX} — switching to runs.events(${taskId}${lastSeenSeq !== undefined ? `, Last-Event-ID ${lastSeenSeq}` : ''})`);
|
|
70
84
|
try {
|
|
71
85
|
const cont = deps.openEvents(taskId, lastSeenSeq !== undefined ? String(lastSeenSeq) : undefined);
|
|
72
86
|
for await (const ev of cont) {
|
|
73
87
|
if (deps.signal?.aborted)
|
|
74
88
|
return;
|
|
89
|
+
if (drains.see(ev))
|
|
90
|
+
continue;
|
|
75
91
|
const rec = ev;
|
|
76
92
|
const t = rec?.type;
|
|
77
93
|
if (t === undefined)
|
|
78
94
|
continue;
|
|
79
95
|
if (t === 'error') {
|
|
80
|
-
debugLog(`runs.events lane frame type=error code=${String(rec?.errorCode ?? rec?.code ?? '')} —
|
|
96
|
+
debugLog(`runs.events lane frame type=error code=${String(rec?.errorCode ?? rec?.code ?? '')} — not forwarded (the cap frame is resumed inside the SDK)`);
|
|
81
97
|
continue;
|
|
82
98
|
}
|
|
83
99
|
const seq = typeof rec?.id === 'string' && /^\d+$/.test(rec.id) ? Number(rec.id) : undefined;
|
|
@@ -94,16 +110,29 @@ export async function* withHeadlessR1Reconnect(live, deps) {
|
|
|
94
110
|
}
|
|
95
111
|
if (deps.signal?.aborted)
|
|
96
112
|
return;
|
|
113
|
+
const drained = drains.legEnded('returned');
|
|
114
|
+
if (drained !== undefined) {
|
|
115
|
+
if ('reconnectAfterMs' in drained) {
|
|
116
|
+
drainReopenAfterMs = drained.reconnectAfterMs;
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
debugLog(`runs.events kept ending on drain end frames (${drained.giveUp}) — checking the run row`);
|
|
120
|
+
const terminal = await terminalFromRunRow(taskId);
|
|
121
|
+
if (terminal) {
|
|
122
|
+
yield terminal;
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
97
127
|
debugLog('runs.events continuation ended without a terminal frame');
|
|
98
128
|
}
|
|
99
129
|
catch (contErr) {
|
|
130
|
+
drains.legEnded('threw');
|
|
100
131
|
debugLog(`runs.events continuation failed: ${contErr instanceof Error ? contErr.message : String(contErr)}`);
|
|
101
132
|
if (deps.signal?.aborted)
|
|
102
133
|
throw originalTearErr;
|
|
103
|
-
const
|
|
104
|
-
const terminal = terminalEventFromRunRow(row);
|
|
134
|
+
const terminal = await terminalFromRunRow(taskId);
|
|
105
135
|
if (terminal) {
|
|
106
|
-
debugLog(`run row terminal (${String(row?.status)}) — synthesizing the terminal frame (R1b)`);
|
|
107
136
|
yield terminal;
|
|
108
137
|
return;
|
|
109
138
|
}
|
|
@@ -18,4 +18,4 @@ export interface ApprovalAllowRuleShadow {
|
|
|
18
18
|
export declare function readAllowRuleShadowFromWire(carrier: object | null | undefined, leg: 'frame' | 'row'): ApprovalAllowRuleShadow | undefined;
|
|
19
19
|
export declare function readApprovalAllowRuleShadow(card: object | null | undefined): ApprovalAllowRuleShadow | undefined;
|
|
20
20
|
export declare function approvalAllowRuleShadowed(card: object | null | undefined): boolean;
|
|
21
|
-
export declare function
|
|
21
|
+
export declare function allowRuleShadowSentence(card: object | null | undefined): string | undefined;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { CORE_ALLOW_RULE_MEMBERS } from '../generated/engineFactTables.js';
|
|
2
|
+
import { quoteUntrustedForSentence } from '../displayUntrusted.js';
|
|
2
3
|
const KNOWN_MEMBERS = new Set(CORE_ALLOW_RULE_MEMBERS);
|
|
3
4
|
function freezeMember(m) {
|
|
4
5
|
return Object.freeze({ ...m });
|
|
@@ -154,14 +155,54 @@ export function readApprovalAllowRuleShadow(card) {
|
|
|
154
155
|
export function approvalAllowRuleShadowed(card) {
|
|
155
156
|
return readApprovalAllowRuleShadow(card) !== undefined;
|
|
156
157
|
}
|
|
157
|
-
|
|
158
|
-
|
|
158
|
+
const ENTRY_MAX = 4096;
|
|
159
|
+
const MEMBER_MAX = 64;
|
|
160
|
+
const ENTRIES_SHOWN = 5;
|
|
161
|
+
const UNREADABLE_LINE = 'An allow rule matched this call but cannot clear it; which rule could not be read, so this one is confirmed individually.';
|
|
162
|
+
function legacySingleEntry(shadow) {
|
|
163
|
+
if (shadow.unreadable === true || shadow.members.length !== 1)
|
|
159
164
|
return undefined;
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
return
|
|
165
|
+
const m = shadow.members[0];
|
|
166
|
+
if (m.member !== 'persisted' || m.malformed === true || m.omitted !== undefined)
|
|
167
|
+
return undefined;
|
|
168
|
+
if (m.entries === undefined || m.entries.length !== 1)
|
|
169
|
+
return undefined;
|
|
170
|
+
return quoteUntrustedForSentence(m.entries[0], ENTRY_MAX);
|
|
171
|
+
}
|
|
172
|
+
function memberPhrase(m) {
|
|
173
|
+
const memberWord = m.member === undefined ? undefined : KNOWN_MEMBERS.has(m.member) ? m.member : quoteUntrustedForSentence(m.member, MEMBER_MAX);
|
|
174
|
+
const word = memberWord ?? 'an unrecognised source';
|
|
175
|
+
const entries = m.entries ?? [];
|
|
176
|
+
if (m.malformed === true && entries.length === 0)
|
|
177
|
+
return `${word} (could not be read)`;
|
|
178
|
+
const listed = entries
|
|
179
|
+
.map((e) => quoteUntrustedForSentence(e, ENTRY_MAX))
|
|
180
|
+
.filter((e) => e !== undefined)
|
|
181
|
+
.slice(0, ENTRIES_SHOWN);
|
|
182
|
+
const notListed = entries.length - listed.length + (m.omitted ?? 0);
|
|
183
|
+
const parts = [];
|
|
184
|
+
if (listed.length > 0)
|
|
185
|
+
parts.push(listed.join(', '));
|
|
186
|
+
if (notListed > 0)
|
|
187
|
+
parts.push(listed.length > 0 ? `and ${String(notListed)} more not listed` : `${String(notListed)} not listed`);
|
|
188
|
+
if (m.malformed === true)
|
|
189
|
+
parts.push('part of it could not be read');
|
|
190
|
+
return parts.length > 0 ? `${word}: ${parts.join('; ')}` : word;
|
|
191
|
+
}
|
|
192
|
+
export function allowRuleShadowSentence(card) {
|
|
193
|
+
const shadow = readApprovalAllowRuleShadow(card);
|
|
194
|
+
if (shadow === undefined)
|
|
195
|
+
return undefined;
|
|
196
|
+
try {
|
|
197
|
+
if (shadow.unreadable === true || shadow.members.length === 0)
|
|
198
|
+
return UNREADABLE_LINE;
|
|
199
|
+
const legacy = legacySingleEntry(shadow);
|
|
200
|
+
if (legacy !== undefined) {
|
|
201
|
+
return `Your saved permission rule ${legacy} still exists — it just cannot clear this particular call, so this one is confirmed individually.`;
|
|
202
|
+
}
|
|
203
|
+
return `Allow rules matched this call but cannot clear it, so this one is confirmed individually — ${shadow.members.map(memberPhrase).join(' · ')}.`;
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
return UNREADABLE_LINE;
|
|
165
207
|
}
|
|
166
|
-
return undefined;
|
|
167
208
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function approvalCompleteParked(frame: unknown): boolean;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
function ownData(o, key) {
|
|
2
|
+
const d = Object.getOwnPropertyDescriptor(o, key);
|
|
3
|
+
return d !== undefined && 'value' in d ? d.value : undefined;
|
|
4
|
+
}
|
|
5
|
+
export function approvalCompleteParked(frame) {
|
|
6
|
+
try {
|
|
7
|
+
if (frame === null || typeof frame !== 'object')
|
|
8
|
+
return false;
|
|
9
|
+
return ownData(frame, 'outcome') === 'expired' && ownData(frame, 'parked') === true;
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ApprovalSettleCause, AskRowEndingCause } from '@sema-agent/sdk';
|
|
2
|
+
export declare const ASK_ROW_ENDING_CAUSE_WORDS: readonly ["routing_failure_fail_closed", "run_cancelled", "run_exited", "batch_aborted", "batch_sibling_withdrawn", "batch_bound_elsewhere", "adhoc_leg_no_durable_domain", "orphan_ttl_exceeded", "crashed_before_park", "shutdown_before_park"];
|
|
3
|
+
export declare function askRowEndingCauseFor(state: 'VOID' | 'DENIED' | undefined, word: unknown): AskRowEndingCause | undefined;
|
|
4
|
+
export declare function approvalCompleteCauseOf(frame: unknown): ApprovalSettleCause | undefined;
|
|
5
|
+
export declare function notPendingCauseReading(err: object): 'ended' | 'other_replica' | 'none';
|
|
6
|
+
export declare function refusalCauseWordOf(err: object): string | undefined;
|
|
7
|
+
export declare function notPendingCauseSaysEnded(err: object): boolean;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { ASK_GONE_DENIED_WORD } from '../engineErrorCodes.js';
|
|
2
|
+
import { SDK_ASK_ROW_ENDING_CAUSES } from '../generated/sdkFactTables.js';
|
|
3
|
+
import { readThrownExtra } from '../wireFailureShape.js';
|
|
4
|
+
export const ASK_ROW_ENDING_CAUSE_WORDS = SDK_ASK_ROW_ENDING_CAUSES;
|
|
5
|
+
const _askRowCausePin = true;
|
|
6
|
+
void _askRowCausePin;
|
|
7
|
+
const DENIED_GROUP_WORD = ASK_GONE_DENIED_WORD;
|
|
8
|
+
const WAIT_CLASS_SETTLE_CAUSE_WORDS = Object.freeze({
|
|
9
|
+
ttl_expired: true,
|
|
10
|
+
broadcast_lost: true,
|
|
11
|
+
stream_disconnected: true,
|
|
12
|
+
undeliverable: true,
|
|
13
|
+
});
|
|
14
|
+
function isAskRowEndingCause(v) {
|
|
15
|
+
return typeof v === 'string' && ASK_ROW_ENDING_CAUSE_WORDS.includes(v);
|
|
16
|
+
}
|
|
17
|
+
function isApprovalSettleCause(v) {
|
|
18
|
+
return isAskRowEndingCause(v) || (typeof v === 'string' && Object.hasOwn(WAIT_CLASS_SETTLE_CAUSE_WORDS, v));
|
|
19
|
+
}
|
|
20
|
+
export function askRowEndingCauseFor(state, word) {
|
|
21
|
+
if (!isAskRowEndingCause(word))
|
|
22
|
+
return undefined;
|
|
23
|
+
if (state === 'DENIED')
|
|
24
|
+
return word === DENIED_GROUP_WORD ? word : undefined;
|
|
25
|
+
if (state === 'VOID')
|
|
26
|
+
return word !== DENIED_GROUP_WORD ? word : undefined;
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
function ownDataSlot(o, key) {
|
|
30
|
+
try {
|
|
31
|
+
const slot = Object.getOwnPropertyDescriptor(o, key);
|
|
32
|
+
return slot !== undefined && Object.hasOwn(slot, 'value') ? slot.value : undefined;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
export function approvalCompleteCauseOf(frame) {
|
|
39
|
+
try {
|
|
40
|
+
if (typeof frame !== 'object' || frame === null)
|
|
41
|
+
return undefined;
|
|
42
|
+
if (ownDataSlot(frame, 'type') !== 'tool_approval_complete')
|
|
43
|
+
return undefined;
|
|
44
|
+
const word = ownDataSlot(frame, 'cause');
|
|
45
|
+
return isApprovalSettleCause(word) ? word : undefined;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const NOT_PENDING_OTHER_REPLICA_WORDS = Object.freeze({
|
|
52
|
+
unknown_or_other_replica: true,
|
|
53
|
+
});
|
|
54
|
+
export function notPendingCauseReading(err) {
|
|
55
|
+
const word = refusalCauseWordOf(err);
|
|
56
|
+
if (word === undefined)
|
|
57
|
+
return 'none';
|
|
58
|
+
if (isAskRowEndingCause(word))
|
|
59
|
+
return 'ended';
|
|
60
|
+
return Object.hasOwn(NOT_PENDING_OTHER_REPLICA_WORDS, word) ? 'other_replica' : 'none';
|
|
61
|
+
}
|
|
62
|
+
export function refusalCauseWordOf(err) {
|
|
63
|
+
const reading = readThrownExtra(err);
|
|
64
|
+
if (reading.state !== 'object')
|
|
65
|
+
return undefined;
|
|
66
|
+
const word = ownDataSlot(reading.value, 'cause');
|
|
67
|
+
return typeof word === 'string' && word !== '' ? word : undefined;
|
|
68
|
+
}
|
|
69
|
+
export function notPendingCauseSaysEnded(err) {
|
|
70
|
+
return notPendingCauseReading(err) === 'ended';
|
|
71
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FsApprovalOutcome, ToolApprovalFrameOutcome } from './toolApprovalWire.js';
|
|
1
|
+
import type { ApprovalHolderIdentity, FsApprovalOutcome, ToolApprovalFrameOutcome } from './toolApprovalWire.js';
|
|
2
2
|
export interface DurableDecisionHold {
|
|
3
3
|
readonly lane: 'durable';
|
|
4
4
|
readonly outcome: Promise<FsApprovalOutcome>;
|
|
@@ -9,6 +9,7 @@ export interface DurableDecisionHold {
|
|
|
9
9
|
}
|
|
10
10
|
export interface LiveCardHold {
|
|
11
11
|
readonly lane: 'live';
|
|
12
|
+
readonly identity: LiveCardIdentity;
|
|
12
13
|
readonly outcome: Promise<ToolApprovalFrameOutcome>;
|
|
13
14
|
phase: 'card' | 'respond';
|
|
14
15
|
superseded?: {
|
|
@@ -19,6 +20,15 @@ export interface LiveCardHold {
|
|
|
19
20
|
trailing?: Promise<void>;
|
|
20
21
|
}
|
|
21
22
|
export type ApprovalHold = DurableDecisionHold | LiveCardHold;
|
|
23
|
+
export interface LiveCardIdentity {
|
|
24
|
+
readonly approvalId: string;
|
|
25
|
+
readonly toolCallId?: string;
|
|
26
|
+
readonly taskId?: string;
|
|
27
|
+
readonly sessionId?: string;
|
|
28
|
+
}
|
|
29
|
+
export declare function liveCardHoldFor(who: ApprovalHolderIdentity): LiveCardHold | undefined;
|
|
30
|
+
export declare function liveCardAnsweredHow(o: ToolApprovalFrameOutcome): 'answered' | 'interrupted' | undefined;
|
|
31
|
+
export declare function awaitLiveCardHolder(hold: LiveCardHold, signal: AbortSignal | undefined): Promise<ToolApprovalFrameOutcome | undefined>;
|
|
22
32
|
export interface ApprovalDecisionHoldTable {
|
|
23
33
|
readonly inFlight: Map<string, ApprovalHold>;
|
|
24
34
|
readonly settled: Map<string, DurableSettledHold>;
|
|
@@ -31,6 +41,6 @@ export interface DurableSettledHold {
|
|
|
31
41
|
}
|
|
32
42
|
export declare const approvalDecisionHolds: ApprovalDecisionHoldTable;
|
|
33
43
|
export declare function liveCardHoldOf(key: string): LiveCardHold | undefined;
|
|
34
|
-
export declare function holdLiveCard(
|
|
44
|
+
export declare function holdLiveCard(identity: LiveCardIdentity, callerSignal: AbortSignal | undefined, present: (hold: LiveCardHold) => Promise<ToolApprovalFrameOutcome>): Promise<ToolApprovalFrameOutcome>;
|
|
35
45
|
export declare function joinLiveCard(hold: LiveCardHold, signal: AbortSignal | undefined): Promise<ToolApprovalFrameOutcome>;
|
|
36
46
|
export declare function supersedeLiveCard(key: string, parked: boolean): boolean;
|
|
@@ -1,10 +1,61 @@
|
|
|
1
1
|
import { hostLog } from '../host.js';
|
|
2
|
+
import { liveFrameCallKey } from './gateIdentity.js';
|
|
3
|
+
import { approvalResolutionOf } from './approvalResolution.js';
|
|
4
|
+
const nonEmpty = (v) => typeof v === 'string' && v !== '';
|
|
5
|
+
export function liveCardHoldFor(who) {
|
|
6
|
+
if (nonEmpty(who.approvalId))
|
|
7
|
+
return liveCardHoldOf(liveFrameCallKey(who.approvalId));
|
|
8
|
+
if (!nonEmpty(who.taskId) || !nonEmpty(who.toolCallId))
|
|
9
|
+
return undefined;
|
|
10
|
+
for (const h of approvalDecisionHolds.inFlight.values()) {
|
|
11
|
+
if (h.lane !== 'live' || h.phase !== 'card')
|
|
12
|
+
continue;
|
|
13
|
+
const id = h.identity;
|
|
14
|
+
if (id.taskId !== who.taskId || id.toolCallId !== who.toolCallId)
|
|
15
|
+
continue;
|
|
16
|
+
if (nonEmpty(who.sessionId) && nonEmpty(id.sessionId) && id.sessionId !== who.sessionId)
|
|
17
|
+
continue;
|
|
18
|
+
return h;
|
|
19
|
+
}
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
function liveCardSettledQuestion(hold, o) {
|
|
23
|
+
const r = approvalResolutionOf(o);
|
|
24
|
+
if (answeredHowOf(r) !== undefined)
|
|
25
|
+
return true;
|
|
26
|
+
if (r.kind === 'unsettled')
|
|
27
|
+
return false;
|
|
28
|
+
return hold.superseded !== undefined && !hold.superseded.parked;
|
|
29
|
+
}
|
|
30
|
+
export function liveCardAnsweredHow(o) {
|
|
31
|
+
return answeredHowOf(approvalResolutionOf(o));
|
|
32
|
+
}
|
|
33
|
+
function answeredHowOf(r) {
|
|
34
|
+
if (r.kind === 'decided')
|
|
35
|
+
return 'answered';
|
|
36
|
+
return r.kind === 'unsettled' && r.cause === 'interrupted' ? 'interrupted' : undefined;
|
|
37
|
+
}
|
|
38
|
+
export async function awaitLiveCardHolder(hold, signal) {
|
|
39
|
+
const unsubscribe = followCallerSignal(signal, hold.interrupt);
|
|
40
|
+
let o;
|
|
41
|
+
try {
|
|
42
|
+
o = await hold.outcome;
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
finally {
|
|
48
|
+
unsubscribe();
|
|
49
|
+
}
|
|
50
|
+
return liveCardSettledQuestion(hold, o) ? { ...o, joinedInFlight: true } : undefined;
|
|
51
|
+
}
|
|
2
52
|
export const approvalDecisionHolds = { inFlight: new Map(), settled: new Map(), openReads: new Set(), clock: 0 };
|
|
3
53
|
export function liveCardHoldOf(key) {
|
|
4
54
|
const h = approvalDecisionHolds.inFlight.get(key);
|
|
5
55
|
return h !== undefined && h.lane === 'live' ? h : undefined;
|
|
6
56
|
}
|
|
7
|
-
export function holdLiveCard(
|
|
57
|
+
export function holdLiveCard(identity, callerSignal, present) {
|
|
58
|
+
const key = liveFrameCallKey(identity.approvalId);
|
|
8
59
|
const h = approvalDecisionHolds;
|
|
9
60
|
const cut = new AbortController();
|
|
10
61
|
let settled = false;
|
|
@@ -19,7 +70,7 @@ export function holdLiveCard(key, callerSignal, present) {
|
|
|
19
70
|
resolveOutcome = resolve;
|
|
20
71
|
rejectOutcome = reject;
|
|
21
72
|
});
|
|
22
|
-
const hold = { lane: 'live', outcome, phase: 'card', cardSignal: cut.signal, interrupt };
|
|
73
|
+
const hold = { lane: 'live', identity: Object.freeze({ ...identity }), outcome, phase: 'card', cardSignal: cut.signal, interrupt };
|
|
23
74
|
h.inFlight.set(key, hold);
|
|
24
75
|
const release = () => {
|
|
25
76
|
if (h.inFlight.get(key) === hold)
|