@sema-agent/client-core 0.93.1 → 0.95.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +554 -0
- package/README.md +89 -55
- package/dist/adapt/arms.js +13 -11
- package/dist/adapt/panelTasks.js +4 -10
- package/dist/adapt/toolCards.js +2 -2
- package/dist/adapt/wireShapes.js +3 -8
- package/dist/adapter/activeRunSelfHeal.d.ts +8 -3
- package/dist/adapter/activeRunSelfHeal.js +20 -12
- package/dist/adapter/downstream/eventToSdkMessage.js +24 -17
- package/dist/adapter/downstream/terminalToSdkResult.js +13 -6
- package/dist/adapter/runStream.js +2 -1
- package/dist/adapter/types.d.ts +7 -0
- package/dist/adapter/types.js +15 -0
- package/dist/agentSession/backgroundView.js +5 -1
- package/dist/agentSession/engineAgentRegistryRead.js +2 -1
- package/dist/agentSession/engineSessionBackgroundStop.js +5 -3
- package/dist/agentsWireCaps.d.ts +17 -0
- package/dist/agentsWireCaps.js +111 -1
- package/dist/approvalDecidedByCapability.d.ts +0 -1
- package/dist/approvalDecidedByCapability.js +2 -7
- package/dist/approvalReachWire.d.ts +18 -0
- package/dist/approvalReachWire.js +58 -0
- package/dist/approvalsStreamLiveCapability.d.ts +0 -1
- package/dist/approvalsStreamLiveCapability.js +15 -14
- 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 +15 -0
- package/dist/callerCwdCapability.js +42 -0
- package/dist/centerWiringCapability.d.ts +1 -3
- package/dist/centerWiringCapability.js +18 -21
- package/dist/classifierStatus.js +4 -4
- package/dist/cloudConfigWireCaps.js +43 -21
- package/dist/compensations.js +1 -1
- package/dist/controlRouter.js +3 -10
- package/dist/coreValuePorts.d.ts +64 -1
- package/dist/coreValuePorts.js +30 -0
- package/dist/cycleOrder.d.ts +15 -0
- package/dist/cycleOrder.js +45 -0
- package/dist/decideFailureNote.js +4 -1
- package/dist/decideReceipt.d.ts +2 -1
- package/dist/decideReceipt.js +41 -13
- package/dist/declared/supportFloorDeclared.d.ts +1 -0
- package/dist/declared/supportFloorDeclared.js +5 -0
- package/dist/detachWire.d.ts +1 -4
- package/dist/detachWire.js +1 -1
- package/dist/deviceExecutorManagementCapability.d.ts +0 -1
- package/dist/deviceExecutorManagementCapability.js +36 -40
- package/dist/deviceFlowPolling.d.ts +5 -0
- package/dist/deviceFlowPolling.js +28 -0
- package/dist/deviceRebind.d.ts +88 -0
- package/dist/deviceRebind.js +242 -0
- package/dist/displayUntrusted.d.ts +1 -0
- package/dist/displayUntrusted.js +963 -30
- package/dist/engineAgentAbsence.d.ts +2 -2
- package/dist/engineAgentPanelStore.d.ts +8 -18
- package/dist/engineAgentPanelStore.js +19 -537
- package/dist/engineCapReader.d.ts +6 -6
- package/dist/engineCapReader.js +30 -43
- package/dist/engineCapsCache.d.ts +7 -2
- package/dist/engineCapsCache.js +64 -26
- package/dist/engineCredentialRequirement.d.ts +9 -0
- package/dist/engineCredentialRequirement.js +23 -0
- package/dist/engineEnvSourcing.d.ts +53 -0
- package/dist/engineEnvSourcing.js +81 -0
- package/dist/engineErrorCodes.d.ts +19 -4
- package/dist/engineErrorCodes.js +39 -21
- package/dist/engineIdentity.js +2 -0
- package/dist/engineNoticeCodes.d.ts +22 -2
- package/dist/engineNoticeCodes.js +73 -6
- package/dist/engineRefusedToolName.d.ts +1 -0
- package/dist/engineRefusedToolName.js +8 -0
- package/dist/engineWireSdk.js +2 -2
- package/dist/executionLaneCapability.d.ts +2 -3
- package/dist/executionLaneCapability.js +28 -28
- package/dist/fileHistoryCaptureCapability.d.ts +0 -1
- package/dist/fileHistoryCaptureCapability.js +13 -12
- package/dist/fileHistoryLegNotice.d.ts +14 -2
- package/dist/fileHistoryLegNotice.js +101 -15
- package/dist/fleet/fleetLedger.d.ts +2 -0
- package/dist/fleet/fleetLedger.js +74 -52
- package/dist/fleet/fleetProjection.d.ts +0 -3
- package/dist/fleet/fleetProjection.js +9 -16
- package/dist/fleetAgentPanelProjection.d.ts +4 -17
- package/dist/fleetAgentPanelProjection.js +7 -197
- package/dist/fleetAgentRowLike.d.ts +16 -0
- package/dist/fleetAgentRowLike.js +1 -0
- package/dist/gateOutcome.d.ts +2 -1
- package/dist/gateOutcome.js +33 -18
- package/dist/gateVocabulary.js +1 -1
- package/dist/generated/engineAskFaceTables.d.ts +3 -0
- package/dist/generated/engineAskFaceTables.js +12 -0
- package/dist/generated/engineFactTables.d.ts +4 -2
- package/dist/generated/engineFactTables.js +13 -0
- package/dist/generated/engineNoticeTables.d.ts +5 -0
- package/dist/generated/engineNoticeTables.js +7 -0
- package/dist/generated/sdkFactTables.d.ts +5 -0
- package/dist/generated/sdkFactTables.js +34 -0
- package/dist/generated/settingsSchemaFns.d.ts +10 -0
- package/dist/generated/settingsSchemaFns.js +22 -0
- package/dist/generated/settingsSchemaTables.d.ts +3 -0
- package/dist/generated/settingsSchemaTables.js +3 -0
- package/dist/headlessPermissionModeWire.d.ts +2 -2
- package/dist/headlessPermissionModeWire.js +11 -21
- package/dist/headlessReconnectWire.js +49 -20
- package/dist/hitl/allowRuleShadow.d.ts +1 -1
- package/dist/hitl/allowRuleShadow.js +49 -8
- package/dist/hitl/approvalCompleteParked.d.ts +1 -0
- package/dist/hitl/approvalCompleteParked.js +14 -0
- package/dist/hitl/approvalEndingCause.d.ts +5 -0
- package/dist/hitl/approvalEndingCause.js +61 -0
- package/dist/hitl/approvalHolds.d.ts +46 -0
- package/dist/hitl/approvalHolds.js +140 -0
- package/dist/hitl/approvalOutcomeNote.js +2 -1
- package/dist/hitl/approvalResolution.js +9 -1
- package/dist/hitl/approvalsFeed.js +23 -6
- package/dist/hitl/askGateWire.d.ts +2 -1
- package/dist/hitl/askGateWire.js +29 -1
- package/dist/hitl/automaticAnswerVerdict.d.ts +8 -2
- package/dist/hitl/automaticAnswerVerdict.js +71 -23
- package/dist/hitl/crashConverged.js +2 -0
- package/dist/hitl/decisionConflict.d.ts +3 -0
- package/dist/hitl/decisionConflict.js +43 -0
- package/dist/hitl/decisionRefusal.d.ts +23 -0
- package/dist/hitl/decisionRefusal.js +88 -0
- package/dist/hitl/frameRouter.d.ts +10 -0
- package/dist/hitl/frameRouter.js +71 -32
- package/dist/hitl/gateLedger.d.ts +8 -0
- package/dist/hitl/gateLedger.js +38 -0
- package/dist/hitl/hitlBridge.d.ts +14 -3
- package/dist/hitl/hitlBridge.js +75 -62
- package/dist/hitl/hitlHostSurface.d.ts +3 -0
- package/dist/hitl/hitlHostSurface.js +17 -15
- package/dist/hitl/livePendingAsk.d.ts +16 -6
- package/dist/hitl/livePendingAsk.js +36 -4
- package/dist/hitl/localAllowRule.js +2 -1
- package/dist/hitl/noAllowCause.d.ts +9 -0
- package/dist/hitl/noAllowCause.js +26 -0
- package/dist/hitl/parkExpiryJudgements.d.ts +19 -0
- package/dist/hitl/parkExpiryJudgements.js +46 -0
- package/dist/hitl/parkResolver.d.ts +3 -7
- package/dist/hitl/parkResolver.js +55 -28
- package/dist/hitl/parkRowBirthWait.js +2 -1
- package/dist/hitl/persistedRulesWire.d.ts +6 -1
- package/dist/hitl/persistedRulesWire.js +16 -4
- package/dist/hitl/planReviewWire.d.ts +2 -3
- package/dist/hitl/planReviewWire.js +86 -39
- package/dist/hitl/replayedApproval.d.ts +8 -0
- package/dist/hitl/replayedApproval.js +125 -10
- package/dist/hitl/resumeRunningCard.d.ts +2 -0
- package/dist/hitl/resumeRunningCard.js +15 -4
- package/dist/hitl/sessionPolicyDeliverable.d.ts +1 -1
- package/dist/hitl/sessionPolicyDeliverable.js +3 -8
- package/dist/hitl/sessionPolicyWire.js +1 -1
- package/dist/hitl/toolApprovalWire.d.ts +50 -5
- package/dist/hitl/toolApprovalWire.js +368 -56
- package/dist/hooksWireCaps.js +38 -6
- package/dist/host.d.ts +5 -0
- package/dist/host.js +3 -1
- package/dist/hostCallbackGuard.d.ts +1 -0
- package/dist/hostCallbackGuard.js +25 -0
- package/dist/humanTurnRead.d.ts +15 -1
- package/dist/humanTurnRead.js +28 -2
- package/dist/index.d.ts +45 -14
- package/dist/index.js +33 -12
- package/dist/interactiveInterrupt.d.ts +8 -0
- package/dist/interactiveInterrupt.js +54 -0
- package/dist/limitsWire.d.ts +5 -1
- package/dist/limitsWire.js +51 -13
- package/dist/liveModelCatalog.d.ts +109 -0
- package/dist/liveModelCatalog.js +344 -18
- package/dist/mcpEngineLeg.d.ts +25 -0
- package/dist/mcpEngineLeg.js +71 -15
- package/dist/mcpPanel.js +2 -1
- package/dist/mcpProbeCapability.d.ts +0 -1
- package/dist/mcpProbeCapability.js +13 -12
- package/dist/mcpReconnect.d.ts +1 -3
- package/dist/mcpReconnect.js +20 -10
- package/dist/memoryComplianceCapability.d.ts +0 -1
- package/dist/memoryComplianceCapability.js +14 -13
- package/dist/memoryOriginCapability.d.ts +0 -1
- package/dist/memoryOriginCapability.js +14 -13
- 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 +4 -2
- package/dist/modelIdentityResolvability.js +25 -5
- package/dist/modelSwitchFallback.d.ts +69 -0
- package/dist/modelSwitchFallback.js +206 -0
- package/dist/notifications.js +12 -11
- package/dist/outputStyleSeatCapability.d.ts +15 -0
- package/dist/outputStyleSeatCapability.js +42 -0
- package/dist/ownKey.d.ts +7 -0
- package/dist/ownKey.js +58 -0
- package/dist/panelReduce.d.ts +114 -0
- package/dist/panelReduce.js +1135 -0
- package/dist/panelStateHolder.d.ts +17 -0
- package/dist/panelStateHolder.js +201 -0
- package/dist/peerLaneCapability.d.ts +0 -1
- package/dist/peerLaneCapability.js +15 -14
- package/dist/permissionModesCapability.d.ts +0 -1
- package/dist/permissionModesCapability.js +5 -10
- package/dist/permissionRuleIssue.js +1 -1
- package/dist/permissionRulesWriteCapability.d.ts +0 -1
- package/dist/permissionRulesWriteCapability.js +15 -14
- package/dist/permissionsAllowGrantCapability.d.ts +2 -1
- package/dist/permissionsAllowGrantCapability.js +35 -19
- package/dist/permissionsDeclaration.d.ts +16 -1
- package/dist/permissionsDeclaration.js +142 -15
- package/dist/printToolResultFrame.js +2 -10
- package/dist/promptDelivery.js +0 -8
- package/dist/protocolSegment.d.ts +1 -0
- package/dist/protocolSegment.js +13 -1
- package/dist/request/taskRequest.d.ts +11 -3
- package/dist/request/taskRequest.js +13 -1
- package/dist/resultFrameKeys.d.ts +4 -0
- package/dist/resultFrameKeys.js +13 -0
- package/dist/resumeRefusalCopy.d.ts +18 -1
- package/dist/resumeRefusalCopy.js +132 -31
- package/dist/retryStatus.js +6 -4
- package/dist/rewindArchiveCapability.d.ts +2 -1
- package/dist/rewindArchiveCapability.js +28 -15
- 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/{hitl/rosterMountedNames.d.ts → rosterMountedNames.d.ts} +1 -1
- package/dist/runCancelContext.js +2 -1
- package/dist/runTerminal.d.ts +0 -11
- package/dist/runTerminal.js +4 -27
- package/dist/sdkRegistryTransit.d.ts +2 -1
- package/dist/sdkRegistryTransit.js +1 -0
- package/dist/sealedKeyCapability.d.ts +0 -1
- package/dist/sealedKeyCapability.js +19 -20
- package/dist/seatContract.d.ts +85 -28
- package/dist/seatContract.js +512 -148
- 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 +14 -13
- package/dist/sessionReadRedactionCapability.d.ts +15 -0
- package/dist/sessionReadRedactionCapability.js +42 -0
- package/dist/sessionSyncFileHistoryCapability.d.ts +0 -1
- package/dist/sessionSyncFileHistoryCapability.js +13 -12
- package/dist/skillToolListsCapability.d.ts +0 -1
- package/dist/skillToolListsCapability.js +13 -12
- package/dist/skillsWireCaps.d.ts +4 -0
- package/dist/skillsWireCaps.js +66 -1
- package/dist/sqlEngineCapability.d.ts +0 -1
- package/dist/sqlEngineCapability.js +21 -21
- package/dist/steerPriorityCapability.d.ts +0 -1
- package/dist/steerPriorityCapability.js +18 -19
- package/dist/storePostureCapability.d.ts +1 -1
- package/dist/storePostureCapability.js +16 -16
- package/dist/streamDrainingLegs.d.ts +6 -0
- package/dist/streamDrainingLegs.js +23 -0
- package/dist/subagent/agentStateDetail.d.ts +1 -0
- package/dist/subagent/agentStateDetail.js +41 -0
- package/dist/subagent/engineCompactWire.d.ts +15 -0
- package/dist/subagent/engineCompactWire.js +82 -45
- package/dist/subagent/engineDelegatedPrompt.js +10 -6
- package/dist/subagent/engineSubagentOutput.d.ts +0 -1
- package/dist/subagent/engineSubagentOutput.js +5 -20
- package/dist/subagent/engineSubagentTail.d.ts +0 -1
- package/dist/subagent/engineSubagentTail.js +7 -32
- package/dist/subagentContentStore.js +3 -3
- package/dist/supportFloor.js +2 -5
- package/dist/taskRequestWords.d.ts +2 -4
- package/dist/taskRequestWords.js +3 -2
- package/dist/terminalStatuses.d.ts +30 -0
- package/dist/terminalStatuses.js +67 -0
- package/dist/toolResult.d.ts +5 -0
- package/dist/toolResult.js +88 -36
- package/dist/types/engineState.d.ts +2 -1
- package/dist/usageAnalytics.d.ts +146 -0
- package/dist/usageAnalytics.js +311 -0
- package/dist/userAttachmentEnvelope.d.ts +22 -1
- package/dist/userAttachmentEnvelope.js +90 -2
- package/dist/userInvokedSkillsCapability.d.ts +0 -1
- package/dist/userInvokedSkillsCapability.js +13 -12
- package/dist/webSearchBackendCapability.d.ts +0 -1
- package/dist/webSearchBackendCapability.js +20 -19
- package/dist/webSearchWireCaps.js +3 -11
- package/dist/wireErrorTriage.d.ts +11 -0
- package/dist/wireErrorTriage.js +35 -0
- package/dist/wireFailureShape.d.ts +10 -0
- package/dist/wireFailureShape.js +72 -5
- package/dist/wireRefusalCopy.d.ts +6 -1
- package/dist/wireRefusalCopy.js +23 -25
- package/dist/wiringInstructionsAttribution.d.ts +10 -0
- package/dist/wiringInstructionsAttribution.js +67 -0
- package/dist/workflowClient.js +19 -2
- package/dist/workflowsJournalCapability.d.ts +0 -1
- package/dist/workflowsJournalCapability.js +13 -12
- package/dist/writeProtectionCapability.d.ts +0 -1
- package/dist/writeProtectionCapability.js +26 -26
- package/docs/INTEGRATION-CLIENTS.md +1733 -52
- package/package.json +5 -5
- package/dist/askSurvivesStandingAnswer.d.ts +0 -13
- package/dist/askSurvivesStandingAnswer.js +0 -53
- package/dist/engineCapsGenerationGuard.d.ts +0 -4
- package/dist/engineCapsGenerationGuard.js +0 -19
- package/dist/hitl/askSurvivesPosture.d.ts +0 -20
- package/dist/hitl/askSurvivesPosture.js +0 -48
- package/dist/panelRunningHistory.d.ts +0 -22
- package/dist/panelRunningHistory.js +0 -82
- package/dist/registryConflict.d.ts +0 -3
- package/dist/registryConflict.js +0 -44
- /package/dist/{hitl/rosterMountedNames.js → rosterMountedNames.js} +0 -0
|
@@ -1,18 +1,22 @@
|
|
|
1
|
-
import { APPROVAL_CARD_PORT_KEY_MISMATCH_REASON, DEFAULT_DENY_REASON, DecideTransportRetryExhaustedError, HitlBridge, NO_APPROVAL_CARD_PORT_REASON,
|
|
1
|
+
import { APPROVAL_CARD_PORT_KEY_MISMATCH_REASON, DEFAULT_DENY_REASON, DecideTransportRetryExhaustedError, HitlBridge, NO_APPROVAL_CARD_PORT_REASON, denyReasonForWire, findPendingForTask, hitlSafetyCodeOf, readDecideCurrentPending, readWireErrorCode, readWireErrorCodeReading, } from './hitlBridge.js';
|
|
2
2
|
import { askParkRowArm } from './askParkRowRouting.js';
|
|
3
3
|
import { hostLog } from '../host.js';
|
|
4
|
-
import { readOwnDataNonEmptyString, readOwnDataValue, readOwnNonEmptyString } from '../ownKey.js';
|
|
4
|
+
import { readAskOrigin, readOwnDataNonEmptyString, readOwnDataValue, readOwnNonEmptyString } from '../ownKey.js';
|
|
5
5
|
import { readAskClassPair } from './askClassPair.js';
|
|
6
|
-
import {
|
|
6
|
+
import { readAllowRuleShadowFromWire } from './allowRuleShadow.js';
|
|
7
7
|
import { createSessionSlot, DEFAULT_SESSION_KEY } from '../sessionSlot.js';
|
|
8
8
|
import { readEngineActiveBgTasks } from '../fleet/fleetLedger.js';
|
|
9
|
-
import { observeCancelByDeny, surfaceApprovalParking, surfaceRememberNotApplied, surfaceEditNotForwarded, surfaceEditRefusedOnBlindAsk, surfaceRuleArmNotSent, surfaceRuleArmRejected } from './hitlHostSurface.js';
|
|
9
|
+
import { INTERRUPT_DENY_REASON, observeCancelByDeny, surfaceApprovalParking, surfaceRememberNotApplied, surfaceEditNotForwarded, surfaceEditRefusedOnBlindAsk, surfaceRuleArmNotSent, surfaceRuleArmRejected } from './hitlHostSurface.js';
|
|
10
10
|
import { approvalCallKey, liveFrameCallKey } from './gateIdentity.js';
|
|
11
|
+
import { displayUntrusted } from '../displayUntrusted.js';
|
|
12
|
+
import { approvalDecisionHolds, awaitLiveCardHolder, holdLiveCard, joinLiveCard, liveCardHoldFor, liveCardHoldOf } from './approvalHolds.js';
|
|
13
|
+
import { approvalResolutionOf } from './approvalResolution.js';
|
|
11
14
|
import { isApprovalMandateWord } from '../gateVocabulary.js';
|
|
12
15
|
import { denyAttributionRefusalFromError } from '../wireRefusalCopy.js';
|
|
13
16
|
import { approvalDecidedByAdmitted } from '../approvalDecidedByCapability.js';
|
|
14
17
|
import { decideFailureNote } from '../decideFailureNote.js';
|
|
15
|
-
import {
|
|
18
|
+
import { thrownIsInstanceOf, wireFailureTextsOf } from '../wireFailureShape.js';
|
|
19
|
+
import { DECIDE_WORKFLOW_REMEMBER_UNSUPPORTED, refusalSaysStillPending } from '../engineErrorCodes.js';
|
|
16
20
|
import { readDecideReceipt } from '../decideReceipt.js';
|
|
17
21
|
import { RULE_OFFER_MATCHES, RULE_OFFER_BATCH_MEMBER_KINDS, RULE_OFFER_UNCOVERED_REASONS, RULE_OFFERS_ABSENCE_REASONS, ASK_ORIGINS, PERSISTED_RULE_MANDATES, } from '@sema-agent/sdk';
|
|
18
22
|
export function isFsApprovalGate(gate) {
|
|
@@ -110,6 +114,7 @@ export function approvalCardPortFor(sessionKey) {
|
|
|
110
114
|
export function _resetApprovalCardPortForTest() {
|
|
111
115
|
cardPortByKey.clear();
|
|
112
116
|
cardPortMissesByKey.clear();
|
|
117
|
+
callCardLedger.clear();
|
|
113
118
|
}
|
|
114
119
|
export function surfaceApprovalCard(req) {
|
|
115
120
|
const cardPort = approvalCardPortFor(DEFAULT_SESSION_KEY);
|
|
@@ -127,17 +132,26 @@ function cardPortMissReason() {
|
|
|
127
132
|
return APPROVAL_CARD_PORT_KEY_MISMATCH_REASON;
|
|
128
133
|
return NO_APPROVAL_CARD_PORT_REASON;
|
|
129
134
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
135
|
+
const REMEMBER_REFUSAL_CODES = Object.freeze([
|
|
136
|
+
'remember_not_in_proof',
|
|
137
|
+
'remember_requires_binding',
|
|
138
|
+
'capability.store_required',
|
|
139
|
+
DECIDE_WORKFLOW_REMEMBER_UNSUPPORTED,
|
|
140
|
+
'decide.parked_remember_unsupported',
|
|
141
|
+
]);
|
|
142
|
+
export function rememberRefusalOf(error) {
|
|
143
|
+
return rememberRefusalIn(readWireErrorCodeReading(error));
|
|
144
|
+
}
|
|
145
|
+
function rememberRefusalIn(reading) {
|
|
146
|
+
return reading.state === 'code' ? REMEMBER_REFUSAL_CODES.find((c) => c === reading.code) : undefined;
|
|
147
|
+
}
|
|
148
|
+
function rememberFallbackKind(e) {
|
|
149
|
+
const reading = readWireErrorCodeReading(e);
|
|
150
|
+
if (rememberRefusalIn(reading) !== undefined)
|
|
151
|
+
return 'refused';
|
|
152
|
+
if (reading.state !== 'absent')
|
|
153
|
+
return undefined;
|
|
154
|
+
return readToolApprovalRespondRefusal(e)?.status === 400 ? 'legacy' : undefined;
|
|
141
155
|
}
|
|
142
156
|
function logAfterDecided(msg) {
|
|
143
157
|
try {
|
|
@@ -170,17 +184,17 @@ function isParkRowInputSizeMarker(v) {
|
|
|
170
184
|
const o = v;
|
|
171
185
|
return o.truncated === true && typeof o.bytes === 'number' && Number.isFinite(o.bytes) && o.bytes >= 0;
|
|
172
186
|
}
|
|
173
|
-
const durableDecisionHolds = { inFlight: new Map(), settled: new Map(), openReads: new Set(), clock: 0 };
|
|
174
187
|
function durableHoldKey(row, callKey) {
|
|
175
|
-
|
|
188
|
+
const createdAt = typeof row.createdAt === 'number' && Number.isFinite(row.createdAt) ? row.createdAt : null;
|
|
189
|
+
return JSON.stringify([typeof row.sessionId === 'string' ? row.sessionId : null, typeof row.taskId === 'string' ? row.taskId : null, callKey, createdAt]);
|
|
176
190
|
}
|
|
177
191
|
function openDurableRead() {
|
|
178
|
-
const mark = ++
|
|
179
|
-
|
|
192
|
+
const mark = ++approvalDecisionHolds.clock;
|
|
193
|
+
approvalDecisionHolds.openReads.add(mark);
|
|
180
194
|
return mark;
|
|
181
195
|
}
|
|
182
196
|
function closeDurableRead(mark) {
|
|
183
|
-
const h =
|
|
197
|
+
const h = approvalDecisionHolds;
|
|
184
198
|
h.openReads.delete(mark);
|
|
185
199
|
let oldest = Infinity;
|
|
186
200
|
for (const m of h.openReads)
|
|
@@ -191,14 +205,14 @@ function closeDurableRead(mark) {
|
|
|
191
205
|
h.settled.delete(key);
|
|
192
206
|
}
|
|
193
207
|
function heldDurableDecision(holdKey, readMark) {
|
|
194
|
-
const live =
|
|
208
|
+
const live = approvalDecisionHolds.inFlight.get(holdKey);
|
|
195
209
|
if (live !== undefined)
|
|
196
|
-
return live;
|
|
197
|
-
const recent =
|
|
210
|
+
return live.lane === 'durable' ? live : undefined;
|
|
211
|
+
const recent = approvalDecisionHolds.settled.get(holdKey);
|
|
198
212
|
return recent !== undefined && recent.at > readMark ? recent.hold : undefined;
|
|
199
213
|
}
|
|
200
214
|
function holdDurableDecision(holdKey, callerSignal, decide) {
|
|
201
|
-
const h =
|
|
215
|
+
const h = approvalDecisionHolds;
|
|
202
216
|
const interruption = new AbortController();
|
|
203
217
|
let settled = false;
|
|
204
218
|
const interrupt = () => {
|
|
@@ -215,7 +229,7 @@ function holdDurableDecision(holdKey, callerSignal, decide) {
|
|
|
215
229
|
resolveOutcome = resolve;
|
|
216
230
|
rejectOutcome = reject;
|
|
217
231
|
});
|
|
218
|
-
const hold = { outcome, presented: false, interrupt, cardSignal: interruption.signal };
|
|
232
|
+
const hold = { lane: 'durable', outcome, presented: false, interrupt, cardSignal: interruption.signal };
|
|
219
233
|
h.inFlight.set(holdKey, hold);
|
|
220
234
|
const release = () => {
|
|
221
235
|
if (h.inFlight.get(holdKey) === hold)
|
|
@@ -276,11 +290,50 @@ export async function surfaceFsApprovalAndDecide(deps, taskId, argsByCall, signa
|
|
|
276
290
|
return { kind: 'failed', stage: 'fetch', reason: found.reason, ...(found.code !== undefined ? { code: found.code } : {}) };
|
|
277
291
|
if (held !== undefined)
|
|
278
292
|
return joinDurableDecision(held, deps, signal);
|
|
293
|
+
const liveHolder = liveCardHoldFor(parkRowHolderIdentity(found.pending, found.gatedCallId));
|
|
294
|
+
if (liveHolder !== undefined) {
|
|
295
|
+
const joined = await awaitLiveCardHolder(liveHolder, signal);
|
|
296
|
+
if (joined !== undefined)
|
|
297
|
+
return fsOutcomeOfJoinedLiveCard(joined, found.gatedCallId);
|
|
298
|
+
return surfaceFsApprovalAndDecide(deps, taskId, argsByCall, signal, parkGatedCallId);
|
|
299
|
+
}
|
|
279
300
|
const callKey = approvalCallKey(found.gatedCallId, taskId);
|
|
280
301
|
const fetched = found;
|
|
281
|
-
return holdDurableDecision(durableHoldKey(fetched.pending, callKey), signal, (hold) =>
|
|
302
|
+
return holdDurableDecision(durableHoldKey(fetched.pending, callKey), signal, async (hold) => {
|
|
303
|
+
const slot = {};
|
|
304
|
+
const out = await presentFsApprovalAndDecide(deps, taskId, argsByCall, signal, fetched, decidedByReading, callKey, hold, slot);
|
|
305
|
+
noteCallOutcome(slot, out);
|
|
306
|
+
return out;
|
|
307
|
+
});
|
|
282
308
|
}
|
|
283
|
-
|
|
309
|
+
function parkRowHolderIdentity(row, gatedCallId) {
|
|
310
|
+
return {
|
|
311
|
+
...(typeof row.taskId === 'string' && row.taskId !== '' ? { taskId: row.taskId } : {}),
|
|
312
|
+
...(gatedCallId !== undefined && gatedCallId !== '' ? { toolCallId: gatedCallId } : {}),
|
|
313
|
+
...(typeof row.sessionId === 'string' && row.sessionId !== '' ? { sessionId: row.sessionId } : {}),
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
function fsOutcomeOfJoinedLiveCard(o, gatedCallId) {
|
|
317
|
+
if (o.aborted === true)
|
|
318
|
+
return { kind: 'aborted', gatedCallId, joinedInFlight: true };
|
|
319
|
+
if (o.decision === 'unresolved')
|
|
320
|
+
return { kind: 'retracted', gatedCallId, joinedInFlight: true };
|
|
321
|
+
return {
|
|
322
|
+
kind: 'decided',
|
|
323
|
+
gatedCallId,
|
|
324
|
+
...(o.decision === 'deny'
|
|
325
|
+
? {
|
|
326
|
+
denied: true,
|
|
327
|
+
...(o.denySettledBy !== undefined ? { denySettledBy: o.denySettledBy } : {}),
|
|
328
|
+
...(o.denyReason !== undefined ? { denyReason: o.denyReason } : {}),
|
|
329
|
+
}
|
|
330
|
+
: {}),
|
|
331
|
+
...(o.denyAttributionDropped === true ? { denyAttributionDropped: true } : {}),
|
|
332
|
+
...(o.denyAttributionRenamed === true ? { denyAttributionRenamed: true } : {}),
|
|
333
|
+
joinedInFlight: true,
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
async function presentFsApprovalAndDecide(deps, taskId, argsByCall, signal, found, decidedByReading, callKey, hold, ledgerSlot) {
|
|
284
337
|
const { pending, gatedCallId } = found;
|
|
285
338
|
const toolName = typeof pending.toolName === 'string' ? pending.toolName : '';
|
|
286
339
|
const streamArgs = gatedCallId !== undefined ? argsByCall.get(gatedCallId) : undefined;
|
|
@@ -304,7 +357,7 @@ async function presentFsApprovalAndDecide(deps, taskId, argsByCall, signal, foun
|
|
|
304
357
|
const durableRuleOffersAbsence = pending.ruleOffersAbsence;
|
|
305
358
|
hold.presented = true;
|
|
306
359
|
deps.onPresented?.();
|
|
307
|
-
const card = await
|
|
360
|
+
const card = await surfaceCallTrackedCard(gatedCallId, undefined, ledgerSlot, {
|
|
308
361
|
toolName,
|
|
309
362
|
args,
|
|
310
363
|
callKey,
|
|
@@ -319,16 +372,15 @@ async function presentFsApprovalAndDecide(deps, taskId, argsByCall, signal, foun
|
|
|
319
372
|
...(pending.requiresRealApproval === true ? { requiresRealApproval: true } : {}),
|
|
320
373
|
...(hasOwnStrictTrue(pending, 'mandated') ? { mandated: true } : {}),
|
|
321
374
|
...((w) => (w !== undefined ? { mandate: w } : {}))(readApprovalMandate(pending)),
|
|
322
|
-
...((o) => (o !== undefined ? { origin: o } : {}))(
|
|
375
|
+
...((o) => (o !== undefined ? { origin: o } : {}))(readAskOrigin(pending)),
|
|
323
376
|
...(readAskClassPair(pending) ?? {}),
|
|
324
377
|
...(pending.gateKind === 'irreversible_ask' ? { irreversibleParkGate: true } : {}),
|
|
325
378
|
...(pending.hasBidiControls === true ? { hasBidiControls: true } : {}),
|
|
326
379
|
...(ruleOffersReadOnly !== undefined ? { ruleOffersReadOnly } : {}),
|
|
327
380
|
...(isWireRecordCarrier(durableProbeCause) ? { probeCause: durableProbeCause } : {}),
|
|
328
381
|
...(durableProbeReason !== undefined ? { probeReason: durableProbeReason } : {}),
|
|
329
|
-
...(
|
|
382
|
+
...(readApprovalRememberRefused(pending) ? { rememberRefused: true } : {}),
|
|
330
383
|
...(durableShadow !== undefined ? { allowRuleShadow: durableShadow } : {}),
|
|
331
|
-
...((t) => (t !== undefined ? { persistedRuleShadowed: t } : {}))(legacyShadowedRuleTextOf(durableShadow)),
|
|
332
384
|
...(typeof durableRuleOffersAbsence === 'string' && durableRuleOffersAbsence !== ''
|
|
333
385
|
? { ruleOffersAbsence: durableRuleOffersAbsence }
|
|
334
386
|
: {}),
|
|
@@ -352,7 +404,7 @@ async function presentFsApprovalAndDecide(deps, taskId, argsByCall, signal, foun
|
|
|
352
404
|
return { kind: 'retracted', gatedCallId };
|
|
353
405
|
case 'aborted':
|
|
354
406
|
{
|
|
355
|
-
const cancelDeny = bridge.decideTool({ decision: 'deny', reason:
|
|
407
|
+
const cancelDeny = bridge.decideTool({ decision: 'deny', reason: INTERRUPT_DENY_REASON }, gatedCallId, undefined, pending);
|
|
356
408
|
hold.trailing = cancelDeny;
|
|
357
409
|
observeCancelByDeny(cancelDeny, taskId);
|
|
358
410
|
}
|
|
@@ -369,12 +421,11 @@ async function presentFsApprovalAndDecide(deps, taskId, argsByCall, signal, foun
|
|
|
369
421
|
sessionDecided = true;
|
|
370
422
|
}
|
|
371
423
|
catch (e) {
|
|
372
|
-
|
|
424
|
+
const fallbackKind = rememberFallbackKind(e);
|
|
425
|
+
if (fallbackKind === undefined)
|
|
373
426
|
throw e;
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
rememberRefused = rememberRefusedByServer(e);
|
|
377
|
-
logAfterDecided(`liveToolApprovalWire: decide(approve+remember) failed (${String(e)}) — falling back to plain approve`);
|
|
427
|
+
rememberRefused = fallbackKind === 'refused';
|
|
428
|
+
logAfterDecided(`liveToolApprovalWire: decide(approve+remember) refused the remember part (${String(e)}) — falling back to plain approve`);
|
|
378
429
|
}
|
|
379
430
|
if (sessionDecided) {
|
|
380
431
|
if (sessionReceipt?.rememberApplied === false)
|
|
@@ -392,13 +443,15 @@ async function presentFsApprovalAndDecide(deps, taskId, argsByCall, signal, foun
|
|
|
392
443
|
const currentPending = readDecideCurrentPending(e);
|
|
393
444
|
const wireCode = readWireErrorCode(e);
|
|
394
445
|
const wireRetriable = typeof e === 'object' && e !== null && refusalSaysStillPending(e);
|
|
395
|
-
const safetyCode = e
|
|
446
|
+
const safetyCode = hitlSafetyCodeOf(e);
|
|
447
|
+
const failureTexts = wireFailureTextsOf(e);
|
|
448
|
+
hostLog('debug', `liveToolApprovalWire: decide(approve) failed: ${failureTexts.log}`);
|
|
396
449
|
return {
|
|
397
450
|
kind: 'failed',
|
|
398
451
|
stage: 'decide',
|
|
399
452
|
gatedCallId,
|
|
400
|
-
reason: `decide(approve) failed: ${
|
|
401
|
-
...(e
|
|
453
|
+
reason: `decide(approve) failed: ${failureTexts.reason}${decideFailureNote(e, 'approve')}`,
|
|
454
|
+
...(thrownIsInstanceOf(e, DecideTransportRetryExhaustedError) ? { retryExhausted: true } : {}),
|
|
402
455
|
...(currentPending !== undefined ? { currentPending } : {}),
|
|
403
456
|
...(wireCode !== undefined ? { errorCode: wireCode } : {}),
|
|
404
457
|
...(wireRetriable ? { retriable: true } : {}),
|
|
@@ -476,14 +529,16 @@ async function presentFsApprovalAndDecide(deps, taskId, argsByCall, signal, foun
|
|
|
476
529
|
const currentPending = readDecideCurrentPending(e);
|
|
477
530
|
const wireCode = readWireErrorCode(e);
|
|
478
531
|
const wireRetriable = typeof e === 'object' && e !== null && refusalSaysStillPending(e);
|
|
479
|
-
const safetyCode = e
|
|
532
|
+
const safetyCode = hitlSafetyCodeOf(e);
|
|
480
533
|
const attributionRefusal = denyAttributionRefusalFromError(e, lastSendCarriedAttribution);
|
|
534
|
+
const failureTexts = wireFailureTextsOf(e);
|
|
535
|
+
hostLog('debug', `liveToolApprovalWire: decide(deny) failed: ${failureTexts.log}`);
|
|
481
536
|
return {
|
|
482
537
|
kind: 'failed',
|
|
483
538
|
stage: 'decide',
|
|
484
539
|
gatedCallId,
|
|
485
|
-
reason: `decide(deny) failed: ${
|
|
486
|
-
...(e
|
|
540
|
+
reason: `decide(deny) failed: ${failureTexts.reason}${decideFailureNote(e, 'deny')}`,
|
|
541
|
+
...(thrownIsInstanceOf(e, DecideTransportRetryExhaustedError) ? { retryExhausted: true } : {}),
|
|
487
542
|
...(currentPending !== undefined ? { currentPending } : {}),
|
|
488
543
|
...(wireCode !== undefined ? { errorCode: wireCode } : {}),
|
|
489
544
|
...(wireRetriable ? { retriable: true } : {}),
|
|
@@ -548,6 +603,7 @@ export const TOOL_APPROVAL_FRAME_KEYS_MIRROR = [
|
|
|
548
603
|
'serverNowMs',
|
|
549
604
|
'delegation',
|
|
550
605
|
'outcome',
|
|
606
|
+
'cause',
|
|
551
607
|
];
|
|
552
608
|
const _mirrorPin = [true, true];
|
|
553
609
|
void _mirrorPin;
|
|
@@ -574,7 +630,7 @@ export function toolPermissionRequestAskBits(card) {
|
|
|
574
630
|
return {};
|
|
575
631
|
const mandated = hasOwnStrictTrue(card, 'mandated');
|
|
576
632
|
const mandate = readApprovalMandate(card);
|
|
577
|
-
const origin =
|
|
633
|
+
const origin = readAskOrigin(card);
|
|
578
634
|
const ruleOffersAbsence = readOwnNonEmptyString(card, 'ruleOffersAbsence');
|
|
579
635
|
const askClassPair = readAskClassPair(card);
|
|
580
636
|
return {
|
|
@@ -656,7 +712,7 @@ export function readToolApprovalRespondAck(v) {
|
|
|
656
712
|
}
|
|
657
713
|
return out;
|
|
658
714
|
}
|
|
659
|
-
function readToolApprovalRespondParking(v) {
|
|
715
|
+
export function readToolApprovalRespondParking(v) {
|
|
660
716
|
if (typeof v !== 'object' || v === null)
|
|
661
717
|
return undefined;
|
|
662
718
|
const read = (fn) => {
|
|
@@ -675,7 +731,16 @@ function readToolApprovalRespondParking(v) {
|
|
|
675
731
|
const hint = read(() => readOwnDataValue(v, 'retryAfterMs'));
|
|
676
732
|
const retryAfterMs = typeof hint === 'number' && Number.isFinite(hint) && hint >= 0 ? hint : undefined;
|
|
677
733
|
const decidePath = read(() => readOwnDataNonEmptyString(v, 'decidePath'));
|
|
678
|
-
|
|
734
|
+
const message = read(() => readOwnDataNonEmptyString(v, 'message'));
|
|
735
|
+
return {
|
|
736
|
+
kind: 'parking',
|
|
737
|
+
view: {
|
|
738
|
+
approvalId,
|
|
739
|
+
...(retryAfterMs !== undefined ? { retryAfterMs } : {}),
|
|
740
|
+
...(decidePath !== undefined ? { decidePath } : {}),
|
|
741
|
+
...(message !== undefined ? { message } : {}),
|
|
742
|
+
},
|
|
743
|
+
};
|
|
679
744
|
}
|
|
680
745
|
function isNonEmptyStringArray(v) {
|
|
681
746
|
return Array.isArray(v) && v.length > 0 && v.every(x => typeof x === 'string' && x !== '');
|
|
@@ -830,14 +895,28 @@ function readProbeReason(v) {
|
|
|
830
895
|
try {
|
|
831
896
|
if (typeof v !== 'object' || v === null || !Object.hasOwn(v, 'probeReason'))
|
|
832
897
|
return undefined;
|
|
833
|
-
|
|
834
|
-
return typeof raw === 'string' && raw.trim() !== '' ? raw : undefined;
|
|
898
|
+
return usableProbeReason(v.probeReason);
|
|
835
899
|
}
|
|
836
900
|
catch {
|
|
837
901
|
return undefined;
|
|
838
902
|
}
|
|
839
903
|
}
|
|
840
|
-
function
|
|
904
|
+
function usableProbeReason(raw) {
|
|
905
|
+
return typeof raw === 'string' && raw.trim() !== '' ? raw : undefined;
|
|
906
|
+
}
|
|
907
|
+
const PROBE_CAUSE_CODE_WORD = /^[a-z][a-z0-9_]{0,31}(?:\.[a-z][a-z0-9_]{0,31}){1,3}$/;
|
|
908
|
+
export function askProbeReasonDetail(card) {
|
|
909
|
+
const reason = usableProbeReason(ownDataValue(card, 'probeReason'));
|
|
910
|
+
if (reason !== undefined)
|
|
911
|
+
return displayUntrusted(reason);
|
|
912
|
+
const cause = ownDataValue(card, 'probeCause');
|
|
913
|
+
if (!isWireRecordCarrier(cause))
|
|
914
|
+
return undefined;
|
|
915
|
+
const code = ownDataValue(cause, 'code');
|
|
916
|
+
const head = 'An automatic check could not clear this call, so it is asking you; the engine did not say the specific reason';
|
|
917
|
+
return typeof code === 'string' && PROBE_CAUSE_CODE_WORD.test(code) ? `${head} (check code: ${code}).` : `${head}.`;
|
|
918
|
+
}
|
|
919
|
+
export function readApprovalRememberRefused(v) {
|
|
841
920
|
try {
|
|
842
921
|
return typeof v === 'object' && v !== null && Object.hasOwn(v, 'rememberRefused') && v.rememberRefused === true;
|
|
843
922
|
}
|
|
@@ -845,6 +924,167 @@ function readRememberRefused(v) {
|
|
|
845
924
|
return false;
|
|
846
925
|
}
|
|
847
926
|
}
|
|
927
|
+
function ownDataValue(v, key) {
|
|
928
|
+
if (typeof v !== 'object' || v === null)
|
|
929
|
+
return undefined;
|
|
930
|
+
try {
|
|
931
|
+
const d = Object.getOwnPropertyDescriptor(v, key);
|
|
932
|
+
return d !== undefined && 'value' in d ? d.value : undefined;
|
|
933
|
+
}
|
|
934
|
+
catch {
|
|
935
|
+
return undefined;
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
function ownStringList(v) {
|
|
939
|
+
if (!Array.isArray(v))
|
|
940
|
+
return undefined;
|
|
941
|
+
try {
|
|
942
|
+
const length = v.length;
|
|
943
|
+
if (typeof length !== 'number' || !Number.isSafeInteger(length) || length < 0)
|
|
944
|
+
return undefined;
|
|
945
|
+
const out = [];
|
|
946
|
+
for (let i = 0; i < length; i++) {
|
|
947
|
+
const d = Object.getOwnPropertyDescriptor(v, i);
|
|
948
|
+
if (d === undefined || !('value' in d) || typeof d.value !== 'string' || d.value === '')
|
|
949
|
+
return undefined;
|
|
950
|
+
out.push(d.value);
|
|
951
|
+
}
|
|
952
|
+
return v.length === length ? Object.freeze(out) : undefined;
|
|
953
|
+
}
|
|
954
|
+
catch {
|
|
955
|
+
return undefined;
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
export function readApprovalBoundGrants(v) {
|
|
959
|
+
const g = ownDataValue(v, 'boundGrants');
|
|
960
|
+
if (typeof g !== 'object' || g === null || Array.isArray(g))
|
|
961
|
+
return undefined;
|
|
962
|
+
const skill = ownDataValue(g, 'skill');
|
|
963
|
+
if (!(skill === null || (typeof skill === 'string' && skill !== '')))
|
|
964
|
+
return undefined;
|
|
965
|
+
const allowedTools = ownStringList(ownDataValue(g, 'allowedTools'));
|
|
966
|
+
const disallowedTools = ownStringList(ownDataValue(g, 'disallowedTools'));
|
|
967
|
+
if (allowedTools === undefined || disallowedTools === undefined)
|
|
968
|
+
return undefined;
|
|
969
|
+
return Object.freeze({ skill, allowedTools, disallowedTools });
|
|
970
|
+
}
|
|
971
|
+
const CAUSE_WORD = /^[a-z][a-z0-9_]{0,63}$/;
|
|
972
|
+
export function readApprovalClassifierNoRuling(v) {
|
|
973
|
+
const w = ownDataValue(v, 'classifierNoRuling');
|
|
974
|
+
return typeof w === 'string' && CAUSE_WORD.test(w) ? w : undefined;
|
|
975
|
+
}
|
|
976
|
+
const CLASSIFIER_NO_RULING_REASONS = Object.freeze({
|
|
977
|
+
error: 'could not run for this call (it failed)',
|
|
978
|
+
timeout: 'could not run for this call (it timed out)',
|
|
979
|
+
parse_error: 'answered for this call but gave no verdict it could use',
|
|
980
|
+
});
|
|
981
|
+
const _noRulingPin = [true, true];
|
|
982
|
+
void _noRulingPin;
|
|
983
|
+
export function classifierNoRulingDetail(word) {
|
|
984
|
+
if (typeof word === 'string' && Object.hasOwn(CLASSIFIER_NO_RULING_REASONS, word)) {
|
|
985
|
+
return `The auto-mode classifier ${CLASSIFIER_NO_RULING_REASONS[word]}, so it is asking you instead.`;
|
|
986
|
+
}
|
|
987
|
+
if (typeof word === 'string' && CAUSE_WORD.test(word))
|
|
988
|
+
return `The auto-mode classifier did not rule on this call (reason: ${word}), so it is asking you instead.`;
|
|
989
|
+
return 'The auto-mode classifier did not rule on this call, so it is asking you instead.';
|
|
990
|
+
}
|
|
991
|
+
const entries = (n) => (n === 1 ? '1 tool entry' : `${String(n)} tool entries`);
|
|
992
|
+
export function approvalBoundGrantsDetail(grants) {
|
|
993
|
+
const g = readApprovalBoundGrants({ boundGrants: grants });
|
|
994
|
+
if (g === undefined)
|
|
995
|
+
return undefined;
|
|
996
|
+
if (g.skill === null)
|
|
997
|
+
return 'This call names no loaded skill, so approving it grants nothing beyond this call.';
|
|
998
|
+
const a = g.allowedTools.length;
|
|
999
|
+
const d = g.disallowedTools.length;
|
|
1000
|
+
if (a === 0 && d === 0)
|
|
1001
|
+
return 'Approving this activates the skill shown on the card; it lists no tools to run without asking and none to refuse.';
|
|
1002
|
+
const allow = `${entries(a)} it lists ${a === 1 ? 'runs' : 'run'} without asking once it is active`;
|
|
1003
|
+
const deny = `${entries(d)} ${d === 1 ? 'is' : 'are'} refused for the rest of this run`;
|
|
1004
|
+
return `Approving this activates the skill shown on the card: ${allow}, and ${deny}.`;
|
|
1005
|
+
}
|
|
1006
|
+
const CALL_LEDGER_MAX_CALLS = 256;
|
|
1007
|
+
const CALL_LEDGER_MAX_ASKS_PER_CALL = 8;
|
|
1008
|
+
const callCardLedger = new Map();
|
|
1009
|
+
function askSignatureOf(req) {
|
|
1010
|
+
return JSON.stringify([req.classes !== undefined ? [...req.classes] : null, req.origin ?? null, req.mandate ?? null]);
|
|
1011
|
+
}
|
|
1012
|
+
function priorCardView(a) {
|
|
1013
|
+
return Object.freeze({
|
|
1014
|
+
...(a.approvalId !== undefined ? { approvalId: a.approvalId } : {}),
|
|
1015
|
+
...(a.origin !== undefined ? { origin: a.origin } : {}),
|
|
1016
|
+
...(a.mandate !== undefined ? { mandate: a.mandate } : {}),
|
|
1017
|
+
...(a.outcome !== undefined ? { outcome: a.outcome } : {}),
|
|
1018
|
+
});
|
|
1019
|
+
}
|
|
1020
|
+
function noteCardOnCall(callId, approvalId, req) {
|
|
1021
|
+
const sig = askSignatureOf(req);
|
|
1022
|
+
let asks = callCardLedger.get(callId);
|
|
1023
|
+
if (asks === undefined) {
|
|
1024
|
+
asks = [];
|
|
1025
|
+
callCardLedger.set(callId, asks);
|
|
1026
|
+
while (callCardLedger.size > CALL_LEDGER_MAX_CALLS) {
|
|
1027
|
+
const oldest = callCardLedger.keys().next().value;
|
|
1028
|
+
if (oldest === undefined)
|
|
1029
|
+
break;
|
|
1030
|
+
callCardLedger.delete(oldest);
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
let at = asks.findIndex((a) => a.sig === sig);
|
|
1034
|
+
if (at < 0) {
|
|
1035
|
+
asks.push({ sig, ...(approvalId !== undefined ? { approvalId } : {}), ...(req.origin !== undefined ? { origin: req.origin } : {}), ...(req.mandate !== undefined ? { mandate: req.mandate } : {}) });
|
|
1036
|
+
while (asks.length > CALL_LEDGER_MAX_ASKS_PER_CALL)
|
|
1037
|
+
asks.shift();
|
|
1038
|
+
at = asks.length - 1;
|
|
1039
|
+
}
|
|
1040
|
+
else if (asks[at].approvalId === undefined && approvalId !== undefined) {
|
|
1041
|
+
asks[at].approvalId = approvalId;
|
|
1042
|
+
}
|
|
1043
|
+
const entry = asks[at];
|
|
1044
|
+
const prior = asks.slice(0, at);
|
|
1045
|
+
return { entry, ...(prior.length > 0 ? { prior: Object.freeze(prior.map(priorCardView)) } : {}) };
|
|
1046
|
+
}
|
|
1047
|
+
async function surfaceCallTrackedCard(callId, approvalId, slot, req) {
|
|
1048
|
+
if (callId === undefined || callId === '')
|
|
1049
|
+
return surfaceApprovalCard(req);
|
|
1050
|
+
const { entry, prior } = noteCardOnCall(callId, approvalId, req);
|
|
1051
|
+
slot.entry = entry;
|
|
1052
|
+
return surfaceApprovalCard(prior !== undefined ? { ...req, priorCardsForCall: prior } : req);
|
|
1053
|
+
}
|
|
1054
|
+
function noteCallOutcome(slot, outcome) {
|
|
1055
|
+
const entry = slot.entry;
|
|
1056
|
+
if (entry === undefined)
|
|
1057
|
+
return;
|
|
1058
|
+
const r = approvalResolutionOf(outcome);
|
|
1059
|
+
if (r.kind === 'decided')
|
|
1060
|
+
entry.outcome = r.decision === 'deny' ? 'denied' : 'allowed';
|
|
1061
|
+
}
|
|
1062
|
+
export function approvalPriorCardsDetail(card) {
|
|
1063
|
+
const prior = ownDataValue(card, 'priorCardsForCall');
|
|
1064
|
+
let isList = false;
|
|
1065
|
+
try {
|
|
1066
|
+
isList = Array.isArray(prior);
|
|
1067
|
+
}
|
|
1068
|
+
catch {
|
|
1069
|
+
return undefined;
|
|
1070
|
+
}
|
|
1071
|
+
if (!isList)
|
|
1072
|
+
return undefined;
|
|
1073
|
+
const length = ownDataValue(prior, 'length');
|
|
1074
|
+
if (typeof length !== 'number' || !Number.isSafeInteger(length) || length <= 0 || length > CALL_LEDGER_MAX_ASKS_PER_CALL)
|
|
1075
|
+
return undefined;
|
|
1076
|
+
const items = [];
|
|
1077
|
+
for (let i = 0; i < length; i++)
|
|
1078
|
+
items.push(ownDataValue(prior, String(i)));
|
|
1079
|
+
const outcome = ownDataValue(items[length - 1], 'outcome');
|
|
1080
|
+
const earlier = outcome === 'allowed' ? 'you already approved an earlier one' : outcome === 'denied' ? 'an earlier one was denied' : 'an earlier one was shown first';
|
|
1081
|
+
const fromRule = items.some((p) => ownDataValue(p, 'origin') === 'ask_rule');
|
|
1082
|
+
const thisFromRule = ownDataValue(card, 'origin') === 'ask_rule';
|
|
1083
|
+
if (fromRule && !thisFromRule) {
|
|
1084
|
+
return `This is a second approval for the same call: ${earlier}, which your ask rule asked for. This one is a separate check, not from your ask rule, and needs its own answer.`;
|
|
1085
|
+
}
|
|
1086
|
+
return `This is a second approval for the same call: ${earlier}. This one is a separate check and needs its own answer.`;
|
|
1087
|
+
}
|
|
848
1088
|
function isNonNegativeFinite(v) {
|
|
849
1089
|
return typeof v === 'number' && Number.isFinite(v) && v >= 0;
|
|
850
1090
|
}
|
|
@@ -1010,8 +1250,56 @@ function subagentBadgeFor(frame) {
|
|
|
1010
1250
|
return { name, color: 'cyan' };
|
|
1011
1251
|
}
|
|
1012
1252
|
const MAX_RESPOND_NOTE_CHARS = 2048;
|
|
1013
|
-
export async function surfaceToolApprovalFrameAndRespond(frame, respond, streamArgs, signal, lane) {
|
|
1253
|
+
export async function surfaceToolApprovalFrameAndRespond(frame, respond, streamArgs, signal, lane, run) {
|
|
1014
1254
|
const approvalId = frame.approvalId;
|
|
1255
|
+
const held = liveCardHoldOf(liveFrameCallKey(approvalId));
|
|
1256
|
+
if (held !== undefined)
|
|
1257
|
+
return joinLiveCard(held, signal);
|
|
1258
|
+
return holdLiveCard(liveCardIdentityOf(approvalId, frame, run), signal, async (hold) => {
|
|
1259
|
+
const slot = {};
|
|
1260
|
+
const out = await presentToolApprovalFrameAndRespond(frame, approvalId, respond, streamArgs, signal, lane, hold, slot);
|
|
1261
|
+
noteCallOutcome(slot, out);
|
|
1262
|
+
return out;
|
|
1263
|
+
});
|
|
1264
|
+
}
|
|
1265
|
+
function liveCardIdentityOf(approvalId, frame, run) {
|
|
1266
|
+
const toolCallId = typeof frame.toolCallId === 'string' && frame.toolCallId !== '' ? frame.toolCallId : undefined;
|
|
1267
|
+
const fromSubagent = isFromSubagent(frame);
|
|
1268
|
+
const ownRun = fromSubagent ? frame.sourceTaskId : run?.taskId;
|
|
1269
|
+
const taskId = typeof ownRun === 'string' && ownRun !== '' ? ownRun : undefined;
|
|
1270
|
+
const sessionId = !fromSubagent && typeof run?.sessionId === 'string' && run.sessionId !== '' ? run.sessionId : undefined;
|
|
1271
|
+
return {
|
|
1272
|
+
approvalId,
|
|
1273
|
+
...(toolCallId !== undefined ? { toolCallId } : {}),
|
|
1274
|
+
...(taskId !== undefined ? { taskId } : {}),
|
|
1275
|
+
...(sessionId !== undefined ? { sessionId } : {}),
|
|
1276
|
+
};
|
|
1277
|
+
}
|
|
1278
|
+
function readApprovalHolderIdentity(v) {
|
|
1279
|
+
if (typeof v !== 'object' || v === null)
|
|
1280
|
+
return {};
|
|
1281
|
+
const out = {};
|
|
1282
|
+
try {
|
|
1283
|
+
for (const k of ['approvalId', 'taskId', 'toolCallId', 'sessionId']) {
|
|
1284
|
+
const d = Object.getOwnPropertyDescriptor(v, k);
|
|
1285
|
+
const x = d !== undefined && Object.hasOwn(d, 'value') ? d.value : undefined;
|
|
1286
|
+
if (typeof x === 'string' && x !== '')
|
|
1287
|
+
out[k] = x;
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
catch {
|
|
1291
|
+
return {};
|
|
1292
|
+
}
|
|
1293
|
+
return out;
|
|
1294
|
+
}
|
|
1295
|
+
export async function joinApprovalHolder(identity, signal) {
|
|
1296
|
+
const hold = liveCardHoldFor(readApprovalHolderIdentity(identity));
|
|
1297
|
+
if (hold === undefined)
|
|
1298
|
+
return { kind: 'free' };
|
|
1299
|
+
const joined = await awaitLiveCardHolder(hold, signal);
|
|
1300
|
+
return joined !== undefined ? { kind: 'joined', outcome: joined } : { kind: 'free' };
|
|
1301
|
+
}
|
|
1302
|
+
async function presentToolApprovalFrameAndRespond(frame, approvalId, respond, streamArgs, signal, lane, hold, ledgerSlot) {
|
|
1015
1303
|
const frameToolCallId = typeof frame.toolCallId === 'string' && frame.toolCallId !== '' ? frame.toolCallId : undefined;
|
|
1016
1304
|
const decidedByReading = decidedByReadingSnapshotOf(lane);
|
|
1017
1305
|
const toolName = typeof frame.toolName === 'string' ? frame.toolName : 'Write';
|
|
@@ -1041,14 +1329,14 @@ export async function surfaceToolApprovalFrameAndRespond(frame, respond, streamA
|
|
|
1041
1329
|
const ruleOffers = readRuleOffers(frame.ruleOffers);
|
|
1042
1330
|
const denialLimitFallback = readDenialLimitFallback(frame.denialLimitFallback);
|
|
1043
1331
|
const frameShadow = readAllowRuleShadowFromWire(frame, 'frame');
|
|
1044
|
-
const card = await
|
|
1332
|
+
const card = await surfaceCallTrackedCard(frameToolCallId, approvalId, ledgerSlot, {
|
|
1045
1333
|
toolName,
|
|
1046
1334
|
args: args,
|
|
1047
1335
|
callKey: liveFrameCallKey(approvalId),
|
|
1048
1336
|
...(frameToolCallId !== undefined
|
|
1049
1337
|
? { toolCallId: frameToolCallId }
|
|
1050
1338
|
: {}),
|
|
1051
|
-
|
|
1339
|
+
signal: hold.cardSignal,
|
|
1052
1340
|
...(isFromSubagent(frame) ? { workerBadge: subagentBadgeFor(frame) } : {}),
|
|
1053
1341
|
...(wireNote !== undefined ? { wireNote } : {}),
|
|
1054
1342
|
...(argsNotRealInput ? { argsUnavailable: true } : {}),
|
|
@@ -1068,10 +1356,9 @@ export async function surfaceToolApprovalFrameAndRespond(frame, respond, streamA
|
|
|
1068
1356
|
: {}),
|
|
1069
1357
|
...(ruleOffers !== undefined ? { ruleOffers } : {}),
|
|
1070
1358
|
...((sh) => (sh !== undefined ? { allowRuleShadow: sh } : {}))(frameShadow),
|
|
1071
|
-
...((t) => (t !== undefined ? { persistedRuleShadowed: t } : {}))(legacyShadowedRuleTextOf(frameShadow)),
|
|
1072
1359
|
...(isWireRecordCarrier(frame.probeCause) ? { probeCause: frame.probeCause } : {}),
|
|
1073
1360
|
...((r) => (r !== undefined ? { probeReason: r } : {}))(readProbeReason(frame)),
|
|
1074
|
-
...(
|
|
1361
|
+
...(readApprovalRememberRefused(frame) ? { rememberRefused: true } : {}),
|
|
1075
1362
|
...(isWireRecordCarrier(frame.ruleEvidence) ? { ruleEvidence: frame.ruleEvidence } : {}),
|
|
1076
1363
|
...(frame.requiresRealApproval === true ? { requiresRealApproval: true } : {}),
|
|
1077
1364
|
...(hasOwnStrictTrue(frame, 'mandated') ? { mandated: true } : {}),
|
|
@@ -1082,9 +1369,18 @@ export async function surfaceToolApprovalFrameAndRespond(frame, respond, streamA
|
|
|
1082
1369
|
? { ruleOffersAbsence: frame.ruleOffersAbsence }
|
|
1083
1370
|
: {}),
|
|
1084
1371
|
...(denialLimitFallback !== undefined ? { denialLimitFallback } : {}),
|
|
1085
|
-
...((o) => (o !== undefined ? { origin: o } : {}))(
|
|
1372
|
+
...((o) => (o !== undefined ? { origin: o } : {}))(readAskOrigin(frame)),
|
|
1086
1373
|
...(readAskClassPair(frame) ?? {}),
|
|
1374
|
+
...((g) => (g !== undefined ? { boundGrants: g } : {}))(readApprovalBoundGrants(frame)),
|
|
1375
|
+
...((w) => (w !== undefined ? { classifierNoRuling: w } : {}))(readApprovalClassifierNoRuling(frame)),
|
|
1087
1376
|
});
|
|
1377
|
+
if (hold.superseded !== undefined) {
|
|
1378
|
+
hostLog('debug', `liveToolApprovalWire: ${approvalId} was settled by the engine while its card was up${hold.superseded.parked ? ' (parked)' : ''} — card withdrawn; ` +
|
|
1379
|
+
`the card came back ${card.kind}; nothing sent`);
|
|
1380
|
+
if (hold.superseded.parked && (card.kind === 'allow' || card.kind === 'deny'))
|
|
1381
|
+
surfaceApprovalParking();
|
|
1382
|
+
return { decision: 'unresolved', retracted: true };
|
|
1383
|
+
}
|
|
1088
1384
|
if (argsNotRealInput && card.kind === 'allow' && card.updatedInput !== undefined) {
|
|
1089
1385
|
hostLog('error', `liveToolApprovalWire: ${approvalId} card returned an edited approval on a card whose arguments are not the tool's real input (${lane?.argsUnavailable === true ? 'args-unavailable ask' : 'arguments omitted or absent on the frame'}) — nothing sent (the ask stays pending)`);
|
|
1090
1386
|
surfaceEditRefusedOnBlindAsk();
|
|
@@ -1094,6 +1390,22 @@ export async function surfaceToolApprovalFrameAndRespond(frame, respond, streamA
|
|
|
1094
1390
|
hostLog('debug', `liveToolApprovalWire: ${approvalId} card retracted without a decision${card.reason ? ` (${card.reason})` : ''} — nothing sent`);
|
|
1095
1391
|
return { decision: 'unresolved', retracted: true };
|
|
1096
1392
|
}
|
|
1393
|
+
if (card.kind === 'aborted') {
|
|
1394
|
+
hold.phase = 'respond';
|
|
1395
|
+
const interruptOpts = lane?.approvalDecisionNoteCapable === true ? { note: INTERRUPT_DENY_REASON } : {};
|
|
1396
|
+
let interruptDeny;
|
|
1397
|
+
try {
|
|
1398
|
+
interruptDeny = Promise.resolve(respond(approvalId, 'deny', interruptOpts));
|
|
1399
|
+
}
|
|
1400
|
+
catch (e) {
|
|
1401
|
+
interruptDeny = Promise.reject(e);
|
|
1402
|
+
}
|
|
1403
|
+
hold.trailing = interruptDeny.then(() => undefined, () => undefined);
|
|
1404
|
+
observeCancelByDeny(interruptDeny, approvalId);
|
|
1405
|
+
hostLog('debug', `liveToolApprovalWire: ${approvalId} card aborted — one tool-level deny issued to settle the pending ask`);
|
|
1406
|
+
return { decision: 'unresolved', aborted: true };
|
|
1407
|
+
}
|
|
1408
|
+
hold.phase = 'respond';
|
|
1097
1409
|
const decision = card.kind === 'allow' ? (card.allowSession ? 'allow_session' : 'allow') : 'deny';
|
|
1098
1410
|
const denySettledByForWire = card.kind === 'deny' ? readApprovalDenySettledBy(card) : undefined;
|
|
1099
1411
|
const attributionKeys = decision === 'deny' ? decisionAttributionKeyOf(decidedByReading, denySettledByForWire) : {};
|