@sema-agent/client-core 0.94.0 → 0.96.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +521 -0
- package/README.md +104 -57
- package/dist/adapt/arms.js +12 -7
- package/dist/adapt/panelTasks.js +4 -10
- package/dist/adapt/toolCards.d.ts +1 -0
- package/dist/adapt/toolCards.js +18 -5
- package/dist/adapt/wireShapes.js +5 -24
- package/dist/adapter/activeRunSelfHeal.d.ts +12 -3
- package/dist/adapter/activeRunSelfHeal.js +50 -16
- package/dist/adapter/downstream/eventToSdkMessage.js +33 -18
- package/dist/adapter/downstream/terminalToSdkResult.js +19 -12
- package/dist/adapter/runStream.js +30 -46
- package/dist/adapter/types.d.ts +7 -0
- package/dist/adapter/types.js +15 -0
- package/dist/agentSession/backgroundView.js +5 -1
- package/dist/agentSession/engineAgentRegistryRead.js +7 -5
- package/dist/agentSession/engineSessionBackgroundStop.js +25 -17
- package/dist/agentsWireCaps.d.ts +2 -0
- package/dist/agentsWireCaps.js +13 -2
- package/dist/approvalDecidedByCapability.d.ts +0 -1
- package/dist/approvalDecidedByCapability.js +2 -7
- package/dist/approvalsStreamLiveCapability.d.ts +0 -1
- package/dist/approvalsStreamLiveCapability.js +2 -6
- package/dist/atMostOnce.d.ts +8 -0
- package/dist/atMostOnce.js +36 -0
- package/dist/attachmentSeatCapability.d.ts +0 -1
- package/dist/attachmentSeatCapability.js +0 -3
- package/dist/attachmentsWireCaps.js +11 -6
- package/dist/bashExitReading.d.ts +10 -0
- package/dist/bashExitReading.js +12 -0
- package/dist/callerCwdCapability.d.ts +0 -5
- package/dist/callerCwdCapability.js +2 -13
- package/dist/centerWiringCapability.d.ts +1 -7
- package/dist/centerWiringCapability.js +18 -27
- package/dist/classifierStatus.js +4 -4
- package/dist/classifierVerdictWire.js +4 -16
- package/dist/clientSlice.js +1 -1
- package/dist/cloudConfigWireCaps.d.ts +3 -3
- package/dist/cloudConfigWireCaps.js +85 -43
- package/dist/compensations.js +1 -1
- package/dist/coreValuePorts.d.ts +11 -7
- package/dist/coreValuePorts.js +5 -8
- package/dist/credentialProvenance.d.ts +28 -0
- package/dist/credentialProvenance.js +76 -0
- package/dist/cycleOrder.d.ts +15 -0
- package/dist/cycleOrder.js +45 -0
- package/dist/decideFailureNote.js +7 -2
- package/dist/decideReceipt.d.ts +2 -1
- package/dist/decideReceipt.js +39 -14
- package/dist/declared/supportFloorDeclared.d.ts +1 -0
- package/dist/declared/supportFloorDeclared.js +5 -0
- package/dist/deviceExecutorManagementCapability.d.ts +0 -1
- package/dist/deviceExecutorManagementCapability.js +7 -16
- package/dist/deviceRebind.d.ts +88 -0
- package/dist/deviceRebind.js +242 -0
- package/dist/displayUntrusted.d.ts +8 -3
- package/dist/displayUntrusted.js +661 -63
- package/dist/engineAgentAbsence.d.ts +2 -2
- package/dist/engineAgentPanelStore.d.ts +8 -18
- package/dist/engineAgentPanelStore.js +19 -537
- package/dist/engineCapReader.d.ts +6 -6
- package/dist/engineCapReader.js +30 -43
- package/dist/engineCapsCache.d.ts +13 -2
- package/dist/engineCapsCache.js +276 -44
- package/dist/engineCredentialRequirement.d.ts +9 -0
- package/dist/engineCredentialRequirement.js +23 -0
- package/dist/engineDirectory.d.ts +79 -0
- package/dist/engineDirectory.js +186 -0
- package/dist/engineEnvSourcing.d.ts +53 -0
- package/dist/engineEnvSourcing.js +81 -0
- package/dist/engineErrorCodes.d.ts +28 -4
- package/dist/engineErrorCodes.js +68 -25
- package/dist/engineIdentity.js +2 -0
- package/dist/engineNoticeCodes.d.ts +17 -0
- package/dist/engineNoticeCodes.js +57 -3
- package/dist/engineWireSdk.js +2 -2
- package/dist/engineWordRenames.d.ts +8 -0
- package/dist/engineWordRenames.js +13 -0
- package/dist/executionLaneCapability.d.ts +2 -3
- package/dist/executionLaneCapability.js +18 -23
- package/dist/fileHistoryCaptureCapability.d.ts +14 -1
- package/dist/fileHistoryCaptureCapability.js +72 -6
- package/dist/fileHistoryLegNotice.d.ts +3 -2
- package/dist/fileHistoryLegNotice.js +51 -2
- package/dist/fleet/bgSubagentRow.d.ts +15 -0
- package/dist/fleet/bgSubagentRow.js +67 -0
- package/dist/fleet/fleetLedger.d.ts +3 -0
- package/dist/fleet/fleetLedger.js +153 -122
- package/dist/fleet/fleetProjection.d.ts +1 -3
- package/dist/fleet/fleetProjection.js +19 -19
- package/dist/fleetAgentPanelProjection.d.ts +4 -17
- package/dist/fleetAgentPanelProjection.js +7 -197
- package/dist/fleetAgentRowLike.d.ts +16 -0
- package/dist/fleetAgentRowLike.js +1 -0
- package/dist/fleetTaskDesc.js +4 -17
- package/dist/gateOutcome.d.ts +12 -1
- package/dist/gateOutcome.js +87 -18
- package/dist/gateVocabulary.d.ts +7 -2
- package/dist/gateVocabulary.js +5 -1
- package/dist/generated/engineAskFaceTables.js +1 -1
- package/dist/generated/engineFactTables.d.ts +5 -3
- package/dist/generated/engineFactTables.js +17 -4
- package/dist/generated/engineNoticeTables.js +12 -3
- package/dist/generated/sdkFactTables.d.ts +2 -0
- package/dist/generated/sdkFactTables.js +17 -0
- package/dist/generated/settingsSchemaFns.d.ts +13 -0
- package/dist/generated/settingsSchemaFns.js +75 -0
- package/dist/generated/toolNameTables.d.ts +1 -0
- package/dist/generated/toolNameTables.js +1 -0
- package/dist/headlessPermissionModeWire.d.ts +1 -1
- package/dist/headlessPermissionModeWire.js +1 -1
- package/dist/headlessReconnectWire.js +49 -20
- package/dist/hitl/allowRuleShadow.d.ts +1 -1
- package/dist/hitl/allowRuleShadow.js +49 -8
- package/dist/hitl/approvalCompleteParked.d.ts +1 -0
- package/dist/hitl/approvalCompleteParked.js +14 -0
- package/dist/hitl/approvalEndingCause.d.ts +7 -0
- package/dist/hitl/approvalEndingCause.js +71 -0
- package/dist/hitl/approvalHolds.d.ts +12 -2
- package/dist/hitl/approvalHolds.js +53 -2
- package/dist/hitl/approvalsFeed.js +23 -11
- package/dist/hitl/askGateWire.d.ts +2 -1
- package/dist/hitl/askGateWire.js +26 -1
- package/dist/hitl/askParkRowRouting.js +1 -1
- package/dist/hitl/automaticAnswerVerdict.d.ts +1 -1
- package/dist/hitl/automaticAnswerVerdict.js +15 -10
- package/dist/hitl/crashConverged.js +2 -0
- package/dist/hitl/decisionConflict.d.ts +3 -0
- package/dist/hitl/decisionConflict.js +41 -0
- package/dist/hitl/decisionRefusal.d.ts +12 -0
- package/dist/hitl/decisionRefusal.js +63 -4
- package/dist/hitl/frameRouter.d.ts +0 -1
- package/dist/hitl/frameRouter.js +32 -57
- package/dist/hitl/gateLedger.d.ts +5 -0
- package/dist/hitl/gateLedger.js +21 -0
- package/dist/hitl/hitlBridge.d.ts +17 -2
- package/dist/hitl/hitlBridge.js +91 -55
- package/dist/hitl/hitlHostSurface.js +3 -11
- package/dist/hitl/livePendingAsk.d.ts +16 -6
- package/dist/hitl/livePendingAsk.js +36 -4
- package/dist/hitl/localAllowRule.d.ts +1 -0
- package/dist/hitl/localAllowRule.js +2 -2
- package/dist/hitl/noAllowCause.d.ts +2 -1
- package/dist/hitl/noAllowCause.js +3 -2
- package/dist/hitl/parkExpiryJudgements.d.ts +19 -0
- package/dist/hitl/parkExpiryJudgements.js +46 -0
- package/dist/hitl/parkResolver.d.ts +4 -7
- package/dist/hitl/parkResolver.js +12 -34
- package/dist/hitl/parkRowBirthWait.d.ts +1 -0
- package/dist/hitl/parkRowBirthWait.js +2 -2
- package/dist/hitl/persistedRulesWire.js +5 -1
- package/dist/hitl/planReviewWire.d.ts +3 -2
- package/dist/hitl/planReviewWire.js +154 -50
- package/dist/hitl/replayedApproval.d.ts +9 -0
- package/dist/hitl/replayedApproval.js +139 -10
- package/dist/hitl/resumeRunningCard.d.ts +2 -0
- package/dist/hitl/resumeRunningCard.js +15 -4
- package/dist/hitl/sessionPolicyDeliverable.js +8 -6
- package/dist/hitl/standingRows.d.ts +18 -0
- package/dist/hitl/standingRows.js +127 -0
- package/dist/hitl/toolApprovalWire.d.ts +39 -7
- package/dist/hitl/toolApprovalWire.js +351 -61
- package/dist/hookMatcherVerdict.d.ts +1 -9
- package/dist/hookMatcherVerdict.js +21 -61
- package/dist/hooksWireCaps.js +40 -8
- package/dist/host.d.ts +5 -0
- package/dist/host.js +3 -1
- package/dist/hostCallbackGuard.d.ts +2 -0
- package/dist/hostCallbackGuard.js +31 -0
- package/dist/index.d.ts +48 -17
- package/dist/index.js +36 -15
- package/dist/interactiveInterrupt.d.ts +8 -0
- package/dist/interactiveInterrupt.js +54 -0
- package/dist/limitsWire.d.ts +5 -0
- package/dist/limitsWire.js +49 -3
- package/dist/liveModelCatalog.d.ts +95 -0
- package/dist/liveModelCatalog.js +297 -32
- package/dist/mcpEngineLeg.d.ts +25 -0
- package/dist/mcpEngineLeg.js +71 -15
- package/dist/mcpPanel.js +2 -1
- package/dist/mcpProbeCapability.d.ts +0 -5
- package/dist/mcpProbeCapability.js +2 -12
- package/dist/mcpReconnect.d.ts +1 -3
- package/dist/mcpReconnect.js +10 -5
- package/dist/memoryComplianceCapability.d.ts +0 -5
- package/dist/memoryComplianceCapability.js +2 -12
- package/dist/memoryOriginCapability.d.ts +0 -5
- package/dist/memoryOriginCapability.js +2 -12
- package/dist/memorySpecWire.js +2 -2
- package/dist/memoryVerbsWire.d.ts +1 -1
- package/dist/memoryVerbsWire.js +4 -0
- package/dist/model/liveCatalogShape.d.ts +14 -0
- package/dist/model/liveCatalogShape.js +71 -0
- package/dist/model/modelSupplyRules.d.ts +1 -0
- package/dist/model/modelSupplyRules.js +30 -9
- package/dist/model/modelsPolicy.d.ts +21 -0
- package/dist/model/modelsPolicy.js +90 -0
- package/dist/modelIdentityResolvability.d.ts +2 -2
- package/dist/modelIdentityResolvability.js +14 -12
- package/dist/modelSwitchFallback.d.ts +69 -0
- package/dist/modelSwitchFallback.js +206 -0
- package/dist/noticePresentation.d.ts +68 -0
- package/dist/noticePresentation.js +247 -0
- package/dist/notifications.js +12 -11
- package/dist/outputStyleSeatCapability.d.ts +0 -2
- package/dist/outputStyleSeatCapability.js +2 -10
- package/dist/ownKey.d.ts +8 -0
- package/dist/ownKey.js +66 -0
- package/dist/panelReduce.d.ts +114 -0
- package/dist/panelReduce.js +1135 -0
- package/dist/panelStateHolder.d.ts +17 -0
- package/dist/panelStateHolder.js +201 -0
- package/dist/peerFrames.js +13 -9
- package/dist/peerLaneCapability.d.ts +0 -1
- package/dist/peerLaneCapability.js +2 -6
- package/dist/permissionModesCapability.d.ts +0 -5
- package/dist/permissionModesCapability.js +5 -16
- package/dist/permissionRuleIssue.js +0 -3
- package/dist/permissionRulesWriteCapability.d.ts +0 -1
- package/dist/permissionRulesWriteCapability.js +2 -6
- package/dist/permissionsAllowGrantCapability.d.ts +0 -1
- package/dist/permissionsAllowGrantCapability.js +3 -9
- package/dist/permissionsDeclaration.d.ts +8 -0
- package/dist/permissionsDeclaration.js +101 -41
- package/dist/printPermissionOutcome.d.ts +12 -0
- package/dist/printPermissionOutcome.js +50 -0
- package/dist/printToolResultFrame.d.ts +1 -0
- package/dist/printToolResultFrame.js +5 -17
- package/dist/promptBlockedCopy.d.ts +5 -0
- package/dist/promptBlockedCopy.js +35 -0
- package/dist/promptDelivery.js +0 -8
- package/dist/protocolSegment.d.ts +9 -6
- package/dist/protocolSegment.js +31 -21
- package/dist/providerRejection.d.ts +4 -0
- package/dist/providerRejection.js +75 -14
- package/dist/replayBody.d.ts +12 -0
- package/dist/replayBody.js +25 -0
- package/dist/resumeRefusalCopy.d.ts +18 -1
- package/dist/resumeRefusalCopy.js +127 -32
- package/dist/retryStatus.d.ts +9 -1
- package/dist/retryStatus.js +9 -2
- package/dist/rewindArchiveCapability.d.ts +5 -14
- package/dist/rewindArchiveCapability.js +18 -61
- package/dist/rewindArchiveReading.d.ts +15 -0
- package/dist/rewindArchiveReading.js +56 -0
- package/dist/rewindEngineAction.d.ts +21 -0
- package/dist/rewindEngineAction.js +36 -0
- package/dist/rewindWireCaps.d.ts +2 -1
- package/dist/rewindWireCaps.js +1 -0
- package/dist/ruleCompileVerdict.d.ts +9 -1
- package/dist/ruleCompileVerdict.js +29 -4
- package/dist/runTerminal.d.ts +15 -12
- package/dist/runTerminal.js +60 -35
- package/dist/sandboxWire.js +13 -0
- package/dist/sdkRegistryTransit.d.ts +2 -1
- package/dist/sdkRegistryTransit.js +1 -0
- package/dist/sealedKeyCapability.d.ts +0 -5
- package/dist/sealedKeyCapability.js +3 -15
- package/dist/seam.js +4 -2
- package/dist/seatContract.d.ts +125 -34
- package/dist/seatContract.js +583 -179
- package/dist/sessionIdSegment.d.ts +1 -0
- package/dist/sessionIdSegment.js +11 -0
- package/dist/sessionMemoryErase.d.ts +1 -1
- package/dist/sessionMemoryErase.js +6 -1
- package/dist/sessionMemoryStatus.js +3 -2
- package/dist/sessionPolicyCapability.d.ts +0 -1
- package/dist/sessionPolicyCapability.js +2 -6
- package/dist/sessionReadRedactionCapability.d.ts +0 -5
- package/dist/sessionReadRedactionCapability.js +2 -13
- package/dist/sessionSyncFileHistory.d.ts +4 -0
- package/dist/sessionSyncFileHistory.js +66 -0
- package/dist/sessionSyncFileHistoryCapability.d.ts +0 -2
- package/dist/sessionSyncFileHistoryCapability.js +2 -9
- package/dist/skillToolListsCapability.d.ts +0 -2
- package/dist/skillToolListsCapability.js +2 -9
- package/dist/skillsWireCaps.d.ts +4 -0
- package/dist/skillsWireCaps.js +66 -1
- package/dist/sqlEngineCapability.d.ts +0 -1
- package/dist/sqlEngineCapability.js +9 -14
- package/dist/steerPriorityCapability.d.ts +0 -2
- package/dist/steerPriorityCapability.js +3 -12
- package/dist/storePostureCapability.d.ts +1 -5
- package/dist/storePostureCapability.js +16 -22
- package/dist/streamDrainingLegs.d.ts +6 -0
- package/dist/streamDrainingLegs.js +23 -0
- package/dist/subagent/engineCompactWire.js +13 -38
- package/dist/subagent/engineDelegatedPrompt.js +10 -6
- package/dist/subagent/engineSubagentOutput.d.ts +0 -1
- package/dist/subagent/engineSubagentOutput.js +5 -20
- package/dist/subagent/engineSubagentSteer.js +7 -5
- package/dist/subagent/engineSubagentTail.d.ts +0 -1
- package/dist/subagent/engineSubagentTail.js +7 -32
- package/dist/subagentContentStore.js +7 -18
- package/dist/supportFloor.d.ts +1 -0
- package/dist/supportFloor.js +15 -14
- package/dist/systemReminderTag.d.ts +1 -0
- package/dist/systemReminderTag.js +8 -0
- package/dist/terminalStatuses.d.ts +30 -0
- package/dist/terminalStatuses.js +67 -0
- package/dist/toolHistoryMismatch.d.ts +0 -3
- package/dist/toolHistoryMismatch.js +3 -7
- package/dist/toolResult.d.ts +6 -1
- package/dist/toolResult.js +90 -37
- package/dist/toolResultContent.d.ts +2 -0
- package/dist/toolResultContent.js +63 -0
- package/dist/types/engineState.d.ts +2 -1
- package/dist/usageAnalytics.d.ts +146 -0
- package/dist/usageAnalytics.js +335 -0
- package/dist/userInvokedSkillsCapability.d.ts +0 -2
- package/dist/userInvokedSkillsCapability.js +2 -9
- package/dist/webSearchBackendCapability.d.ts +0 -1
- package/dist/webSearchBackendCapability.js +3 -7
- package/dist/webSearchWireCaps.js +3 -11
- package/dist/wireErrorTriage.d.ts +2 -0
- package/dist/wireErrorTriage.js +34 -5
- package/dist/wireFailureShape.d.ts +23 -2
- package/dist/wireFailureShape.js +88 -43
- package/dist/wireRefusalCopy.js +2 -18
- package/dist/workflowClient.js +7 -11
- package/dist/workflowsJournalCapability.d.ts +0 -1
- package/dist/workflowsJournalCapability.js +2 -6
- package/dist/writeProtectionCapability.d.ts +0 -1
- package/dist/writeProtectionCapability.js +5 -10
- package/docs/INTEGRATION-CLIENTS.md +2279 -27
- package/package.json +5 -5
- package/dist/engineCapsGenerationGuard.d.ts +0 -4
- package/dist/engineCapsGenerationGuard.js +0 -19
- package/dist/panelRunningHistory.d.ts +0 -22
- package/dist/panelRunningHistory.js +0 -82
- package/dist/registryConflict.d.ts +0 -3
- package/dist/registryConflict.js +0 -44
package/dist/hitl/gateLedger.js
CHANGED
|
@@ -13,6 +13,8 @@ export function hasLedgerPositionKey(ev) {
|
|
|
13
13
|
return (id !== undefined && id !== null) || (seq !== undefined && seq !== null);
|
|
14
14
|
}
|
|
15
15
|
export const PREAMBLE_APPROVALS_MAX_ENTRIES = 4096;
|
|
16
|
+
export const APPROVAL_SETTLED_HOWS = Object.freeze(['answered', 'interrupted', 'closed_by_engine']);
|
|
17
|
+
export const SETTLED_APPROVALS_MAX_ENTRIES = 4096;
|
|
16
18
|
export const START_ARGS_MAX_ENTRIES = 256;
|
|
17
19
|
function normalizeDenyAttribution(a) {
|
|
18
20
|
if (a === undefined)
|
|
@@ -88,6 +90,7 @@ export function createGateLedger() {
|
|
|
88
90
|
let denyStampAttribution;
|
|
89
91
|
let seq;
|
|
90
92
|
const preambleApprovalIds = new Set();
|
|
93
|
+
const settledApprovalHows = new Map();
|
|
91
94
|
const liveCards = new Set();
|
|
92
95
|
return {
|
|
93
96
|
noteSeq(ev) {
|
|
@@ -121,6 +124,24 @@ export function createGateLedger() {
|
|
|
121
124
|
beginStreamSegment() {
|
|
122
125
|
preambleApprovalIds.clear();
|
|
123
126
|
},
|
|
127
|
+
noteApprovalSettled(approvalId, how) {
|
|
128
|
+
if (typeof approvalId !== 'string' || approvalId === '')
|
|
129
|
+
return;
|
|
130
|
+
if (!APPROVAL_SETTLED_HOWS.includes(how))
|
|
131
|
+
return;
|
|
132
|
+
if (settledApprovalHows.has(approvalId))
|
|
133
|
+
return;
|
|
134
|
+
settledApprovalHows.set(approvalId, how);
|
|
135
|
+
while (settledApprovalHows.size > SETTLED_APPROVALS_MAX_ENTRIES) {
|
|
136
|
+
const oldest = settledApprovalHows.keys().next();
|
|
137
|
+
if (oldest.done === true)
|
|
138
|
+
break;
|
|
139
|
+
settledApprovalHows.delete(oldest.value);
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
settledApprovals() {
|
|
143
|
+
return settledApprovalHows;
|
|
144
|
+
},
|
|
124
145
|
trackLiveCard(phaseOf, handled) {
|
|
125
146
|
const entry = { phaseOf, handled };
|
|
126
147
|
liveCards.add(entry);
|
|
@@ -46,7 +46,8 @@ export interface PlanReviewOutcome {
|
|
|
46
46
|
export declare const PLAN_REVIEW_MODE_AFTER_WORDS: readonly ["default", "acceptEdits"];
|
|
47
47
|
export type PlanReviewModeAfter = (typeof PLAN_REVIEW_MODE_AFTER_WORDS)[number];
|
|
48
48
|
export declare function isPlanReviewModeAfter(v: string | undefined): v is PlanReviewModeAfter;
|
|
49
|
-
export
|
|
49
|
+
export declare const GATE_FAILURE_CODES: readonly ["no_pending", "binding_mismatch", "wrong_gate", "bad_plan_edit", "bad_plan_mode", "empty_answer", "binding_missing"];
|
|
50
|
+
export type HitlSafetyCode = (typeof GATE_FAILURE_CODES)[number];
|
|
50
51
|
export type HitlFailureStage = 'fetch' | 'input' | 'card' | 'decide' | 'orchestration';
|
|
51
52
|
export declare const NO_APPROVAL_CARD_PORT_REASON = "no approval card port installed (print/non-REPL mode, or host forgot installApprovalCardPort)";
|
|
52
53
|
export declare const APPROVAL_CARD_PORT_KEY_MISMATCH_REASON = "no approval card port installed for the default session key, but a non-default sessionKey has one \u2014 likely a keyed-install/default-read mismatch (installApprovalCardPortFor vs the zero-arg default-key read), not a missing install";
|
|
@@ -62,9 +63,23 @@ export declare class HitlSafetyError extends Error {
|
|
|
62
63
|
readonly code: HitlSafetyCode;
|
|
63
64
|
constructor(message: string, code: HitlSafetyCode);
|
|
64
65
|
}
|
|
66
|
+
export declare function hitlSafetyCodeOf(e: unknown): HitlSafetyCode | undefined;
|
|
65
67
|
export type GateCurrentPending = Readonly<NonNullable<ApprovalStaleError['currentPending']>>;
|
|
66
68
|
export declare function readDecideCurrentPending(e: unknown): GateCurrentPending | undefined;
|
|
67
69
|
export declare function readWireErrorCode(e: unknown): string | undefined;
|
|
70
|
+
export type WireErrorCodeReading = {
|
|
71
|
+
readonly state: 'code';
|
|
72
|
+
readonly code: string;
|
|
73
|
+
} | {
|
|
74
|
+
readonly state: 'absent';
|
|
75
|
+
} | {
|
|
76
|
+
readonly state: 'unreadable';
|
|
77
|
+
};
|
|
78
|
+
export declare function readWireErrorCodeReading(e: unknown): WireErrorCodeReading;
|
|
79
|
+
export declare function readWireCodes(e: unknown): {
|
|
80
|
+
readonly errorCode?: string;
|
|
81
|
+
readonly blockedBy?: string;
|
|
82
|
+
};
|
|
68
83
|
export declare function __setDecideTimeoutRetryBudgetForTests(ms?: number): void;
|
|
69
84
|
export declare class DecideTransportRetryExhaustedError extends Error {
|
|
70
85
|
readonly attempts: number;
|
|
@@ -105,7 +120,7 @@ export type FindPendingOutcome = {
|
|
|
105
120
|
} | {
|
|
106
121
|
ok: false;
|
|
107
122
|
reason: string;
|
|
108
|
-
code?: 'no_pending';
|
|
123
|
+
code?: 'no_pending' | 'wrong_gate';
|
|
109
124
|
};
|
|
110
125
|
export declare function findPendingForTask(client: HitlClientLike, taskId: string, matches: (toolName: string | undefined) => boolean, opts?: {
|
|
111
126
|
signal?: AbortSignal;
|
package/dist/hitl/hitlBridge.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { askParkForeignGateKind } from '../adapter/activeRunSelfHeal.js';
|
|
2
2
|
import { eventSeq } from '../adapter/types.js';
|
|
3
3
|
import { hostLog } from '../host.js';
|
|
4
|
+
import { invokeHostCallbackIsolated } from '../hostCallbackGuard.js';
|
|
4
5
|
import { abortableSleep } from '../abortableSleep.js';
|
|
5
6
|
import { readOwnDataValue } from '../ownKey.js';
|
|
6
|
-
import { wireFailureTextsOf } from '../wireFailureShape.js';
|
|
7
|
+
import { THROWN_SLOT_UNREADABLE, readBlockedBy, readThrownSlot, thrownIsInstanceOf, wireFailureTextsOf } from '../wireFailureShape.js';
|
|
8
|
+
import { RESUME_POLICY_FOLD_CODE } from '../engineErrorCodes.js';
|
|
7
9
|
import { suspendedReopenOf } from './suspendedReopen.js';
|
|
8
10
|
export const DEFAULT_DENY_REASON = 'The user rejected this tool use';
|
|
9
11
|
const MAX_DENY_REASON_CHARS = 4096;
|
|
@@ -27,6 +29,15 @@ export const PLAN_REVIEW_MODE_AFTER_WORDS = Object.freeze(['default', 'acceptEdi
|
|
|
27
29
|
export function isPlanReviewModeAfter(v) {
|
|
28
30
|
return v !== undefined && PLAN_REVIEW_MODE_AFTER_WORDS.includes(v);
|
|
29
31
|
}
|
|
32
|
+
export const GATE_FAILURE_CODES = Object.freeze([
|
|
33
|
+
'no_pending',
|
|
34
|
+
'binding_mismatch',
|
|
35
|
+
'wrong_gate',
|
|
36
|
+
'bad_plan_edit',
|
|
37
|
+
'bad_plan_mode',
|
|
38
|
+
'empty_answer',
|
|
39
|
+
'binding_missing',
|
|
40
|
+
]);
|
|
30
41
|
export const NO_APPROVAL_CARD_PORT_REASON = 'no approval card port installed (print/non-REPL mode, or host forgot installApprovalCardPort)';
|
|
31
42
|
export const APPROVAL_CARD_PORT_KEY_MISMATCH_REASON = 'no approval card port installed for the default session key, but a non-default sessionKey has one — likely a keyed-install/default-read mismatch (installApprovalCardPortFor vs the zero-arg default-key read), not a missing install';
|
|
32
43
|
export const NO_QUESTION_OVERLAY_REASON = 'no question overlay mounted (print/non-REPL mode)';
|
|
@@ -41,28 +52,55 @@ export class HitlSafetyError extends Error {
|
|
|
41
52
|
this.name = 'HitlSafetyError';
|
|
42
53
|
}
|
|
43
54
|
}
|
|
55
|
+
export function hitlSafetyCodeOf(e) {
|
|
56
|
+
if (!thrownIsInstanceOf(e, HitlSafetyError))
|
|
57
|
+
return undefined;
|
|
58
|
+
const raw = readThrownSlot(e, 'code');
|
|
59
|
+
return typeof raw === 'string' && GATE_FAILURE_CODES.includes(raw) ? raw : undefined;
|
|
60
|
+
}
|
|
44
61
|
const _gateCurrentPendingReadonlyPin = true;
|
|
45
62
|
void _gateCurrentPendingReadonlyPin;
|
|
46
63
|
export function readDecideCurrentPending(e) {
|
|
47
|
-
|
|
64
|
+
if (e === null || e === undefined)
|
|
65
|
+
return undefined;
|
|
66
|
+
const raw = readThrownSlot(e, 'currentPending');
|
|
48
67
|
if (typeof raw !== 'object' || raw === null)
|
|
49
68
|
return undefined;
|
|
50
|
-
const
|
|
51
|
-
|
|
69
|
+
const toolName = readThrownSlot(raw, 'toolName');
|
|
70
|
+
const boundCallId = readThrownSlot(raw, 'boundCallId');
|
|
71
|
+
const boundInputHash = readThrownSlot(raw, 'boundInputHash');
|
|
72
|
+
if (typeof toolName !== 'string' || toolName.length === 0)
|
|
52
73
|
return undefined;
|
|
53
|
-
if (typeof
|
|
74
|
+
if (typeof boundCallId !== 'string' || boundCallId.length === 0)
|
|
54
75
|
return undefined;
|
|
55
76
|
return {
|
|
56
|
-
toolName
|
|
57
|
-
boundCallId
|
|
58
|
-
...(typeof
|
|
59
|
-
? { boundInputHash
|
|
77
|
+
toolName,
|
|
78
|
+
boundCallId,
|
|
79
|
+
...(typeof boundInputHash === 'string' && boundInputHash.length > 0
|
|
80
|
+
? { boundInputHash }
|
|
60
81
|
: {}),
|
|
61
82
|
};
|
|
62
83
|
}
|
|
63
84
|
export function readWireErrorCode(e) {
|
|
64
|
-
const
|
|
65
|
-
return
|
|
85
|
+
const reading = readWireErrorCodeReading(e);
|
|
86
|
+
return reading.state === 'code' ? reading.code : undefined;
|
|
87
|
+
}
|
|
88
|
+
export function readWireErrorCodeReading(e) {
|
|
89
|
+
if (e === null || e === undefined)
|
|
90
|
+
return { state: 'absent' };
|
|
91
|
+
const raw = readThrownSlot(e, 'errorCode');
|
|
92
|
+
if (raw === THROWN_SLOT_UNREADABLE)
|
|
93
|
+
return { state: 'unreadable' };
|
|
94
|
+
return typeof raw === 'string' && raw.length > 0 ? { state: 'code', code: raw } : { state: 'absent' };
|
|
95
|
+
}
|
|
96
|
+
export function readWireCodes(e) {
|
|
97
|
+
const reading = readWireErrorCodeReading(e);
|
|
98
|
+
if (reading.state !== 'code')
|
|
99
|
+
return {};
|
|
100
|
+
if (reading.code !== RESUME_POLICY_FOLD_CODE)
|
|
101
|
+
return { errorCode: reading.code };
|
|
102
|
+
const folded = readBlockedBy(e);
|
|
103
|
+
return folded.kind === 'named' ? { errorCode: reading.code, blockedBy: folded.code } : { errorCode: reading.code };
|
|
66
104
|
}
|
|
67
105
|
const DECIDE_TRANSPORT_RETRY_BACKOFF_MS = 750;
|
|
68
106
|
const DECIDE_RETRY_BACKOFF_MAX_MS = 5_000;
|
|
@@ -80,10 +118,9 @@ function decideTimeoutRetryBudgetMs() {
|
|
|
80
118
|
function isDecideAttemptTimeout(e, depth = 0) {
|
|
81
119
|
if (depth > 3 || e === null || typeof e !== 'object')
|
|
82
120
|
return false;
|
|
83
|
-
|
|
84
|
-
if (o.name === 'TimeoutError')
|
|
121
|
+
if (readThrownSlot(e, 'name') === 'TimeoutError')
|
|
85
122
|
return true;
|
|
86
|
-
return isDecideAttemptTimeout(
|
|
123
|
+
return isDecideAttemptTimeout(readThrownSlot(e, 'cause'), depth + 1);
|
|
87
124
|
}
|
|
88
125
|
const TRANSIENT_NETWORK_CODES = new Set([
|
|
89
126
|
'ECONNREFUSED', 'ECONNRESET', 'ETIMEDOUT', 'EPIPE', 'EAI_AGAIN',
|
|
@@ -93,18 +130,21 @@ const TRANSIENT_NETWORK_CODES = new Set([
|
|
|
93
130
|
function isTransientDecideTransportFailure(e, depth = 0) {
|
|
94
131
|
if (depth > 3 || e === null || typeof e !== 'object')
|
|
95
132
|
return false;
|
|
96
|
-
if (e
|
|
133
|
+
if (thrownIsInstanceOf(e, HitlSafetyError))
|
|
97
134
|
return false;
|
|
98
|
-
const
|
|
99
|
-
if (typeof
|
|
135
|
+
const status = readThrownSlot(e, 'status');
|
|
136
|
+
if (status === THROWN_SLOT_UNREADABLE || typeof status === 'number')
|
|
100
137
|
return false;
|
|
101
|
-
|
|
138
|
+
const name = readThrownSlot(e, 'name');
|
|
139
|
+
if (name === 'TimeoutError' || name === 'AbortError')
|
|
102
140
|
return true;
|
|
103
|
-
|
|
141
|
+
const code = readThrownSlot(e, 'code');
|
|
142
|
+
if (typeof code === 'string' && TRANSIENT_NETWORK_CODES.has(code))
|
|
104
143
|
return true;
|
|
105
|
-
|
|
144
|
+
const message = readThrownSlot(e, 'message');
|
|
145
|
+
if (typeof message === 'string' && message.toLowerCase().includes('fetch failed'))
|
|
106
146
|
return true;
|
|
107
|
-
return isTransientDecideTransportFailure(
|
|
147
|
+
return isTransientDecideTransportFailure(readThrownSlot(e, 'cause'), depth + 1);
|
|
108
148
|
}
|
|
109
149
|
export class DecideTransportRetryExhaustedError extends Error {
|
|
110
150
|
attempts;
|
|
@@ -149,7 +189,7 @@ class DecideSpan {
|
|
|
149
189
|
}
|
|
150
190
|
catch (e) {
|
|
151
191
|
this.ok = false;
|
|
152
|
-
this.retryExhausted = e
|
|
192
|
+
this.retryExhausted = thrownIsInstanceOf(e, DecideTransportRetryExhaustedError);
|
|
153
193
|
throw e;
|
|
154
194
|
}
|
|
155
195
|
finally {
|
|
@@ -175,32 +215,13 @@ class DecideSpan {
|
|
|
175
215
|
notifyDecideObserver(this.observer, Object.freeze({ ...this.identity, phase: 'end', ok: this.ok, attempts: this.attempts, retryExhausted: this.retryExhausted }));
|
|
176
216
|
}
|
|
177
217
|
}
|
|
178
|
-
function reportObserverFault(phase, what, e) {
|
|
179
|
-
try {
|
|
180
|
-
hostLog('debug', `hitlBridge: onDecideOperation(${phase}) ${what}: ${String(e).slice(0, 160)}`);
|
|
181
|
-
return true;
|
|
182
|
-
}
|
|
183
|
-
catch {
|
|
184
|
-
return false;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
218
|
function wireOptsOf(opts) {
|
|
188
219
|
if (opts === undefined || opts.operation === undefined)
|
|
189
220
|
return opts;
|
|
190
221
|
return opts.signal !== undefined ? { signal: opts.signal } : undefined;
|
|
191
222
|
}
|
|
192
223
|
function notifyDecideObserver(observer, ev) {
|
|
193
|
-
|
|
194
|
-
const out = observer(ev);
|
|
195
|
-
if (out && typeof out.then === 'function') {
|
|
196
|
-
void Promise.resolve(out).then(undefined, (e) => {
|
|
197
|
-
reportObserverFault(ev.phase, 'rejected', e);
|
|
198
|
-
});
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
catch (e) {
|
|
202
|
-
reportObserverFault(ev.phase, 'threw', e);
|
|
203
|
-
}
|
|
224
|
+
invokeHostCallbackIsolated(`hitlBridge: onDecideOperation(${ev.phase})`, () => observer(ev));
|
|
204
225
|
}
|
|
205
226
|
const ANY_TOOL_FAMILY = () => true;
|
|
206
227
|
export async function findPendingForTask(client, taskId, matches, opts, callId, identityAccepts = (r) => matches(typeof r.toolName === 'string' ? r.toolName : undefined)) {
|
|
@@ -213,10 +234,21 @@ export async function findPendingForTask(client, taskId, matches, opts, callId,
|
|
|
213
234
|
hostLog('debug', `hitlBridge: approvals.list failed: ${t.log}`);
|
|
214
235
|
return { ok: false, reason: `approvals.list failed: ${t.reason}` };
|
|
215
236
|
}
|
|
216
|
-
const
|
|
237
|
+
const readings = rows.map((r) => ({ r, foreign: askParkForeignGateKind(r) }));
|
|
238
|
+
const decidable = readings.filter((x) => x.foreign === null).map((x) => x.r);
|
|
217
239
|
const identityRow = callId !== undefined
|
|
218
240
|
? decidable.find((r) => r.taskId === taskId && (r.boundCallId === callId || r.toolCallId === callId))
|
|
219
241
|
: undefined;
|
|
242
|
+
const identityForeign = callId !== undefined && identityRow === undefined
|
|
243
|
+
? readings.find((x) => x.r.taskId === taskId && (x.r.boundCallId === callId || x.r.toolCallId === callId) && x.foreign !== null)
|
|
244
|
+
: undefined;
|
|
245
|
+
if (identityForeign !== undefined) {
|
|
246
|
+
return {
|
|
247
|
+
ok: false,
|
|
248
|
+
reason: `the pending row this park names (call ${callId}) is parked on a '${String(identityForeign.foreign)}' gate — not an approval this leg decides; refusing to decide a different row`,
|
|
249
|
+
code: 'wrong_gate',
|
|
250
|
+
};
|
|
251
|
+
}
|
|
220
252
|
const identityConflicts = identityRow !== undefined && !identityAccepts(identityRow);
|
|
221
253
|
const pool = identityConflicts ? decidable.filter((r) => identityAccepts(r)) : decidable;
|
|
222
254
|
const pending = (identityConflicts ? undefined : identityRow) ??
|
|
@@ -275,7 +307,7 @@ export class HitlBridge {
|
|
|
275
307
|
if (p.boundCallId === undefined || p.boundInputHash === undefined) {
|
|
276
308
|
throw new HitlSafetyError(`pending checkpoint ${p.id ?? '<no-id>'} is missing D-1 binding fields ` +
|
|
277
309
|
`(boundCallId=${String(p.boundCallId)}, boundInputHash=${String(p.boundInputHash)}) — ` +
|
|
278
|
-
'pre-D-1 workers are no longer supported (server 5.x requires the verbatim two-tuple echo)', '
|
|
310
|
+
'pre-D-1 workers are no longer supported (server 5.x requires the verbatim two-tuple echo)', 'binding_missing');
|
|
279
311
|
}
|
|
280
312
|
return { boundCallId: p.boundCallId, boundInputHash: p.boundInputHash };
|
|
281
313
|
}
|
|
@@ -374,7 +406,7 @@ export class HitlBridge {
|
|
|
374
406
|
return r;
|
|
375
407
|
}
|
|
376
408
|
catch (e) {
|
|
377
|
-
retryExhausted = e
|
|
409
|
+
retryExhausted = thrownIsInstanceOf(e, DecideTransportRetryExhaustedError);
|
|
378
410
|
throw e;
|
|
379
411
|
}
|
|
380
412
|
finally {
|
|
@@ -407,9 +439,12 @@ export class HitlBridge {
|
|
|
407
439
|
return r;
|
|
408
440
|
}
|
|
409
441
|
catch (e) {
|
|
410
|
-
|
|
442
|
+
const binding = bindingMismatchReading(e);
|
|
443
|
+
if (binding === 'mismatch') {
|
|
411
444
|
throw new HitlSafetyError('approval_binding_mismatch — the pending action changed under the human; refetch + re-present', 'binding_mismatch');
|
|
412
445
|
}
|
|
446
|
+
if (binding === 'unreadable')
|
|
447
|
+
throw e;
|
|
413
448
|
if (!isTransientDecideTransportFailure(e) || callerAborted())
|
|
414
449
|
throw e;
|
|
415
450
|
if (isDecideAttemptTimeout(e)) {
|
|
@@ -479,16 +514,17 @@ function marshalAnswer(a) {
|
|
|
479
514
|
entry.note = a.note;
|
|
480
515
|
return entry;
|
|
481
516
|
}
|
|
482
|
-
function
|
|
517
|
+
function bindingMismatchReading(e) {
|
|
483
518
|
if (!e || typeof e !== 'object')
|
|
484
|
-
return
|
|
485
|
-
const
|
|
486
|
-
const
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
519
|
+
return 'not';
|
|
520
|
+
const code = readWireErrorCodeReading(e);
|
|
521
|
+
const name = readThrownSlot(e, 'name');
|
|
522
|
+
const family = (code.state === 'code' && code.code === 'approval_binding_mismatch') || name === 'ApprovalBindingMismatchError';
|
|
523
|
+
if (family)
|
|
524
|
+
return 'mismatch';
|
|
525
|
+
if (code.state === 'unreadable')
|
|
526
|
+
return 'unreadable';
|
|
527
|
+
return 'not';
|
|
492
528
|
}
|
|
493
529
|
export function backendDeny(reason) {
|
|
494
530
|
return {
|
|
@@ -2,7 +2,7 @@ import { createSessionSlot, DEFAULT_SESSION_KEY } from '../sessionSlot.js';
|
|
|
2
2
|
import { hostLog } from '../host.js';
|
|
3
3
|
import { unrefTimer } from '../unrefTimer.js';
|
|
4
4
|
import { decideFailureNote } from '../decideFailureNote.js';
|
|
5
|
-
import {
|
|
5
|
+
import { decisionRefusalSaysAskGone } from './decisionRefusal.js';
|
|
6
6
|
const hostSurfaceByKey = createSessionSlot();
|
|
7
7
|
const hostSurfaceMissesByKey = new Map();
|
|
8
8
|
export function installHitlHostSurface(surface) {
|
|
@@ -133,14 +133,6 @@ const RULE_NOT_SENT_REJECTED_TIMEOUT_MS = 10_000;
|
|
|
133
133
|
export function surfaceRuleArmRejected(why) {
|
|
134
134
|
surfaceSelfClearingWarn(RULE_NOT_SENT_REJECTED_KEY, ruleNotSentRejectedText(why), RULE_NOT_SENT_REJECTED_TIMEOUT_MS);
|
|
135
135
|
}
|
|
136
|
-
function isNoPendingError(e) {
|
|
137
|
-
if (e instanceof HitlSafetyError)
|
|
138
|
-
return e.code === 'no_pending';
|
|
139
|
-
if (typeof e !== 'object' || e === null || !('code' in e))
|
|
140
|
-
return false;
|
|
141
|
-
const code = e.code;
|
|
142
|
-
return typeof code === 'string' && code === 'no_pending';
|
|
143
|
-
}
|
|
144
136
|
export function observeCancelByDeny(settle, taskId) {
|
|
145
137
|
let timer;
|
|
146
138
|
const budget = new Promise((_, reject) => {
|
|
@@ -152,8 +144,8 @@ export function observeCancelByDeny(settle, taskId) {
|
|
|
152
144
|
hostLog('debug', `[hitl-cancel-deny] cancel-by-deny settled for run ${taskId} (session unlocked)`);
|
|
153
145
|
})
|
|
154
146
|
.catch((e) => {
|
|
155
|
-
if (
|
|
156
|
-
hostLog('debug', `[hitl-cancel-deny] cancel-by-deny
|
|
147
|
+
if (decisionRefusalSaysAskGone(e)) {
|
|
148
|
+
hostLog('debug', `[hitl-cancel-deny] cancel-by-deny found the question no longer pending for run ${taskId} (benign — settled elsewhere, parked or gone)`);
|
|
157
149
|
return;
|
|
158
150
|
}
|
|
159
151
|
const rowNote = decideFailureNote(e, 'deny');
|
|
@@ -22,16 +22,26 @@ export type LivePendingReading = {
|
|
|
22
22
|
dropped: number;
|
|
23
23
|
};
|
|
24
24
|
export declare function readLivePendingRows(body: unknown): LivePendingReading;
|
|
25
|
-
export
|
|
26
|
-
sessionId
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
export type SuspendedAskFilter = {
|
|
26
|
+
readonly sessionId: string;
|
|
27
|
+
readonly allSessions?: never;
|
|
28
|
+
readonly identityPending?: never;
|
|
29
|
+
} | {
|
|
30
|
+
readonly allSessions: true;
|
|
31
|
+
readonly sessionId?: never;
|
|
32
|
+
readonly identityPending?: never;
|
|
33
|
+
} | {
|
|
34
|
+
readonly identityPending: true;
|
|
35
|
+
readonly sessionId?: never;
|
|
36
|
+
readonly allSessions?: never;
|
|
37
|
+
};
|
|
38
|
+
export declare function suspendedSubagentAsks(snapshot: ApprovalsFeedEmission | null | undefined, filter: SuspendedAskFilter): LivePendingAskView[];
|
|
29
39
|
export interface ApprovalsAwaitingDecisionCount {
|
|
30
40
|
durable: number | null;
|
|
31
41
|
live: number | null;
|
|
32
42
|
suspendedSubagent: number | null;
|
|
33
43
|
}
|
|
34
|
-
export declare function countApprovalsAwaitingDecision(snapshot: ApprovalsFeedEmission | null | undefined, filter
|
|
44
|
+
export declare function countApprovalsAwaitingDecision(snapshot: ApprovalsFeedEmission | null | undefined, filter: SuspendedAskFilter): ApprovalsAwaitingDecisionCount;
|
|
35
45
|
export declare function livePendingRowToApprovalFrame(row: LivePendingAskView): ToolApprovalFrame;
|
|
36
46
|
export declare function surfaceSuspendedAskAndRespond(row: LivePendingAskView, respond: RespondToolApprovalFn, signal?: AbortSignal, lane?: ToolApprovalFrameLaneOpts): Promise<ToolApprovalFrameOutcome>;
|
|
37
47
|
export interface SuspendedAskDelta {
|
|
@@ -45,4 +55,4 @@ export interface SuspendedAskTracker {
|
|
|
45
55
|
requeue(approvalId: string): void;
|
|
46
56
|
noteDecided(approvalId: string): void;
|
|
47
57
|
}
|
|
48
|
-
export declare function createSuspendedAskTracker(filter
|
|
58
|
+
export declare function createSuspendedAskTracker(filter: SuspendedAskFilter): SuspendedAskTracker;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { THROWN_SLOT_UNREADABLE, readThrownSlot } from '../wireFailureShape.js';
|
|
1
2
|
import { isToolApprovalFrame, surfaceToolApprovalFrameAndRespond, } from './toolApprovalWire.js';
|
|
2
3
|
function nonEmptyString(v) {
|
|
3
4
|
return typeof v === 'string' && v !== '';
|
|
@@ -69,20 +70,48 @@ export function readLivePendingRows(body) {
|
|
|
69
70
|
return { kind: 'malformed' };
|
|
70
71
|
return { kind: 'present', rows, dropped };
|
|
71
72
|
}
|
|
72
|
-
|
|
73
|
+
const IDENTITY_PENDING_SCOPE = Object.freeze({ kind: 'identity_pending' });
|
|
74
|
+
function suspendedAskScopeOf(filter) {
|
|
75
|
+
if (typeof filter !== 'object' || filter === null)
|
|
76
|
+
return IDENTITY_PENDING_SCOPE;
|
|
77
|
+
const sessionId = readThrownSlot(filter, 'sessionId', true);
|
|
78
|
+
const allSessions = readThrownSlot(filter, 'allSessions', true);
|
|
79
|
+
const identityPending = readThrownSlot(filter, 'identityPending', true);
|
|
80
|
+
if (sessionId === THROWN_SLOT_UNREADABLE || allSessions === THROWN_SLOT_UNREADABLE || identityPending === THROWN_SLOT_UNREADABLE)
|
|
81
|
+
return IDENTITY_PENDING_SCOPE;
|
|
82
|
+
const sessionOk = typeof sessionId === 'string' && sessionId !== '';
|
|
83
|
+
const allOk = allSessions === true;
|
|
84
|
+
const pendingOk = identityPending === true;
|
|
85
|
+
if ((sessionId !== undefined && !sessionOk) || (allSessions !== undefined && !allOk) || (identityPending !== undefined && !pendingOk))
|
|
86
|
+
return IDENTITY_PENDING_SCOPE;
|
|
87
|
+
if (sessionOk && !allOk && !pendingOk)
|
|
88
|
+
return { kind: 'session', sessionId };
|
|
89
|
+
if (allOk && !sessionOk && !pendingOk)
|
|
90
|
+
return { kind: 'all' };
|
|
91
|
+
return IDENTITY_PENDING_SCOPE;
|
|
92
|
+
}
|
|
93
|
+
function subagentAsksIn(snapshot, scope) {
|
|
94
|
+
if (scope.kind === 'identity_pending')
|
|
95
|
+
return [];
|
|
73
96
|
if (snapshot?.kind === 'unknown')
|
|
74
97
|
return [];
|
|
75
98
|
const rows = snapshot?.livePending;
|
|
76
99
|
if (!Array.isArray(rows))
|
|
77
100
|
return [];
|
|
78
|
-
return rows.filter(r => r.fromSubagent === true && (
|
|
101
|
+
return rows.filter(r => r.fromSubagent === true && (scope.kind === 'all' || r.sessionId === scope.sessionId));
|
|
102
|
+
}
|
|
103
|
+
export function suspendedSubagentAsks(snapshot, filter) {
|
|
104
|
+
return subagentAsksIn(snapshot, suspendedAskScopeOf(filter));
|
|
79
105
|
}
|
|
80
106
|
export function countApprovalsAwaitingDecision(snapshot, filter) {
|
|
107
|
+
const scope = suspendedAskScopeOf(filter);
|
|
108
|
+
if (scope.kind === 'identity_pending')
|
|
109
|
+
return { durable: null, live: null, suspendedSubagent: null };
|
|
81
110
|
if (snapshot === null || snapshot === undefined)
|
|
82
111
|
return { durable: null, live: null, suspendedSubagent: null };
|
|
83
112
|
if (snapshot.kind === 'unknown')
|
|
84
113
|
return { durable: null, live: null, suspendedSubagent: null };
|
|
85
|
-
const bySession = (rows) =>
|
|
114
|
+
const bySession = (rows) => scope.kind === 'session' ? rows.filter(r => r.sessionId === scope.sessionId) : [...rows];
|
|
86
115
|
const durable = (snapshot.pendingDropped ?? 0) > 0 ? null : Array.isArray(snapshot.pending) ? bySession(snapshot.pending).length : null;
|
|
87
116
|
if (!Array.isArray(snapshot.livePending))
|
|
88
117
|
return { durable, live: null, suspendedSubagent: null };
|
|
@@ -113,6 +142,7 @@ export function surfaceSuspendedAskAndRespond(row, respond, signal, lane) {
|
|
|
113
142
|
}
|
|
114
143
|
const TRACKER_UNSEEN_CLAIMS_MAX = 512;
|
|
115
144
|
export function createSuspendedAskTracker(filter) {
|
|
145
|
+
const scope = suspendedAskScopeOf(filter);
|
|
116
146
|
const shown = new Set();
|
|
117
147
|
const shownWithFrame = new Set();
|
|
118
148
|
const claimed = new Map();
|
|
@@ -137,7 +167,9 @@ export function createSuspendedAskTracker(filter) {
|
|
|
137
167
|
ingest(snapshot) {
|
|
138
168
|
if (snapshot?.kind === 'unknown')
|
|
139
169
|
return { appeared: [], gone: [], upgraded: [] };
|
|
140
|
-
|
|
170
|
+
if (scope.kind === 'identity_pending')
|
|
171
|
+
return { appeared: [], gone: [], upgraded: [] };
|
|
172
|
+
const rows = subagentAsksIn(snapshot, scope);
|
|
141
173
|
const present = new Set(rows.map(r => r.approvalId));
|
|
142
174
|
const appeared = [];
|
|
143
175
|
const upgraded = [];
|
|
@@ -6,6 +6,7 @@ export interface LocalAllowRuleDeps {
|
|
|
6
6
|
bashRuleContentHasDangerousBarePrefix(ruleContent: string): boolean;
|
|
7
7
|
isDangerousBashPermission(toolName: string, ruleContent: string): boolean;
|
|
8
8
|
isDangerousPowerShellPermission(toolName: string, ruleContent: string): boolean;
|
|
9
|
+
onFailure?(log: string): void;
|
|
9
10
|
}
|
|
10
11
|
export type LocalAllowRuleParse = {
|
|
11
12
|
ok: true;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { reasonOfThrownWithSink } from '../hostCallbackGuard.js';
|
|
2
2
|
const BASH_TOOL_NAME_FOR_RULES = 'Bash';
|
|
3
3
|
export function parseLocalAllowRule(rule, expectedToolName, deps) {
|
|
4
4
|
if (typeof rule !== 'string' || rule === '') {
|
|
@@ -9,7 +9,7 @@ export function parseLocalAllowRule(rule, expectedToolName, deps) {
|
|
|
9
9
|
value = deps.parseRule(rule);
|
|
10
10
|
}
|
|
11
11
|
catch (e) {
|
|
12
|
-
return { ok: false, error: `rule text did not parse (${
|
|
12
|
+
return { ok: false, error: `rule text did not parse (${reasonOfThrownWithSink(e, (log) => deps.onFailure?.(log))})` };
|
|
13
13
|
}
|
|
14
14
|
if (typeof value.toolName !== 'string' || value.toolName === '') {
|
|
15
15
|
return { ok: false, error: 'rule text carries no tool name' };
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
export type NoAllowCause = 'no_allow_rule' | 'ask_rule' | 'budget' | 'other';
|
|
1
|
+
export type NoAllowCause = 'no_allow_rule' | 'ask_rule' | 'engine_ask_rule' | 'budget' | 'other';
|
|
2
2
|
export interface RuleLadderNoAllowFacts {
|
|
3
3
|
readonly allowed?: boolean;
|
|
4
4
|
readonly denied?: boolean;
|
|
5
5
|
readonly askRuleMatched?: boolean;
|
|
6
6
|
readonly budgetExhausted?: boolean;
|
|
7
7
|
readonly noRuleMatched?: boolean;
|
|
8
|
+
readonly noAskRuleMatched?: boolean;
|
|
8
9
|
}
|
|
9
10
|
export declare function noAllowCauseOf(card: object | null | undefined, ladder: RuleLadderNoAllowFacts | null | undefined): NoAllowCause | undefined;
|
|
@@ -18,8 +18,9 @@ export function noAllowCauseOf(card, ladder) {
|
|
|
18
18
|
if (ladderSays(ladder, 'budgetExhausted'))
|
|
19
19
|
return 'budget';
|
|
20
20
|
const standing = automaticAnswerVerdict(card, 'standing_rule');
|
|
21
|
-
if (standing.kind === 'must_ask' && (standing.askClass === 'ask_rule' || standing.origin === 'ask_rule'))
|
|
22
|
-
return 'ask_rule';
|
|
21
|
+
if (standing.kind === 'must_ask' && (standing.askClass === 'ask_rule' || standing.origin === 'ask_rule')) {
|
|
22
|
+
return ladderSays(ladder, 'noAskRuleMatched') || ladderSays(ladder, 'noRuleMatched') ? 'engine_ask_rule' : 'ask_rule';
|
|
23
|
+
}
|
|
23
24
|
if (ladderSays(ladder, 'noRuleMatched') && standing.kind === 'may_answer')
|
|
24
25
|
return 'no_allow_rule';
|
|
25
26
|
return 'other';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export type ApprovalCompleteDisposition = 'live-expired-parked' | 'live-expired-retract' | 'settled' | null;
|
|
2
|
+
export declare function classifyApprovalCompleteFrame(frame: unknown): ApprovalCompleteDisposition;
|
|
3
|
+
export type ParkRowDeadlineState = {
|
|
4
|
+
kind: 'none';
|
|
5
|
+
} | {
|
|
6
|
+
kind: 'pending';
|
|
7
|
+
deadlineMs: number;
|
|
8
|
+
remainingMs: number;
|
|
9
|
+
} | {
|
|
10
|
+
kind: 'past';
|
|
11
|
+
deadlineMs: number;
|
|
12
|
+
remainingMs: number;
|
|
13
|
+
};
|
|
14
|
+
export declare function parkRowDeadlineState(row: unknown, nowMs: number): ParkRowDeadlineState;
|
|
15
|
+
export declare function lateDecideRoute(o: {
|
|
16
|
+
windowClosed: boolean;
|
|
17
|
+
durableRowFound: boolean;
|
|
18
|
+
}): 'decide' | 'respond';
|
|
19
|
+
export declare function runReapedByDeadline(client: unknown, taskId: string): Promise<boolean>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { APPROVAL_EXPIRED } from '../engineErrorCodes.js';
|
|
2
|
+
import { approvalCompleteParked } from './approvalCompleteParked.js';
|
|
3
|
+
export function classifyApprovalCompleteFrame(frame) {
|
|
4
|
+
if (typeof frame !== 'object' || frame === null)
|
|
5
|
+
return null;
|
|
6
|
+
const f = frame;
|
|
7
|
+
if (f.type !== 'tool_approval_complete')
|
|
8
|
+
return null;
|
|
9
|
+
const outcome = f.outcome;
|
|
10
|
+
if (outcome === 'allowed' || outcome === 'denied')
|
|
11
|
+
return 'settled';
|
|
12
|
+
if (outcome !== 'expired')
|
|
13
|
+
return null;
|
|
14
|
+
return approvalCompleteParked(frame) ? 'live-expired-parked' : 'live-expired-retract';
|
|
15
|
+
}
|
|
16
|
+
const PARK_DEADLINE_MAX_SANE_MS = 24 * 60 * 60 * 1000;
|
|
17
|
+
export function parkRowDeadlineState(row, nowMs) {
|
|
18
|
+
if (typeof row !== 'object' || row === null)
|
|
19
|
+
return { kind: 'none' };
|
|
20
|
+
const raw = row.deadline;
|
|
21
|
+
if (typeof raw !== 'number' || !Number.isFinite(raw) || raw <= 0)
|
|
22
|
+
return { kind: 'none' };
|
|
23
|
+
const remainingMs = raw - nowMs;
|
|
24
|
+
if (remainingMs > PARK_DEADLINE_MAX_SANE_MS)
|
|
25
|
+
return { kind: 'none' };
|
|
26
|
+
return remainingMs > 0
|
|
27
|
+
? { kind: 'pending', deadlineMs: raw, remainingMs }
|
|
28
|
+
: { kind: 'past', deadlineMs: raw, remainingMs };
|
|
29
|
+
}
|
|
30
|
+
export function lateDecideRoute(o) {
|
|
31
|
+
if (!o.windowClosed)
|
|
32
|
+
return 'respond';
|
|
33
|
+
return o.durableRowFound ? 'decide' : 'respond';
|
|
34
|
+
}
|
|
35
|
+
export async function runReapedByDeadline(client, taskId) {
|
|
36
|
+
try {
|
|
37
|
+
const runs = client?.runs;
|
|
38
|
+
if (typeof runs?.get !== 'function')
|
|
39
|
+
return false;
|
|
40
|
+
const rec = (await runs.get(taskId));
|
|
41
|
+
return rec?.errorCode === APPROVAL_EXPIRED;
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { AgentEvent } from '@sema-agent/sdk';
|
|
2
|
-
import { type GateCurrentPending, type HitlFailureStage } from './hitlBridge.js';
|
|
2
|
+
import { type GateCurrentPending, type HitlFailureStage, type HitlSafetyCode } from './hitlBridge.js';
|
|
3
3
|
import { type QuestionAnswer } from '../liveQuestionStore.js';
|
|
4
|
-
import { type FsApprovalOutcome } from './toolApprovalWire.js';
|
|
5
4
|
import type { AskAnsweredOutput, GateLedger } from './gateLedger.js';
|
|
6
5
|
import { type AskGateWireDeps, type GatePark } from './frameRouter.js';
|
|
7
6
|
import { type DecideReceiptView } from '../decideReceipt.js';
|
|
@@ -13,8 +12,7 @@ export interface HopBudget {
|
|
|
13
12
|
}
|
|
14
13
|
export declare function nextHopBudget(prev: HopBudget | undefined, round: HopRound): HopBudget;
|
|
15
14
|
export declare const MAX_TOTAL_PARKS = 64;
|
|
16
|
-
export
|
|
17
|
-
export type GateFailureCode = (typeof GATE_FAILURE_CODES)[number];
|
|
15
|
+
export type GateFailureCode = HitlSafetyCode;
|
|
18
16
|
export type GateOutcome = {
|
|
19
17
|
kind: 'decided';
|
|
20
18
|
gatedCallId?: string | undefined;
|
|
@@ -30,14 +28,13 @@ export type GateOutcome = {
|
|
|
30
28
|
reason: string;
|
|
31
29
|
code?: GateFailureCode | undefined;
|
|
32
30
|
errorCode?: string | undefined;
|
|
31
|
+
blockedBy?: string | undefined;
|
|
33
32
|
retriable?: true;
|
|
34
33
|
retryExhausted?: true;
|
|
35
34
|
currentPending?: GateCurrentPending | undefined;
|
|
36
35
|
};
|
|
37
36
|
export declare function isAlreadyResolvedGateReason(reason: unknown): boolean;
|
|
38
|
-
export declare function isAlreadyResolvedFailure(
|
|
39
|
-
kind: 'failed';
|
|
40
|
-
}>): boolean;
|
|
37
|
+
export declare function isAlreadyResolvedFailure(failure: unknown): boolean;
|
|
41
38
|
export declare function isGateStandingErrorCode(code: string | null | undefined, retriable?: boolean): boolean;
|
|
42
39
|
export declare function isCodeClassifiedGateFailure(code: string | null | undefined, retriable?: boolean): boolean;
|
|
43
40
|
export declare function toAnsweredOutput(questions: unknown[], answer: QuestionAnswer): AskAnsweredOutput;
|