@sema-agent/client-core 0.99.0 → 0.101.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 +572 -0
- package/README.md +174 -114
- package/dist/adapt/arms.js +109 -50
- package/dist/adapt/panelTasks.d.ts +2 -1
- package/dist/adapt/panelTasks.js +32 -9
- package/dist/adapt/textStream.d.ts +1 -1
- package/dist/adapt/textStream.js +58 -32
- package/dist/adapt/toolCards.js +9 -8
- package/dist/adapt.js +7 -1
- package/dist/adapter/activeRunSelfHeal.d.ts +31 -2
- package/dist/adapter/activeRunSelfHeal.js +162 -13
- package/dist/adapter/downstream/eventToSdkMessage.d.ts +25 -6
- package/dist/adapter/downstream/eventToSdkMessage.js +157 -20
- package/dist/adapter/downstream/terminalToSdkResult.d.ts +60 -1
- package/dist/adapter/downstream/terminalToSdkResult.js +219 -39
- package/dist/adapter/downstream/wiringManifestView.d.ts +3 -1
- package/dist/adapter/downstream/wiringManifestView.js +1 -0
- package/dist/adapter/runStream.d.ts +4 -4
- package/dist/adapter/runStream.js +184 -42
- package/dist/adapter/types.d.ts +2 -0
- package/dist/agentsWireCaps.d.ts +9 -7
- package/dist/agentsWireCaps.js +101 -17
- package/dist/approvalDecidedByCapability.js +2 -2
- package/dist/approvalFrameFamilies.d.ts +33 -0
- package/dist/approvalFrameFamilies.js +120 -0
- package/dist/approvalsStreamLiveCapability.js +2 -2
- package/dist/attachmentsWireCaps.js +41 -13
- package/dist/callerCwdCapability.js +2 -2
- package/dist/centerWiringCapability.js +2 -2
- package/dist/clockReading.d.ts +2 -0
- package/dist/clockReading.js +4 -0
- package/dist/cloudConfigWireCaps.d.ts +28 -5
- package/dist/cloudConfigWireCaps.js +334 -103
- package/dist/compactionStatus.d.ts +34 -0
- package/dist/compactionStatus.js +196 -0
- package/dist/coreValuePorts.d.ts +12 -2
- package/dist/coreValuePorts.js +9 -0
- package/dist/decideFailureNote.js +8 -6
- package/dist/decideReceipt.js +2 -2
- package/dist/deviceExecutorManagementCapability.js +2 -2
- package/dist/deviceFlowPolling.js +1 -1
- package/dist/disableSkillsWire.d.ts +1 -1
- package/dist/disableSkillsWire.js +4 -3
- package/dist/displayUntrusted.d.ts +1 -0
- package/dist/displayUntrusted.js +215 -13
- package/dist/engineAgentPanelStore.d.ts +7 -4
- package/dist/engineCapReader.js +1 -1
- package/dist/engineConfigDrift.js +1 -1
- package/dist/engineErrorCodes.d.ts +23 -6
- package/dist/engineErrorCodes.js +36 -11
- package/dist/engineGenerationConvergence.d.ts +39 -0
- package/dist/engineGenerationConvergence.js +95 -0
- package/dist/engineGenerationPort.d.ts +61 -0
- package/dist/engineGenerationPort.js +144 -0
- package/dist/engineHealthFacts.d.ts +23 -0
- package/dist/engineHealthFacts.js +92 -0
- package/dist/engineIdentity.d.ts +4 -0
- package/dist/engineIdentity.js +11 -0
- package/dist/engineNoticeCodes.d.ts +2 -5
- package/dist/engineRowRef.js +4 -0
- package/dist/engineSessionMessages.js +2 -2
- package/dist/engineToolDirectory.d.ts +3 -0
- package/dist/engineToolDirectory.js +6 -4
- package/dist/engineWireFor.d.ts +99 -0
- package/dist/engineWireFor.js +248 -6
- package/dist/engineWireTarget.d.ts +1 -0
- package/dist/engineWireTarget.js +8 -0
- package/dist/env/uiLanguage.js +1 -1
- package/dist/errorSupplementRoles.d.ts +3 -0
- package/dist/errorSupplementRoles.js +37 -0
- package/dist/eventLeg.d.ts +1 -7
- package/dist/eventLeg.js +7 -8
- package/dist/executionLaneCapability.js +2 -2
- package/dist/fileHistoryCaptureCapability.d.ts +0 -3
- package/dist/fileHistoryCaptureCapability.js +3 -7
- package/dist/finalVerifyWire.d.ts +6 -3
- package/dist/finalVerifyWire.js +6 -23
- package/dist/flagInput.d.ts +4 -0
- package/dist/flagInput.js +24 -0
- package/dist/fleet/fleetLedger.js +5 -2
- package/dist/fleet/fleetProjection.d.ts +1 -0
- package/dist/fleet/fleetProjection.js +15 -2
- package/dist/gateVocabulary.js +3 -0
- package/dist/generated/engineFactTables.d.ts +7 -2
- package/dist/generated/engineFactTables.js +79 -0
- package/dist/generated/engineNoticeTables.js +15 -0
- package/dist/generated/settingsSchemaActiveTiers.d.ts +1 -0
- package/dist/generated/settingsSchemaActiveTiers.js +14 -0
- package/dist/generated/settingsSchemaCallerTextEcho.d.ts +1 -0
- package/dist/generated/settingsSchemaCallerTextEcho.js +8 -0
- package/dist/generated/settingsSchemaControlAndBidi.d.ts +1 -0
- package/dist/generated/settingsSchemaControlAndBidi.js +8 -0
- package/dist/generated/settingsSchemaDefaultModel.d.ts +11 -0
- package/dist/generated/settingsSchemaDefaultModel.js +25 -0
- package/dist/generated/settingsSchemaFns.d.ts +66 -0
- package/dist/generated/settingsSchemaFns.js +38 -0
- package/dist/generated/settingsSchemaMcpRequestEntry.d.ts +1 -0
- package/dist/generated/settingsSchemaMcpRequestEntry.js +156 -0
- package/dist/generated/settingsSchemaSafetyMergeSpec.d.ts +1 -0
- package/dist/generated/settingsSchemaSafetyMergeSpec.js +95 -0
- package/dist/generated/settingsSchemaSettingsSources.d.ts +1 -0
- package/dist/generated/settingsSchemaSettingsSources.js +58 -0
- package/dist/generated/settingsSchemaTables.d.ts +3 -0
- package/dist/generated/settingsSchemaTables.js +18 -0
- package/dist/generated/settingsSchemaTypes.d.ts +28 -0
- package/dist/generated/settingsSchemaUrlPattern.d.ts +1 -0
- package/dist/generated/settingsSchemaUrlPattern.js +183 -0
- package/dist/headlessPermissionModeWire.d.ts +18 -2
- package/dist/headlessPermissionModeWire.js +30 -19
- package/dist/hitl/allowRuleShadow.js +9 -7
- package/dist/hitl/approvalCardReading.d.ts +3 -0
- package/dist/hitl/approvalCardReading.js +17 -0
- package/dist/hitl/approvalCardReasons.js +2 -2
- package/dist/hitl/approvalCompleteParked.js +1 -1
- package/dist/hitl/approvalDelivery.d.ts +87 -0
- package/dist/hitl/approvalDelivery.js +193 -0
- package/dist/hitl/approvalHolds.d.ts +14 -0
- package/dist/hitl/approvalHolds.js +41 -0
- package/dist/hitl/approvalResolution.d.ts +11 -0
- package/dist/hitl/approvalResolution.js +50 -11
- package/dist/hitl/askClassPair.d.ts +8 -2
- package/dist/hitl/askClassPair.js +31 -4
- package/dist/hitl/askParkAutoReopenBlock.d.ts +30 -0
- package/dist/hitl/askParkAutoReopenBlock.js +117 -0
- package/dist/hitl/askParkRowRouting.js +4 -1
- package/dist/hitl/attributionLadder.d.ts +62 -0
- package/dist/hitl/attributionLadder.js +138 -0
- package/dist/hitl/automaticAnswerVerdict.d.ts +6 -1
- package/dist/hitl/automaticAnswerVerdict.js +46 -11
- package/dist/hitl/crashConverged.js +2 -2
- package/dist/hitl/decisionConflict.d.ts +6 -2
- package/dist/hitl/decisionConflict.js +24 -9
- package/dist/hitl/decisionLedger.d.ts +55 -0
- package/dist/hitl/decisionLedger.js +156 -0
- package/dist/hitl/decisionRefusal.d.ts +21 -10
- package/dist/hitl/decisionRefusal.js +100 -55
- package/dist/hitl/decisionSend.d.ts +116 -0
- package/dist/hitl/decisionSend.js +563 -0
- package/dist/hitl/frameRouter.d.ts +1 -0
- package/dist/hitl/frameRouter.js +9 -2
- package/dist/hitl/hitlBridge.d.ts +18 -6
- package/dist/hitl/hitlBridge.js +59 -43
- package/dist/hitl/livePendingAsk.js +4 -3
- package/dist/hitl/noAllowCause.js +1 -1
- package/dist/hitl/parkResolver.js +3 -2
- package/dist/hitl/persistedRulesWire.js +1 -0
- package/dist/hitl/planReviewWire.d.ts +4 -0
- package/dist/hitl/planReviewWire.js +104 -106
- package/dist/hitl/resumeRunningCard.d.ts +3 -2
- package/dist/hitl/resumeRunningCard.js +17 -11
- package/dist/hitl/sessionPolicyDeliverable.d.ts +5 -2
- package/dist/hitl/sessionPolicyDeliverable.js +65 -35
- package/dist/hitl/sessionPolicyWire.d.ts +13 -3
- package/dist/hitl/sessionPolicyWire.js +81 -16
- package/dist/hitl/standingRows.js +1 -1
- package/dist/hitl/toolApprovalWire.d.ts +9 -10
- package/dist/hitl/toolApprovalWire.js +103 -151
- package/dist/hookMatcherVerdict.d.ts +2 -0
- package/dist/hookMatcherVerdict.js +12 -0
- package/dist/hooksCompactTransition.d.ts +19 -0
- package/dist/hooksCompactTransition.js +41 -0
- package/dist/hooksWireCaps.d.ts +1 -1
- package/dist/hooksWireCaps.js +202 -203
- package/dist/host.d.ts +1 -14
- package/dist/host.js +0 -8
- package/dist/hostCallbackGuard.d.ts +1 -0
- package/dist/hostCallbackGuard.js +1 -1
- package/dist/hostSettingsSource.d.ts +172 -0
- package/dist/hostSettingsSource.js +675 -0
- package/dist/hostTurnSettings.d.ts +114 -19
- package/dist/hostTurnSettings.js +966 -68
- package/dist/httpHookPolicy.d.ts +37 -0
- package/dist/httpHookPolicy.js +176 -0
- package/dist/humanTurn.d.ts +4 -2
- package/dist/humanTurn.js +40 -10
- package/dist/humanTurnRead.js +4 -3
- package/dist/humanTurnSentences.d.ts +10 -0
- package/dist/humanTurnSentences.js +74 -0
- package/dist/i18n/messages.en.d.ts +313 -0
- package/dist/i18n/messages.en.js +326 -13
- package/dist/i18n/messages.zh.js +341 -13
- package/dist/i18n/translate.js +3 -3
- package/dist/index.d.ts +85 -15
- package/dist/index.js +53 -12
- package/dist/inheritEnvCapability.d.ts +4 -1
- package/dist/inheritEnvCapability.js +38 -17
- package/dist/inheritEnvWire.d.ts +2 -1
- package/dist/inheritEnvWire.js +11 -5
- package/dist/injectionLaneNotice.d.ts +5 -0
- package/dist/injectionLaneNotice.js +46 -0
- package/dist/interactiveToolsWire.d.ts +4 -2
- package/dist/interactiveToolsWire.js +5 -5
- package/dist/jsonFaithful.d.ts +20 -0
- package/dist/jsonFaithful.js +152 -0
- package/dist/limitsWire.d.ts +7 -2
- package/dist/limitsWire.js +19 -13
- package/dist/liveInitToolFace.d.ts +6 -1
- package/dist/liveInitToolFace.js +5 -3
- package/dist/liveModelCatalog.d.ts +22 -0
- package/dist/liveModelCatalog.js +132 -18
- package/dist/mcpPanel.js +3 -1
- package/dist/mcpProbeCapability.js +2 -2
- package/dist/mcpReconnect.js +2 -2
- package/dist/mcpStatusSupersetKeys.d.ts +24 -0
- package/dist/mcpStatusSupersetKeys.js +45 -0
- package/dist/mcpToolToggles.d.ts +6 -0
- package/dist/mcpToolToggles.js +47 -0
- package/dist/mcpWireCaps.d.ts +48 -4
- package/dist/mcpWireCaps.js +338 -99
- package/dist/mcpWireTransport.d.ts +4 -0
- package/dist/mcpWireTransport.js +18 -0
- package/dist/memoryComplianceCapability.js +2 -2
- package/dist/memoryOriginCapability.js +2 -2
- package/dist/model/catalogDefault.d.ts +24 -0
- package/dist/model/catalogDefault.js +4 -0
- package/dist/model/liveCatalogShape.js +5 -4
- package/dist/model/modelsPolicy.js +4 -3
- package/dist/model/onboardJudgement.d.ts +1 -0
- package/dist/model/onboardJudgement.js +1 -1
- package/dist/model/subagentModelWord.js +2 -2
- package/dist/modelCapabilityProbe.d.ts +2 -1
- package/dist/modelCapabilityProbe.js +16 -15
- package/dist/modelIdentityResolvability.d.ts +12 -1
- package/dist/modelIdentityResolvability.js +69 -28
- package/dist/modsKernelIdentity.d.ts +10 -0
- package/dist/modsKernelIdentity.js +103 -0
- package/dist/modsKernelTransit.d.ts +8 -0
- package/dist/modsKernelTransit.js +6 -0
- package/dist/notifications.d.ts +30 -12
- package/dist/notifications.js +241 -53
- package/dist/outputStyleSeatCapability.js +2 -2
- package/dist/ownKey.d.ts +37 -0
- package/dist/ownKey.js +238 -2
- package/dist/panelReduce.d.ts +5 -0
- package/dist/panelReduce.js +45 -13
- package/dist/panelStateHolder.d.ts +1 -0
- package/dist/panelStateHolder.js +10 -1
- package/dist/peerFrames.d.ts +1 -1
- package/dist/peerFrames.js +6 -2
- package/dist/peerLaneCapability.js +2 -2
- package/dist/permissionModesCapability.js +4 -4
- package/dist/permissionRuleIssue.d.ts +2 -1
- package/dist/permissionRuleIssue.js +24 -21
- package/dist/permissionRulesWriteCapability.js +2 -2
- package/dist/permissionsAllowGrantCapability.js +2 -2
- package/dist/permissionsDeclaration.d.ts +43 -4
- package/dist/permissionsDeclaration.js +102 -35
- package/dist/pluginHooksWire.d.ts +20 -4
- package/dist/pluginHooksWire.js +101 -60
- package/dist/prepareRefusal.d.ts +9 -0
- package/dist/prepareRefusal.js +90 -0
- package/dist/printInitToolFace.js +2 -2
- package/dist/printModelStatus.js +1 -1
- package/dist/projectMemory.d.ts +32 -0
- package/dist/projectMemory.js +70 -0
- package/dist/promptBlockedCopy.d.ts +2 -1
- package/dist/promptBlockedCopy.js +2 -1
- package/dist/promptDelivery.d.ts +23 -3
- package/dist/promptDelivery.js +169 -30
- package/dist/providerRejection.d.ts +19 -1
- package/dist/providerRejection.js +75 -4
- package/dist/queuedDelivery.d.ts +48 -0
- package/dist/queuedDelivery.js +233 -0
- package/dist/reattachWindow.d.ts +94 -0
- package/dist/reattachWindow.js +127 -0
- package/dist/request/printNotification.d.ts +1 -1
- package/dist/request/printNotification.js +5 -1
- package/dist/request/submissionIdentity.d.ts +37 -0
- package/dist/request/submissionIdentity.js +65 -0
- package/dist/request/taskRequest.d.ts +22 -14
- package/dist/request/taskRequest.js +312 -202
- package/dist/resultFrameKeys.d.ts +1 -0
- package/dist/resultFrameKeys.js +4 -1
- package/dist/resumeRefusalCopy.d.ts +3 -1
- package/dist/resumeRefusalCopy.js +22 -4
- package/dist/retryStatus.d.ts +26 -0
- package/dist/retryStatus.js +133 -28
- package/dist/rewindArchiveCapability.js +2 -2
- package/dist/rewindEngineAction.d.ts +2 -0
- package/dist/rewindEngineAction.js +23 -1
- package/dist/rowKind.d.ts +36 -0
- package/dist/rowKind.js +97 -0
- package/dist/ruleCompileVerdict.d.ts +18 -0
- package/dist/ruleCompileVerdict.js +67 -2
- package/dist/ruleReadings.d.ts +58 -0
- package/dist/ruleReadings.js +132 -0
- package/dist/ruleRefusalSentence.d.ts +8 -0
- package/dist/ruleRefusalSentence.js +64 -0
- package/dist/runCancelContext.d.ts +0 -1
- package/dist/runCancelContext.js +1 -2
- package/dist/runTerminal.d.ts +5 -0
- package/dist/runTerminal.js +52 -17
- package/dist/sandboxWire.d.ts +3 -2
- package/dist/sandboxWire.js +59 -27
- package/dist/scenarioRefusal.d.ts +2 -1
- package/dist/scenarioRefusal.js +6 -6
- package/dist/scenarioSkills.d.ts +20 -0
- package/dist/scenarioSkills.js +72 -0
- package/dist/scenarioWire.d.ts +5 -2
- package/dist/scenarioWire.js +9 -9
- package/dist/sealedKeyCapability.js +2 -2
- package/dist/seam.d.ts +26 -9
- package/dist/seam.js +44 -4
- package/dist/seatContract.d.ts +62 -9
- package/dist/seatContract.js +70 -25
- package/dist/selfOrchestrationDenial.js +1 -1
- package/dist/sessionPolicyCapability.js +2 -2
- package/dist/sessionRulesChildrenReadLive.d.ts +6 -0
- package/dist/sessionRulesChildrenReadLive.js +5 -0
- package/dist/sessionRulesNamespaceFormsCapability.d.ts +12 -0
- package/dist/sessionRulesNamespaceFormsCapability.js +29 -0
- package/dist/sessionSyncFileHistoryCapability.js +2 -2
- package/dist/settingsCredentialKeyPaths.d.ts +8 -0
- package/dist/settingsCredentialKeyPaths.js +274 -0
- package/dist/settingsHooksSalvage.d.ts +1 -0
- package/dist/settingsHooksSalvage.js +7 -1
- package/dist/settingsLayerAdmission.d.ts +4 -0
- package/dist/settingsLayerAdmission.js +16 -0
- package/dist/skillToolListsCapability.js +6 -5
- package/dist/skillsWireCaps.d.ts +14 -3
- package/dist/skillsWireCaps.js +48 -18
- package/dist/slashCommandGate.d.ts +24 -0
- package/dist/slashCommandGate.js +74 -0
- package/dist/slashCommandTable.d.ts +14 -0
- package/dist/slashCommandTable.js +99 -0
- package/dist/sqlEngineCapability.js +2 -2
- package/dist/steerPriorityCapability.js +2 -2
- package/dist/storePostureCapability.js +2 -2
- package/dist/subagent/agentStateDetail.js +1 -1
- package/dist/subagent/engineDelegatedPrompt.d.ts +9 -0
- package/dist/subagent/engineDelegatedPrompt.js +38 -7
- package/dist/subagent/engineRowStopGate.js +2 -2
- package/dist/subagent/engineSubagentResume.js +3 -3
- package/dist/subagent/engineTaskHandleWire.d.ts +1 -0
- package/dist/subagent/engineTaskHandleWire.js +10 -0
- package/dist/subagentContentStore.d.ts +1 -0
- package/dist/subagentContentStore.js +135 -27
- package/dist/submitFailure.d.ts +8 -0
- package/dist/submitFailure.js +17 -0
- package/dist/supportFloor.d.ts +1 -0
- package/dist/supportFloor.js +7 -0
- package/dist/terminationIntent.d.ts +55 -0
- package/dist/terminationIntent.js +352 -0
- package/dist/toolHistoryMismatch.d.ts +8 -0
- package/dist/toolHistoryMismatch.js +37 -6
- package/dist/toolResult.d.ts +13 -3
- package/dist/toolResult.js +158 -9
- package/dist/toolResultContent.d.ts +13 -0
- package/dist/toolResultContent.js +82 -7
- package/dist/toolRoster.d.ts +18 -0
- package/dist/toolRoster.js +64 -0
- package/dist/toolsFlagNames.d.ts +8 -0
- package/dist/toolsFlagNames.js +110 -0
- package/dist/turnFailurePresentation.js +41 -96
- package/dist/usageLimitAutoResume.d.ts +74 -0
- package/dist/usageLimitAutoResume.js +227 -0
- package/dist/userAttachmentEnvelope.js +1 -1
- package/dist/userAttachmentSeat.js +5 -5
- package/dist/userInvokedSkillsCapability.js +2 -2
- package/dist/webSearchBackendCapability.js +2 -2
- package/dist/wireErrorTriage.js +99 -50
- package/dist/wireFailureShape.d.ts +25 -1
- package/dist/wireFailureShape.js +92 -5
- package/dist/wireRefusalCopy.d.ts +75 -18
- package/dist/wireRefusalCopy.js +532 -148
- package/dist/wiringFleetDoctor.d.ts +3 -0
- package/dist/wiringFleetDoctor.js +21 -0
- package/dist/workflow.d.ts +2 -1
- package/dist/workflow.js +38 -1
- package/dist/workflowClient.d.ts +2 -7
- package/dist/workflowsJournalCapability.js +2 -2
- package/dist/writeProtectionCapability.js +2 -2
- package/docs/INTEGRATION-CLIENTS.md +1013 -190
- package/package.json +15 -4
|
@@ -0,0 +1,563 @@
|
|
|
1
|
+
import { settleWithinDeadline } from '../abortableSleep.js';
|
|
2
|
+
import { hostLog } from '../host.js';
|
|
3
|
+
import { msg, renderMessage } from '../i18n/translate.js';
|
|
4
|
+
import { askGoneFromError } from '../decideReceipt.js';
|
|
5
|
+
import { appendOwnElement, guardedRead, readOwnDataNonEmptyString, readOwnDataValue } from '../ownKey.js';
|
|
6
|
+
import { effectiveCodeOf, ownReadingSlot } from '../engineWireFor.js';
|
|
7
|
+
import { ASK_DECISION_LANE_DISABLED, ASK_GONE, ASK_GONE_PARKED, ASK_IDEMPOTENCY_CONFLICT, ASK_NOT_FOUND, ASK_PARKING_RETRY } from '../engineErrorCodes.js';
|
|
8
|
+
import { isSlotCarrier, readErrorNumber, readErrorString, readThrownSlot } from '../wireFailureShape.js';
|
|
9
|
+
import { readDecisionNoteAudit } from './approvalDecisionNoteAudit.js';
|
|
10
|
+
import { carrierReadOf, deliverWithAttributionLadder, isLocalSafetyStop } from './attributionLadder.js';
|
|
11
|
+
import { budgetSpent, deliverApprovalDecision, deliveryTiming, isAborted, newSendTally, PARKING_WAIT_CAP_MS, setDeliveryTimingForTests, sleepFor, settledTransportReadingOf, withTransportRetry, deliveryReadingOf, } from './approvalDelivery.js';
|
|
12
|
+
import { ASK_DECIDED_CODE, classifyDeliveredDecisionRefusal, decisionRefusalClosesOut, notPendingAfterRetry } from './decisionRefusal.js';
|
|
13
|
+
import { addDecisionOpKeys, closeDecisionOp, decisionLedgerKeysOf, decisionOpsWithKey, openDecisionOp } from './decisionLedger.js';
|
|
14
|
+
import { hostHoldIsActive, takeHostHoldLedgerOp, tryHoldApprovalNow } from './approvalHolds.js';
|
|
15
|
+
import { answerPayloadFor, decisionAttributionKeyOf, isToolApprovalRespondReplayed, readApprovalDenySettledBy, readToolApprovalRespondAck, readToolApprovalRespondParking, } from './toolApprovalWire.js';
|
|
16
|
+
export const HITL_DECISION_FAMILIES = Object.freeze(['approval', 'ask', 'elicitation']);
|
|
17
|
+
export const HITL_DECISION_NOT_APPLIED_CAUSES = Object.freeze(['gone', 'parked', 'parking', 'lane_disabled', 'refused', 'idempotency_crossed']);
|
|
18
|
+
export const HITL_DECISION_UNCONFIRMED_CAUSES = Object.freeze(['transport', 'server_error', 'local_error', 'aborted', 'gone_after_retry']);
|
|
19
|
+
export const HITL_DECISION_NOT_SENT_CAUSES = Object.freeze(['aborted', 'duplicate_in_flight', 'invalid_request', 'no_verb', 'not_an_answer']);
|
|
20
|
+
const PARKING_POLL_MAX = 2;
|
|
21
|
+
const PARKING_POLL_DELAY_MS = 400;
|
|
22
|
+
export const HITL_DECISION_READBACK_BUDGET_MS = 4_000;
|
|
23
|
+
const IDEMPOTENCY_KEY_MAX = 255;
|
|
24
|
+
export function __setHitlDecisionSendTimingForTests(t) {
|
|
25
|
+
setDeliveryTimingForTests(t);
|
|
26
|
+
}
|
|
27
|
+
export function hitlAskIdempotencyKey(askId, verdict) {
|
|
28
|
+
const key = `sema-ask:${askId}:${verdict}`;
|
|
29
|
+
return key.length <= IDEMPOTENCY_KEY_MAX ? key : key.slice(0, IDEMPOTENCY_KEY_MAX);
|
|
30
|
+
}
|
|
31
|
+
function retryAfterMsOf(e) {
|
|
32
|
+
if (!isSlotCarrier(e))
|
|
33
|
+
return undefined;
|
|
34
|
+
const ms = readErrorNumber(e, 'retryAfterMs');
|
|
35
|
+
if (ms !== undefined && Number.isFinite(ms) && ms >= 0)
|
|
36
|
+
return ms;
|
|
37
|
+
const sec = readErrorNumber(e, 'retryAfterSec');
|
|
38
|
+
return sec !== undefined && Number.isFinite(sec) && sec >= 0 ? sec * 1000 : undefined;
|
|
39
|
+
}
|
|
40
|
+
function actorLabelOf(e) {
|
|
41
|
+
const actor = readThrownSlot(e, 'actor', 'data');
|
|
42
|
+
if (typeof actor !== 'object' || actor === null)
|
|
43
|
+
return undefined;
|
|
44
|
+
const label = guardedRead(() => readOwnDataNonEmptyString(actor, 'label'));
|
|
45
|
+
if (label !== undefined)
|
|
46
|
+
return label;
|
|
47
|
+
const id = guardedRead(() => readOwnDataNonEmptyString(actor, 'id'));
|
|
48
|
+
return id !== undefined && id !== '_' ? id : undefined;
|
|
49
|
+
}
|
|
50
|
+
function verdictOf(word) {
|
|
51
|
+
return word === 'approve' || word === 'allow' || word === 'allow_session' ? 'approve' : word === 'deny' ? 'deny' : undefined;
|
|
52
|
+
}
|
|
53
|
+
function outcomeOfThrown(e, family, ours, signal, tally, noteCapable, reading = settledTransportReadingOf(e, signal, tally)) {
|
|
54
|
+
const base = { family, attempts: tally.attempts };
|
|
55
|
+
const cls = reading.cls;
|
|
56
|
+
if (cls === 'aborted')
|
|
57
|
+
return { ...base, kind: 'unconfirmed', cause: 'aborted' };
|
|
58
|
+
if (cls === 'transport')
|
|
59
|
+
return { ...base, kind: 'unconfirmed', cause: 'transport' };
|
|
60
|
+
if (cls === 'local_error')
|
|
61
|
+
return { ...base, kind: 'unconfirmed', cause: 'local_error' };
|
|
62
|
+
const answered = ownReadingSlot(reading, 'answered');
|
|
63
|
+
if (answered === undefined)
|
|
64
|
+
return { ...base, kind: 'unconfirmed', cause: 'local_error' };
|
|
65
|
+
return answeredOutcome(answered.layer, answered.status, reading, cls, family, ours, tally, noteCapable, base);
|
|
66
|
+
}
|
|
67
|
+
function answeredOutcome(e, status, reading, cls, family, ours, tally, noteCapable, base) {
|
|
68
|
+
const obj = e;
|
|
69
|
+
if (cls === 'server_5xx')
|
|
70
|
+
return { ...base, kind: 'unconfirmed', cause: 'server_error', status };
|
|
71
|
+
const answeredCapture = ownReadingSlot(reading, 'answered');
|
|
72
|
+
const code = answeredCapture !== undefined ? effectiveCodeOf(answeredCapture.code) : undefined;
|
|
73
|
+
const at = { ...base, status, ...(code !== undefined ? { errorCode: code } : {}) };
|
|
74
|
+
const retried = family !== 'ask' && tally.retried;
|
|
75
|
+
if (retried && notPendingAfterRetry(status, true))
|
|
76
|
+
return { ...base, kind: 'unconfirmed', cause: 'gone_after_retry', status };
|
|
77
|
+
if (isSafetyStopLayer(e, reading))
|
|
78
|
+
return { ...at, kind: 'not_applied', cause: 'refused', ...refusalOf(e, reading) };
|
|
79
|
+
if (family === 'ask') {
|
|
80
|
+
switch (code) {
|
|
81
|
+
case ASK_DECIDED_CODE: {
|
|
82
|
+
const first = verdictOf(readErrorString(obj, 'firstDecision'));
|
|
83
|
+
const decidedAtMs = readErrorNumber(obj, 'decidedAtMs');
|
|
84
|
+
const actorLabel = actorLabelOf(obj);
|
|
85
|
+
const note = readErrorString(obj, 'decisionNote');
|
|
86
|
+
return {
|
|
87
|
+
...base,
|
|
88
|
+
kind: 'settled_elsewhere',
|
|
89
|
+
...(first !== undefined ? { firstDecision: first } : {}),
|
|
90
|
+
...(first !== undefined && ours !== undefined && first !== ours ? { contrary: true } : {}),
|
|
91
|
+
...(decidedAtMs !== undefined ? { decidedAtMs } : {}),
|
|
92
|
+
...(actorLabel !== undefined ? { actorLabel } : {}),
|
|
93
|
+
...(noteCapable && note !== undefined ? { noteAudit: readDecisionNoteAudit({ decisionNote: note }) } : {}),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
case ASK_IDEMPOTENCY_CONFLICT:
|
|
97
|
+
return { ...at, kind: 'not_applied', cause: 'idempotency_crossed', ...refusalOf(e, reading) };
|
|
98
|
+
case ASK_GONE_PARKED: {
|
|
99
|
+
const sessionId = readErrorString(obj, 'sessionId');
|
|
100
|
+
return { ...at, kind: 'not_applied', cause: 'parked', ...(sessionId !== undefined ? { sessionId } : {}) };
|
|
101
|
+
}
|
|
102
|
+
case ASK_GONE: {
|
|
103
|
+
const gone = askGoneFromError(e);
|
|
104
|
+
return { ...at, kind: 'not_applied', cause: 'gone', ...(gone !== null ? { gone } : {}) };
|
|
105
|
+
}
|
|
106
|
+
case ASK_PARKING_RETRY: {
|
|
107
|
+
const retryAfterMs = retryAfterMsOf(e);
|
|
108
|
+
return { ...at, kind: 'not_applied', cause: 'parking', ...(retryAfterMs !== undefined ? { retryAfterMs } : {}) };
|
|
109
|
+
}
|
|
110
|
+
case ASK_DECISION_LANE_DISABLED:
|
|
111
|
+
return { ...at, kind: 'not_applied', cause: 'lane_disabled' };
|
|
112
|
+
case ASK_NOT_FOUND:
|
|
113
|
+
return { ...at, kind: 'not_applied', cause: 'gone' };
|
|
114
|
+
default:
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (status === 404 || status === 410)
|
|
119
|
+
return { ...at, kind: 'not_applied', cause: 'gone' };
|
|
120
|
+
if (status === 501)
|
|
121
|
+
return { ...at, kind: 'not_applied', cause: 'lane_disabled' };
|
|
122
|
+
return { ...at, kind: 'not_applied', cause: 'refused', ...refusalOf(e, reading) };
|
|
123
|
+
}
|
|
124
|
+
function isSafetyStopLayer(layer, reading) {
|
|
125
|
+
return isLocalSafetyStop(carrierReadOf(layer, reading), reading);
|
|
126
|
+
}
|
|
127
|
+
function refusalOf(e, reading) {
|
|
128
|
+
const r = classifyDeliveredDecisionRefusal(e, reading);
|
|
129
|
+
return r !== undefined ? { refusal: r } : {};
|
|
130
|
+
}
|
|
131
|
+
async function sendApprovalFamily(respond, approvalId, answer, ctx) {
|
|
132
|
+
const payload = answerPayloadFor(answer, 'respond', { approvalDecisionNoteCapable: ctx.noteCapable });
|
|
133
|
+
if (payload === undefined)
|
|
134
|
+
return { family: 'approval', attempts: ctx.tally.attempts, kind: 'not_sent', cause: 'not_an_answer' };
|
|
135
|
+
const attribution = answer.kind === 'deny' ? decisionAttributionKeyOf(ctx.decidedBy, readApprovalDenySettledBy(answer)) : {};
|
|
136
|
+
const body = { ...payload, ...attribution };
|
|
137
|
+
const ladder = { lastCarried: false, dropped: false, renamed: false };
|
|
138
|
+
const ours = verdictOf(payload.decision);
|
|
139
|
+
const extras = bodyFacts(answer, payload, false);
|
|
140
|
+
const delivery = await deliverApprovalDecision({
|
|
141
|
+
approvalId,
|
|
142
|
+
body,
|
|
143
|
+
send: (b, signal) => respond(approvalId, b, signal !== undefined ? { signal } : undefined),
|
|
144
|
+
signal: ctx.signal,
|
|
145
|
+
tally: ctx.tally,
|
|
146
|
+
ladder,
|
|
147
|
+
parkingOf: (raw) => {
|
|
148
|
+
const p = readToolApprovalRespondParking(raw);
|
|
149
|
+
return p?.kind === 'parking' ? p.view : undefined;
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
const retriedFact = ownReadingSlot(delivery, 'parkingRetried') === true ? { parkingRetried: true } : {};
|
|
153
|
+
if (delivery.kind === 'thrown')
|
|
154
|
+
return { ...outcomeOfThrown(delivery.error, 'approval', ours, ctx.signal, ctx.tally, ctx.noteCapable), ...extras, ...retriedFact };
|
|
155
|
+
const raw = delivery.raw;
|
|
156
|
+
const facts = { ...extras, ...retriedFact, ...(ladder.dropped ? { attributionDropped: true } : {}), ...(ladder.renamed ? { attributionRenamed: true } : {}) };
|
|
157
|
+
const base = { family: 'approval', attempts: ctx.tally.attempts, ...facts };
|
|
158
|
+
const parking = readToolApprovalRespondParking(raw);
|
|
159
|
+
if (parking !== undefined) {
|
|
160
|
+
const view = parking.kind === 'parking' && parking.view.approvalId === approvalId ? parking.view : undefined;
|
|
161
|
+
const hint = view !== undefined ? ownReadingSlot(view, 'retryAfterMs') : undefined;
|
|
162
|
+
return { ...base, kind: 'not_applied', cause: 'parking', ...(view !== undefined ? { parking: view, ...(hint !== undefined ? { retryAfterMs: hint } : {}) } : {}) };
|
|
163
|
+
}
|
|
164
|
+
const parsed = readToolApprovalRespondAck(raw);
|
|
165
|
+
if (parsed !== undefined && isToolApprovalRespondReplayed(parsed)) {
|
|
166
|
+
const first = parsed.approvalId === approvalId ? verdictOf(parsed.decision) : undefined;
|
|
167
|
+
return {
|
|
168
|
+
...base,
|
|
169
|
+
kind: 'settled_elsewhere',
|
|
170
|
+
...(first !== undefined ? { firstDecision: first } : {}),
|
|
171
|
+
...(first !== undefined && ours !== undefined && first !== ours ? { contrary: true } : {}),
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
if (ownTrue(raw, 'idempotent'))
|
|
175
|
+
return { ...base, kind: 'settled_elsewhere' };
|
|
176
|
+
const ack = parsed !== undefined && parsed.approvalId === approvalId ? parsed : undefined;
|
|
177
|
+
return { ...base, kind: 'applied', ...(ack !== undefined ? { ack } : {}), ...(ctx.noteCapable ? { noteAudit: readDecisionNoteAudit(raw) } : {}) };
|
|
178
|
+
}
|
|
179
|
+
function bodyFacts(answer, payload, rememberUnsupported) {
|
|
180
|
+
const reason = answer.kind === 'deny' && typeof answer.reason === 'string' ? answer.reason : undefined;
|
|
181
|
+
return {
|
|
182
|
+
...(reason !== undefined && reason.trim() !== '' && payload.note === undefined ? { noteDropped: true } : {}),
|
|
183
|
+
...(rememberUnsupported && answer.kind === 'allow' && answer.allowSession === true ? { rememberDropped: true } : {}),
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
function ownTrue(raw, key) {
|
|
187
|
+
return typeof raw === 'object' && raw !== null && guardedRead(() => readOwnDataValue(raw, key)) === true;
|
|
188
|
+
}
|
|
189
|
+
async function sendAskFamily(respondForFallback, decideAsk, req, ctx) {
|
|
190
|
+
const payload = answerPayloadFor(req.answer, 'respond', { approvalDecisionNoteCapable: ctx.noteCapable });
|
|
191
|
+
if (payload === undefined)
|
|
192
|
+
return { family: 'ask', attempts: ctx.tally.attempts, kind: 'not_sent', cause: 'not_an_answer' };
|
|
193
|
+
const verdict = verdictOf(payload.decision) ?? 'deny';
|
|
194
|
+
const attribution = req.answer.kind === 'deny' ? decisionAttributionKeyOf(ctx.decidedBy, readApprovalDenySettledBy(req.answer)) : {};
|
|
195
|
+
const body = {
|
|
196
|
+
decision: verdict,
|
|
197
|
+
idempotencyKey: hitlAskIdempotencyKey(req.askId, verdict),
|
|
198
|
+
...(verdict === 'approve' && payload.updatedInput !== undefined ? { updatedInput: payload.updatedInput } : {}),
|
|
199
|
+
...(payload.note !== undefined ? { note: payload.note } : {}),
|
|
200
|
+
...attribution,
|
|
201
|
+
};
|
|
202
|
+
const extras = bodyFacts(req.answer, payload, true);
|
|
203
|
+
const ladder = { lastCarried: false, dropped: false, renamed: false };
|
|
204
|
+
let current = body;
|
|
205
|
+
const parkingDelay = deliveryTiming().parkingDelayMs ?? PARKING_POLL_DELAY_MS;
|
|
206
|
+
for (let poll = 0;; poll++) {
|
|
207
|
+
try {
|
|
208
|
+
const raw = await deliverWithAttributionLadder(current, (b) => {
|
|
209
|
+
current = b;
|
|
210
|
+
return withTransportRetry((signal) => decideAsk(req.taskId, req.askId, b, signal !== undefined ? { signal } : undefined), ctx.signal, ctx.tally);
|
|
211
|
+
}, ctx.signal, ladder, undefined, { kind: 'delivered', readingOf: (thrown) => deliveryReadingOf(thrown, ctx.tally) });
|
|
212
|
+
return {
|
|
213
|
+
family: 'ask',
|
|
214
|
+
attempts: ctx.tally.attempts,
|
|
215
|
+
...extras,
|
|
216
|
+
...(ladder.dropped ? { attributionDropped: true } : {}),
|
|
217
|
+
...(ladder.renamed ? { attributionRenamed: true } : {}),
|
|
218
|
+
kind: 'applied',
|
|
219
|
+
...(ctx.noteCapable ? { noteAudit: readDecisionNoteAudit(raw) } : {}),
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
catch (e) {
|
|
223
|
+
const settled = settledTransportReadingOf(e, ctx.signal, ctx.tally);
|
|
224
|
+
const settledAnswer = ownReadingSlot(settled, 'answered');
|
|
225
|
+
const code = settledAnswer !== undefined ? effectiveCodeOf(settledAnswer.code) : undefined;
|
|
226
|
+
const wait = Math.max(parkingDelay * (poll + 1), retryAfterMsOf(settledAnswer?.layer ?? e) ?? 0);
|
|
227
|
+
const safetyStop = settledAnswer !== undefined && isSafetyStopLayer(settledAnswer.layer, settled);
|
|
228
|
+
if (code === ASK_PARKING_RETRY && !safetyStop && poll < PARKING_POLL_MAX && !isAborted(ctx.signal) && wait <= PARKING_WAIT_CAP_MS && !budgetSpent(ctx.tally, wait)) {
|
|
229
|
+
await sleepFor(wait, ctx.signal);
|
|
230
|
+
if (!isAborted(ctx.signal))
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
const out = outcomeOfThrown(e, 'ask', verdict, ctx.signal, ctx.tally, ctx.noteCapable, settled);
|
|
234
|
+
if (out.kind === 'not_applied' && out.cause === 'lane_disabled' && code === ASK_DECISION_LANE_DISABLED && req.approvalId !== undefined) {
|
|
235
|
+
if (respondForFallback !== undefined && ctx.signal?.aborted !== true) {
|
|
236
|
+
const fb = await sendApprovalFamily(respondForFallback, req.approvalId, req.answer, ctx);
|
|
237
|
+
return { ...fb, family: 'ask', fallback: 'approval' };
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return { ...out, ...extras };
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
function validElicitResponse(r) {
|
|
245
|
+
if (typeof r !== 'object' || r === null)
|
|
246
|
+
return undefined;
|
|
247
|
+
const action = guardedRead(() => readOwnDataValue(r, 'action'));
|
|
248
|
+
if (action !== 'accept' && action !== 'decline' && action !== 'cancel')
|
|
249
|
+
return undefined;
|
|
250
|
+
const content = guardedRead(() => readOwnDataValue(r, 'content'));
|
|
251
|
+
if (content === undefined)
|
|
252
|
+
return Object.freeze({ action });
|
|
253
|
+
if (action !== 'accept' || typeof content !== 'object' || content === null || Array.isArray(content))
|
|
254
|
+
return undefined;
|
|
255
|
+
const out = {};
|
|
256
|
+
try {
|
|
257
|
+
for (const k of Object.keys(content)) {
|
|
258
|
+
const v = readOwnDataValue(content, k);
|
|
259
|
+
if (typeof v === 'string' || typeof v === 'boolean' || (typeof v === 'number' && Number.isFinite(v)))
|
|
260
|
+
Object.defineProperty(out, k, { value: v, enumerable: true, writable: true, configurable: true });
|
|
261
|
+
else if (Array.isArray(v)) {
|
|
262
|
+
const copy = [];
|
|
263
|
+
for (let i = 0; i < v.length; i++) {
|
|
264
|
+
const x = readOwnDataValue(v, String(i));
|
|
265
|
+
if (typeof x !== 'string')
|
|
266
|
+
return undefined;
|
|
267
|
+
appendOwnElement(copy, x);
|
|
268
|
+
}
|
|
269
|
+
Object.defineProperty(out, k, { value: copy, enumerable: true, writable: true, configurable: true });
|
|
270
|
+
}
|
|
271
|
+
else
|
|
272
|
+
return undefined;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
catch {
|
|
276
|
+
return undefined;
|
|
277
|
+
}
|
|
278
|
+
return Object.freeze({ action, content: out });
|
|
279
|
+
}
|
|
280
|
+
function verbOf(holder, name) {
|
|
281
|
+
if (typeof holder !== 'object' || holder === null)
|
|
282
|
+
return undefined;
|
|
283
|
+
try {
|
|
284
|
+
const fn = holder[name];
|
|
285
|
+
if (typeof fn !== 'function')
|
|
286
|
+
return undefined;
|
|
287
|
+
const bound = (...args) => {
|
|
288
|
+
try {
|
|
289
|
+
return Promise.resolve(fn.apply(holder, args));
|
|
290
|
+
}
|
|
291
|
+
catch (e) {
|
|
292
|
+
return Promise.reject(e);
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
return bound;
|
|
296
|
+
}
|
|
297
|
+
catch {
|
|
298
|
+
return undefined;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
function signalOf(v) {
|
|
302
|
+
try {
|
|
303
|
+
return v instanceof AbortSignal ? v : undefined;
|
|
304
|
+
}
|
|
305
|
+
catch {
|
|
306
|
+
return undefined;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
function holdOf(v) {
|
|
310
|
+
if (typeof v !== 'object' || v === null)
|
|
311
|
+
return undefined;
|
|
312
|
+
try {
|
|
313
|
+
const h = v;
|
|
314
|
+
return typeof h.sending === 'function' && typeof h.release === 'function' ? h : undefined;
|
|
315
|
+
}
|
|
316
|
+
catch {
|
|
317
|
+
return undefined;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
function holdFits(handle, req) {
|
|
321
|
+
try {
|
|
322
|
+
const id = handle.identity;
|
|
323
|
+
if (typeof id.approvalId === 'string' && id.approvalId !== '')
|
|
324
|
+
return id.approvalId === req.approvalId;
|
|
325
|
+
if (typeof id.toolCallId !== 'string' || id.toolCallId === '' || id.toolCallId !== req.toolCallId)
|
|
326
|
+
return false;
|
|
327
|
+
return typeof id.taskId !== 'string' || id.taskId === '' || id.taskId === req.taskId;
|
|
328
|
+
}
|
|
329
|
+
catch {
|
|
330
|
+
return false;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
function callHold(call) {
|
|
334
|
+
try {
|
|
335
|
+
call();
|
|
336
|
+
}
|
|
337
|
+
catch (e) {
|
|
338
|
+
hostLog('debug', `decisionSend.callHold: ${String(e).slice(0, 120)}`);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
function hostField(holder, key) {
|
|
342
|
+
if (typeof holder !== 'object' || holder === null)
|
|
343
|
+
return undefined;
|
|
344
|
+
try {
|
|
345
|
+
return holder[key];
|
|
346
|
+
}
|
|
347
|
+
catch {
|
|
348
|
+
return undefined;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
function snapshotAnswer(raw) {
|
|
352
|
+
const kind = guardedRead(() => readOwnDataValue(raw, 'kind'));
|
|
353
|
+
if (kind === 'allow') {
|
|
354
|
+
const allowSession = guardedRead(() => readOwnDataValue(raw, 'allowSession')) === true;
|
|
355
|
+
const edited = guardedRead(() => readOwnDataValue(raw, 'updatedInput'));
|
|
356
|
+
if (edited === undefined)
|
|
357
|
+
return Object.freeze({ kind: 'allow', allowSession });
|
|
358
|
+
let copy;
|
|
359
|
+
try {
|
|
360
|
+
const text = JSON.stringify(edited);
|
|
361
|
+
if (typeof text !== 'string')
|
|
362
|
+
return undefined;
|
|
363
|
+
copy = JSON.parse(text);
|
|
364
|
+
}
|
|
365
|
+
catch {
|
|
366
|
+
return undefined;
|
|
367
|
+
}
|
|
368
|
+
return Object.freeze({ kind: 'allow', allowSession, updatedInput: copy });
|
|
369
|
+
}
|
|
370
|
+
if (kind === 'deny') {
|
|
371
|
+
const reason = guardedRead(() => readOwnDataValue(raw, 'reason'));
|
|
372
|
+
const settledBy = readApprovalDenySettledBy(raw);
|
|
373
|
+
return Object.freeze({ kind: 'deny', ...(typeof reason === 'string' ? { reason } : {}), ...(settledBy !== undefined ? { settledBy } : {}) });
|
|
374
|
+
}
|
|
375
|
+
return typeof kind === 'string' ? Object.freeze({ kind }) : undefined;
|
|
376
|
+
}
|
|
377
|
+
function readRequest(req) {
|
|
378
|
+
if (typeof req !== 'object' || req === null)
|
|
379
|
+
return undefined;
|
|
380
|
+
const s = (k) => guardedRead(() => readOwnDataNonEmptyString(req, k));
|
|
381
|
+
const family = s('family');
|
|
382
|
+
if (family === 'elicitation') {
|
|
383
|
+
const elicitationId = s('elicitationId');
|
|
384
|
+
const response = validElicitResponse(guardedRead(() => readOwnDataValue(req, 'response')));
|
|
385
|
+
return elicitationId !== undefined && response !== undefined ? { family, elicitationId, taskId: s('taskId'), response } : undefined;
|
|
386
|
+
}
|
|
387
|
+
const rawAnswer = guardedRead(() => readOwnDataValue(req, 'answer'));
|
|
388
|
+
if (typeof rawAnswer !== 'object' || rawAnswer === null)
|
|
389
|
+
return undefined;
|
|
390
|
+
const answer = snapshotAnswer(rawAnswer);
|
|
391
|
+
if (answer === undefined)
|
|
392
|
+
return undefined;
|
|
393
|
+
if (family === 'approval') {
|
|
394
|
+
const approvalId = s('approvalId');
|
|
395
|
+
return approvalId !== undefined ? { family, approvalId, taskId: s('taskId'), toolCallId: s('toolCallId'), answer } : undefined;
|
|
396
|
+
}
|
|
397
|
+
if (family === 'ask') {
|
|
398
|
+
const taskId = s('taskId');
|
|
399
|
+
const askId = s('askId');
|
|
400
|
+
return taskId !== undefined && askId !== undefined ? { family, taskId, askId, approvalId: s('approvalId'), toolCallId: s('toolCallId'), answer } : undefined;
|
|
401
|
+
}
|
|
402
|
+
return undefined;
|
|
403
|
+
}
|
|
404
|
+
function latchKeysOf(r) {
|
|
405
|
+
if (r.family === 'elicitation')
|
|
406
|
+
return decisionLedgerKeysOf({ elicitationId: r.elicitationId });
|
|
407
|
+
if (r.family === 'ask')
|
|
408
|
+
return decisionLedgerKeysOf({ askId: r.askId, approvalId: r.approvalId });
|
|
409
|
+
return decisionLedgerKeysOf({ approvalId: r.approvalId });
|
|
410
|
+
}
|
|
411
|
+
function ledgerFamilyOf(family) {
|
|
412
|
+
return family === 'elicitation' ? 'elicitation' : 'tool_approval';
|
|
413
|
+
}
|
|
414
|
+
async function readBack(deps, gate) {
|
|
415
|
+
const port = hostField(deps, 'readPending');
|
|
416
|
+
if (typeof port !== 'function')
|
|
417
|
+
return undefined;
|
|
418
|
+
const settled = await settleWithinDeadline(HITL_DECISION_READBACK_BUDGET_MS, (signal) => Promise.resolve(port.call(deps, gate, { signal })));
|
|
419
|
+
if (settled.kind !== 'value')
|
|
420
|
+
return 'unknown';
|
|
421
|
+
return settled.value === 'pending' || settled.value === 'not_pending' ? settled.value : 'unknown';
|
|
422
|
+
}
|
|
423
|
+
export async function sendHitlDecision(request, deps) {
|
|
424
|
+
const familyRead = typeof request === 'object' && request !== null ? guardedRead(() => readOwnDataNonEmptyString(request, 'family')) : undefined;
|
|
425
|
+
const family = familyRead === 'ask' || familyRead === 'elicitation' ? familyRead : 'approval';
|
|
426
|
+
const notSent = (cause) => Object.freeze({ family, attempts: 0, kind: 'not_sent', cause });
|
|
427
|
+
let req;
|
|
428
|
+
try {
|
|
429
|
+
req = readRequest(request);
|
|
430
|
+
}
|
|
431
|
+
catch {
|
|
432
|
+
req = undefined;
|
|
433
|
+
}
|
|
434
|
+
if (req === undefined)
|
|
435
|
+
return notSent('invalid_request');
|
|
436
|
+
const signal = signalOf(hostField(deps, 'signal'));
|
|
437
|
+
const client = hostField(deps, 'client');
|
|
438
|
+
const toolApprovals = hostField(client, 'toolApprovals');
|
|
439
|
+
const respond = verbOf(toolApprovals, 'respond');
|
|
440
|
+
const decideAsk = verbOf(toolApprovals, 'decideAsk');
|
|
441
|
+
const elicit = verbOf(hostField(client, 'elicitations'), 'respond');
|
|
442
|
+
if ((req.family === 'approval' && respond === undefined) || (req.family === 'ask' && decideAsk === undefined) || (req.family === 'elicitation' && elicit === undefined))
|
|
443
|
+
return notSent('no_verb');
|
|
444
|
+
if (req.family !== 'elicitation' && req.answer.kind !== 'allow' && req.answer.kind !== 'deny')
|
|
445
|
+
return notSent('not_an_answer');
|
|
446
|
+
if (isAborted(signal))
|
|
447
|
+
return notSent('aborted');
|
|
448
|
+
let ownHold;
|
|
449
|
+
let hold;
|
|
450
|
+
if (req.family !== 'elicitation' && req.approvalId !== undefined) {
|
|
451
|
+
const given = holdOf(hostField(deps, 'hold'));
|
|
452
|
+
if (given !== undefined && hostHoldIsActive(given) && holdFits(given, req)) {
|
|
453
|
+
hold = given;
|
|
454
|
+
}
|
|
455
|
+
else {
|
|
456
|
+
const attempt = tryHoldApprovalNow({ approvalId: req.approvalId, ...(req.taskId !== undefined ? { taskId: req.taskId } : {}), ...(req.toolCallId !== undefined ? { toolCallId: req.toolCallId } : {}) }, signal);
|
|
457
|
+
if (attempt.kind === 'settled')
|
|
458
|
+
return Object.freeze({ family, attempts: 0, kind: 'settled_elsewhere' });
|
|
459
|
+
if (attempt.kind === 'busy')
|
|
460
|
+
return notSent('duplicate_in_flight');
|
|
461
|
+
ownHold = attempt.hold;
|
|
462
|
+
hold = ownHold;
|
|
463
|
+
}
|
|
464
|
+
callHold(() => hold?.sending());
|
|
465
|
+
}
|
|
466
|
+
const ledgerFamily = ledgerFamilyOf(req.family);
|
|
467
|
+
if (latchKeysOf(req).some((k) => decisionOpsWithKey(ledgerFamily, k).some((o) => o.phase === 'posting' && o.settledAt === null))) {
|
|
468
|
+
ownHold?.release();
|
|
469
|
+
return notSent('duplicate_in_flight');
|
|
470
|
+
}
|
|
471
|
+
const requestKeys = req.family === 'elicitation'
|
|
472
|
+
? decisionLedgerKeysOf({ taskId: req.taskId, elicitationId: req.elicitationId })
|
|
473
|
+
: decisionLedgerKeysOf({ taskId: req.taskId, approvalId: req.approvalId, callId: req.toolCallId, askId: req.family === 'ask' ? req.askId : undefined });
|
|
474
|
+
const taken = hold !== undefined ? takeHostHoldLedgerOp(hold) : undefined;
|
|
475
|
+
let op;
|
|
476
|
+
if (taken !== undefined && taken.settledAt === null) {
|
|
477
|
+
op = taken;
|
|
478
|
+
op.phase = 'posting';
|
|
479
|
+
op.ownCallOpen = true;
|
|
480
|
+
addDecisionOpKeys(op, requestKeys);
|
|
481
|
+
}
|
|
482
|
+
else {
|
|
483
|
+
op = openDecisionOp(ledgerFamily, requestKeys, 'posting', true);
|
|
484
|
+
}
|
|
485
|
+
const decidedBy = hostField(deps, 'approvalDecidedBy');
|
|
486
|
+
const ctx = {
|
|
487
|
+
signal,
|
|
488
|
+
tally: newSendTally(),
|
|
489
|
+
noteCapable: hostField(deps, 'approvalDecisionNoteCapable') === true,
|
|
490
|
+
decidedBy: typeof decidedBy === 'object' && decidedBy !== null ? decidedBy : undefined,
|
|
491
|
+
};
|
|
492
|
+
let out;
|
|
493
|
+
try {
|
|
494
|
+
if (req.family === 'approval') {
|
|
495
|
+
out = await sendApprovalFamily(respond, req.approvalId, req.answer, ctx);
|
|
496
|
+
}
|
|
497
|
+
else if (req.family === 'ask') {
|
|
498
|
+
out = await sendAskFamily(respond, decideAsk, { taskId: req.taskId, askId: req.askId, approvalId: req.approvalId, answer: req.answer }, ctx);
|
|
499
|
+
}
|
|
500
|
+
else {
|
|
501
|
+
const { elicitationId, response } = req;
|
|
502
|
+
try {
|
|
503
|
+
await withTransportRetry((sig) => elicit(elicitationId, response, sig !== undefined ? { signal: sig } : undefined), signal, ctx.tally);
|
|
504
|
+
out = { family: 'elicitation', attempts: ctx.tally.attempts, kind: 'applied' };
|
|
505
|
+
}
|
|
506
|
+
catch (e) {
|
|
507
|
+
out = outcomeOfThrown(e, 'elicitation', undefined, signal, ctx.tally, false);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
const ambiguous = out.kind === 'unconfirmed' || (out.kind === 'not_applied' && (out.cause === 'parking' || out.cause === 'refused' || out.cause === 'idempotency_crossed'));
|
|
511
|
+
if (ambiguous && out.cause !== 'aborted') {
|
|
512
|
+
const gate = req.family === 'elicitation'
|
|
513
|
+
? { family: req.family, elicitationId: req.elicitationId, ...(req.taskId !== undefined ? { taskId: req.taskId } : {}) }
|
|
514
|
+
: {
|
|
515
|
+
family: req.family,
|
|
516
|
+
...(req.approvalId !== undefined ? { approvalId: req.approvalId } : {}),
|
|
517
|
+
...(req.family === 'ask' ? { askId: req.askId } : {}),
|
|
518
|
+
...(req.taskId !== undefined ? { taskId: req.taskId } : {}),
|
|
519
|
+
};
|
|
520
|
+
const pending = await readBack(deps, gate);
|
|
521
|
+
if (pending !== undefined) {
|
|
522
|
+
out = { ...out, pending };
|
|
523
|
+
if ((out.cause === 'refused' || out.cause === 'idempotency_crossed') && decisionRefusalClosesOut(out.refusal, pending))
|
|
524
|
+
out = { ...out, closesOut: true };
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
catch {
|
|
529
|
+
out = { family: req.family, attempts: ctx.tally.attempts, kind: 'unconfirmed', cause: 'local_error' };
|
|
530
|
+
}
|
|
531
|
+
const notApplied = out.kind !== 'applied' &&
|
|
532
|
+
(out.pending === 'pending' ||
|
|
533
|
+
(out.kind === 'not_applied' && (out.cause === 'lane_disabled' || out.cause === 'idempotency_crossed' || (out.cause === 'refused' && out.refusal?.standing === 'refused-pending'))));
|
|
534
|
+
if (notApplied)
|
|
535
|
+
op.notApplied = true;
|
|
536
|
+
closeDecisionOp(op, 'package');
|
|
537
|
+
if (ownHold !== undefined)
|
|
538
|
+
ownHold.release(out.kind === 'applied' || out.kind === 'settled_elsewhere' ? 'answered' : undefined);
|
|
539
|
+
return Object.freeze(out);
|
|
540
|
+
}
|
|
541
|
+
export function hitlDecisionOutcomeContent(outcome, lang) {
|
|
542
|
+
try {
|
|
543
|
+
if (typeof outcome !== 'object' || outcome === null)
|
|
544
|
+
return undefined;
|
|
545
|
+
const kind = readOwnDataValue(outcome, 'kind');
|
|
546
|
+
if (kind === 'settled_elsewhere') {
|
|
547
|
+
if (readOwnDataValue(outcome, 'contrary') !== true)
|
|
548
|
+
return undefined;
|
|
549
|
+
const first = readOwnDataValue(outcome, 'firstDecision');
|
|
550
|
+
if (first === 'deny')
|
|
551
|
+
return renderMessage(msg('approval.decision.settledElsewhereContrary.deniedFirst'), lang);
|
|
552
|
+
if (first === 'approve')
|
|
553
|
+
return renderMessage(msg('approval.decision.settledElsewhereContrary.approvedFirst'), lang);
|
|
554
|
+
return undefined;
|
|
555
|
+
}
|
|
556
|
+
if (kind === 'unconfirmed' && readOwnDataValue(outcome, 'cause') === 'gone_after_retry')
|
|
557
|
+
return renderMessage(msg('approval.decision.unconfirmedAfterRetry'), lang);
|
|
558
|
+
return undefined;
|
|
559
|
+
}
|
|
560
|
+
catch {
|
|
561
|
+
return undefined;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
@@ -70,6 +70,7 @@ export interface FrameRouterCtx {
|
|
|
70
70
|
signal?: AbortSignal | undefined;
|
|
71
71
|
}
|
|
72
72
|
export declare function isAskTool(toolName: string | undefined): boolean;
|
|
73
|
+
export declare function questionCardVerdict(carrier: object | null | undefined): boolean | undefined;
|
|
73
74
|
export declare function parkGateArmOf(gate: unknown): GateKind | null;
|
|
74
75
|
export declare function isHostProgressFrame(ev: AgentEvent): boolean;
|
|
75
76
|
interface HeldFlushInterruptEvidence {
|
package/dist/hitl/frameRouter.js
CHANGED
|
@@ -5,6 +5,8 @@ import { classifierDenyFromToolEnd } from '../classifierVerdictWire.js';
|
|
|
5
5
|
import { toolEndOutputText } from '../toolResultContent.js';
|
|
6
6
|
import { GATE_PARKED_ERROR_CODE } from '../engineErrorCodes.js';
|
|
7
7
|
import { readRunTerminal, runTerminalCode, runTerminalGateKind, runTerminalGateToolName } from '../runTerminal.js';
|
|
8
|
+
import { readApprovalCardWord } from './approvalCardReading.js';
|
|
9
|
+
import { guardedRead, readOwnDataValue } from '../ownKey.js';
|
|
8
10
|
import { parkHeldCallIdOf } from '../engineRowRef.js';
|
|
9
11
|
import { inheritFrameBinding } from '../frameBinding.js';
|
|
10
12
|
import { surfaceForCurrentSession, surfaceReplayedApprovalListUnreadable } from './hitlHostSurface.js';
|
|
@@ -102,6 +104,10 @@ function parkFamilyEvidence(led, gateToolName, gatedCallId) {
|
|
|
102
104
|
return false;
|
|
103
105
|
return gatedCallId === undefined || led.isFsOrShellGatedCall(gatedCallId);
|
|
104
106
|
}
|
|
107
|
+
export function questionCardVerdict(carrier) {
|
|
108
|
+
const word = readApprovalCardWord(carrier);
|
|
109
|
+
return word === undefined ? undefined : word === 'question';
|
|
110
|
+
}
|
|
105
111
|
export function parkGateArmOf(gate) {
|
|
106
112
|
if (gate === null || typeof gate !== 'object')
|
|
107
113
|
return null;
|
|
@@ -117,7 +123,7 @@ export function parkGateArmOf(gate) {
|
|
|
117
123
|
const leg = durableDecideLegOf(typeof kind === 'string' ? { gateKind: kind } : null);
|
|
118
124
|
if (leg !== 'approval' && leg !== 'absent')
|
|
119
125
|
return null;
|
|
120
|
-
if (isAskToolLoose(toolName))
|
|
126
|
+
if (questionCardVerdict(gate) ?? isAskToolLoose(toolName))
|
|
121
127
|
return 'ask';
|
|
122
128
|
if (leg === 'approval')
|
|
123
129
|
return 'fs';
|
|
@@ -147,7 +153,8 @@ function parkGateOf(result) {
|
|
|
147
153
|
if (typeof taskId !== 'string' || taskId.length === 0)
|
|
148
154
|
return null;
|
|
149
155
|
const toolName = runTerminalGateToolName(read);
|
|
150
|
-
const
|
|
156
|
+
const approvalCard = guardedRead(() => readOwnDataValue(read.gate, 'approvalCard'));
|
|
157
|
+
const arm = parkGateArmOf({ kind: runTerminalGateKind(read), toolName, approvalCard });
|
|
151
158
|
return arm === null ? null : { taskId, gate: arm, toolName };
|
|
152
159
|
}
|
|
153
160
|
function parkGatedCallId(src) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type { AgentEvent, ApprovalDecidedBy, ApprovalDecision, ApprovalStaleError, PendingCheckpoint, CheckpointGate, PlanReviewRequest, AssistantTaskStatus } from '@sema-agent/sdk';
|
|
1
|
+
import type { AgentEvent, ApprovalDecidedBy, ApprovalDecision, ApprovalStaleError, PendingCheckpoint, CheckpointGate, PlanReviewRequest, AssistantTaskStatus, QuestionAnswerItem } from '@sema-agent/sdk';
|
|
2
2
|
import type { PermissionResult } from '@sema-agent/agent-types';
|
|
3
|
+
import { type CapturedLocalCode, type CauseSlotRead } from '../engineWireFor.js';
|
|
3
4
|
import type { ApprovalsListEnvelope } from './crashConverged.js';
|
|
4
5
|
import { type SuspendedReopenReading } from './suspendedReopen.js';
|
|
5
6
|
export declare const DEFAULT_DENY_REASON = "The user rejected this tool use";
|
|
@@ -33,11 +34,7 @@ export interface HitlClientLike {
|
|
|
33
34
|
approvals: ApprovalsResourceLike;
|
|
34
35
|
assistant: AssistantResourceLike;
|
|
35
36
|
}
|
|
36
|
-
export
|
|
37
|
-
header: string;
|
|
38
|
-
selected: string[];
|
|
39
|
-
note?: string;
|
|
40
|
-
}
|
|
37
|
+
export type AskAnswer = QuestionAnswerItem;
|
|
41
38
|
export interface PlanReviewOutcome {
|
|
42
39
|
decision: 'approve' | 'edit' | 'reject';
|
|
43
40
|
editedPlan?: string;
|
|
@@ -63,6 +60,21 @@ export declare class HitlSafetyError extends Error {
|
|
|
63
60
|
readonly code: HitlSafetyCode;
|
|
64
61
|
constructor(message: string, code: HitlSafetyCode, options?: ErrorOptions);
|
|
65
62
|
}
|
|
63
|
+
export interface RefusalCarrier {
|
|
64
|
+
readonly local?: HitlSafetyCode;
|
|
65
|
+
readonly carrier: {} | null | undefined;
|
|
66
|
+
}
|
|
67
|
+
export declare function refusalCarrierOf(err: {} | null | undefined, localCodeRead?: {
|
|
68
|
+
readonly value: CapturedLocalCode;
|
|
69
|
+
}, answeredLayer?: boolean, causeRead?: CauseSlotRead, headRead?: SafetyStopHead): RefusalCarrier;
|
|
70
|
+
export declare function safetyStopNamed(err: {} | null | undefined): boolean;
|
|
71
|
+
export interface SafetyStopHead {
|
|
72
|
+
readonly named: boolean;
|
|
73
|
+
readonly local?: HitlSafetyCode;
|
|
74
|
+
}
|
|
75
|
+
export declare function safetyStopHeadOf(err: {} | null | undefined, localCodeRead?: {
|
|
76
|
+
readonly value: CapturedLocalCode;
|
|
77
|
+
}, namedRead?: boolean): SafetyStopHead;
|
|
66
78
|
export declare function hitlSafetyCodeOf(e: unknown): HitlSafetyCode | undefined;
|
|
67
79
|
export type GateCurrentPending = Readonly<NonNullable<ApprovalStaleError['currentPending']>>;
|
|
68
80
|
export declare function readDecideCurrentPending(e: unknown): GateCurrentPending | undefined;
|