@sema-agent/client-core 0.97.1 → 0.98.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 +408 -0
- package/README.md +74 -37
- package/dist/adapt/arms.d.ts +1 -0
- package/dist/adapt/arms.js +128 -34
- package/dist/adapt/ids.d.ts +12 -1
- package/dist/adapt/ids.js +59 -8
- package/dist/adapt/instanceLedger.d.ts +50 -0
- package/dist/adapt/instanceLedger.js +147 -0
- package/dist/adapt/textStream.d.ts +1 -0
- package/dist/adapt/textStream.js +24 -7
- package/dist/adapt/toolCards.d.ts +27 -5
- package/dist/adapt/toolCards.js +39 -6
- package/dist/adapt/wireShapes.js +6 -2
- package/dist/adapt.d.ts +2 -0
- package/dist/adapt.js +8 -3
- package/dist/adapter/activeRunSelfHeal.d.ts +5 -0
- package/dist/adapter/activeRunSelfHeal.js +51 -28
- package/dist/adapter/downstream/eventToSdkMessage.d.ts +2 -5
- package/dist/adapter/downstream/eventToSdkMessage.js +27 -34
- package/dist/adapter/downstream/terminalToSdkResult.js +11 -4
- package/dist/adapter/downstream/turnUsageToModelUsage.d.ts +5 -2
- package/dist/adapter/downstream/turnUsageToModelUsage.js +2 -0
- package/dist/adapter/runStream.js +29 -13
- package/dist/adapter/types.d.ts +4 -4
- package/dist/agentSession/backgroundView.js +2 -1
- package/dist/agentSession/engineAgentRegistryRead.d.ts +2 -2
- package/dist/agentSession/engineAgentRegistryRead.js +12 -13
- package/dist/agentsWireCaps.d.ts +8 -8
- package/dist/agentsWireCaps.js +168 -175
- package/dist/approvalDecidedByCapability.d.ts +0 -4
- package/dist/approvalDecidedByCapability.js +0 -6
- package/dist/approvalsStreamLiveCapability.d.ts +0 -4
- package/dist/approvalsStreamLiveCapability.js +0 -6
- package/dist/assistantInbox.d.ts +34 -0
- package/dist/assistantInbox.js +118 -0
- package/dist/centerWiringCapability.js +9 -1
- package/dist/clientSlice.d.ts +0 -9
- package/dist/clientSlice.js +0 -3
- package/dist/cloudConfigWireCaps.d.ts +4 -2
- package/dist/cloudConfigWireCaps.js +81 -61
- package/dist/compensations.js +1 -1
- package/dist/connectorStatus.d.ts +21 -0
- package/dist/connectorStatus.js +112 -0
- package/dist/controlRouter.d.ts +14 -1
- package/dist/controlRouter.js +68 -17
- package/dist/coreValuePorts.d.ts +3 -3
- package/dist/decideReceipt.d.ts +2 -2
- package/dist/decideReceipt.js +5 -2
- package/dist/declared/supportFloorDeclared.js +3 -3
- package/dist/deviceExecutorManagementCapability.d.ts +0 -4
- package/dist/deviceExecutorManagementCapability.js +0 -6
- package/dist/deviceRebind.d.ts +49 -1
- package/dist/deviceRebind.js +221 -3
- package/dist/displayUntrusted.d.ts +1 -0
- package/dist/displayUntrusted.js +250 -76
- package/dist/engineAgentAbsence.d.ts +1 -1
- package/dist/engineAgentPanelStore.d.ts +5 -4
- package/dist/engineAgentPanelStore.js +3 -12
- package/dist/engineCapReader.d.ts +0 -4
- package/dist/engineCapReader.js +1 -5
- package/dist/engineCapsCache.d.ts +4 -0
- package/dist/engineCapsCache.js +17 -12
- package/dist/engineClosedSets.d.ts +1 -0
- package/dist/engineClosedSets.js +4 -1
- package/dist/engineErrorCodes.d.ts +9 -2
- package/dist/engineErrorCodes.js +9 -1
- package/dist/engineIdentity.d.ts +1 -0
- package/dist/engineIdentity.js +8 -0
- package/dist/engineRowRef.d.ts +28 -0
- package/dist/engineRowRef.js +111 -0
- package/dist/engineSessionMessages.d.ts +67 -0
- package/dist/engineSessionMessages.js +364 -0
- package/dist/engineToolDirectory.d.ts +0 -9
- package/dist/engineToolDirectory.js +1 -94
- package/dist/engineUrl.d.ts +18 -0
- package/dist/engineUrl.js +52 -0
- package/dist/env/uiLanguage.d.ts +9 -0
- package/dist/env/uiLanguage.js +35 -0
- package/dist/eventLeg.d.ts +92 -0
- package/dist/eventLeg.js +285 -0
- package/dist/executionLaneCapability.d.ts +0 -4
- package/dist/executionLaneCapability.js +3 -16
- package/dist/fileHistoryCaptureCapability.d.ts +0 -4
- package/dist/fileHistoryCaptureCapability.js +5 -7
- package/dist/fleet/fleetLedger.d.ts +0 -3
- package/dist/fleet/fleetLedger.js +21 -36
- package/dist/fleet/fleetProjection.d.ts +2 -2
- package/dist/fleet/fleetProjection.js +10 -8
- package/dist/frameBinding.d.ts +5 -0
- package/dist/frameBinding.js +23 -0
- package/dist/gateFailureCodes.d.ts +2 -0
- package/dist/gateFailureCodes.js +15 -0
- package/dist/gateOutcome.d.ts +3 -1
- package/dist/gateOutcome.js +25 -6
- package/dist/gateVocabulary.d.ts +5 -0
- package/dist/gateVocabulary.js +64 -2
- package/dist/generated/engineAskFaceTables.js +2 -2
- package/dist/generated/engineFactTables.d.ts +6 -3
- package/dist/generated/engineFactTables.js +22 -4
- package/dist/generated/engineNoticeTables.js +9 -0
- package/dist/generated/toolNameTables.d.ts +1 -0
- package/dist/generated/toolNameTables.js +1 -0
- package/dist/hitl/allowRuleShadow.d.ts +6 -1
- package/dist/hitl/allowRuleShadow.js +21 -17
- package/dist/hitl/approvalCardReading.d.ts +15 -0
- package/dist/hitl/approvalCardReading.js +154 -0
- package/dist/hitl/approvalCardReasons.d.ts +13 -0
- package/dist/hitl/approvalCardReasons.js +120 -0
- package/dist/hitl/approvalHolds.d.ts +47 -15
- package/dist/hitl/approvalHolds.js +134 -28
- package/dist/hitl/approvalResolution.d.ts +51 -26
- package/dist/hitl/approvalResolution.js +86 -122
- package/dist/hitl/approvalsFeed.js +6 -18
- package/dist/hitl/askClassPair.d.ts +2 -0
- package/dist/hitl/askClassPair.js +1 -0
- package/dist/hitl/askGateWire.d.ts +20 -2
- package/dist/hitl/askGateWire.js +49 -1
- package/dist/hitl/askParkRowRouting.d.ts +5 -0
- package/dist/hitl/askParkRowRouting.js +32 -1
- package/dist/hitl/askSettlementLine.d.ts +18 -0
- package/dist/hitl/askSettlementLine.js +79 -0
- package/dist/hitl/automaticAnswerVerdict.d.ts +1 -1
- package/dist/hitl/automaticAnswerVerdict.js +21 -5
- package/dist/hitl/crashConverged.d.ts +11 -20
- package/dist/hitl/crashConverged.js +56 -0
- package/dist/hitl/crashConvergedNotice.d.ts +3 -1
- package/dist/hitl/crashConvergedNotice.js +48 -11
- package/dist/hitl/decisionConflict.js +3 -10
- package/dist/hitl/decisionRefusal.d.ts +40 -1
- package/dist/hitl/decisionRefusal.js +199 -42
- package/dist/hitl/frameRouter.d.ts +5 -2
- package/dist/hitl/frameRouter.js +20 -16
- package/dist/hitl/gateLedger.d.ts +2 -0
- package/dist/hitl/gateLedger.js +50 -13
- package/dist/hitl/hitlBridge.d.ts +1 -2
- package/dist/hitl/hitlBridge.js +10 -7
- package/dist/hitl/livePendingAsk.d.ts +3 -3
- package/dist/hitl/livePendingAsk.js +7 -18
- package/dist/hitl/parkResolver.d.ts +2 -24
- package/dist/hitl/parkResolver.js +61 -97
- package/dist/hitl/persistedRulesWire.d.ts +24 -0
- package/dist/hitl/persistedRulesWire.js +122 -2
- package/dist/hitl/planReviewWire.d.ts +26 -13
- package/dist/hitl/planReviewWire.js +112 -78
- package/dist/hitl/refusedToolNameProse.d.ts +0 -1
- package/dist/hitl/refusedToolNameProse.js +0 -3
- package/dist/hitl/replayedApproval.d.ts +4 -3
- package/dist/hitl/replayedApproval.js +7 -4
- package/dist/hitl/sessionPolicyDeliverable.js +2 -4
- package/dist/hitl/sessionPolicyWire.d.ts +32 -20
- package/dist/hitl/sessionPolicyWire.js +162 -52
- package/dist/hitl/standingRows.d.ts +20 -2
- package/dist/hitl/standingRows.js +69 -8
- package/dist/hitl/toolApprovalWire.d.ts +87 -152
- package/dist/hitl/toolApprovalWire.js +591 -380
- package/dist/hookMatcherVerdict.d.ts +6 -1
- package/dist/hookMatcherVerdict.js +14 -7
- package/dist/hooksWireCaps.d.ts +2 -2
- package/dist/hooksWireCaps.js +59 -55
- package/dist/i18n/messages.en.d.ts +121 -0
- package/dist/i18n/messages.en.js +119 -0
- package/dist/i18n/messages.zh.d.ts +3 -0
- package/dist/i18n/messages.zh.js +120 -0
- package/dist/i18n/translate.d.ts +25 -0
- package/dist/i18n/translate.js +127 -0
- package/dist/index.d.ts +53 -20
- package/dist/index.js +38 -11
- package/dist/inheritEnvCapability.d.ts +31 -0
- package/dist/inheritEnvCapability.js +104 -0
- package/dist/liveModelCatalog.d.ts +1 -2
- package/dist/liveModelCatalog.js +2 -6
- package/dist/liveQuestionStore.d.ts +2 -21
- package/dist/mcpLiveness.d.ts +2 -1
- package/dist/mcpProbeWire.d.ts +6 -1
- package/dist/mcpProbeWire.js +1 -1
- package/dist/mcpWireCaps.d.ts +13 -2
- package/dist/mcpWireCaps.js +48 -0
- package/dist/memoryEntriesWire.d.ts +4 -9
- package/dist/model/modelSupplyRules.d.ts +0 -2
- package/dist/model/modelSupplyRules.js +3 -12
- package/dist/model/modelsPolicy.d.ts +0 -5
- package/dist/model/modelsPolicy.js +6 -36
- package/dist/model/subagentModelWord.d.ts +31 -0
- package/dist/model/subagentModelWord.js +261 -0
- package/dist/notifications.d.ts +6 -0
- package/dist/notifications.js +71 -23
- package/dist/outputStyleSeatCapability.d.ts +0 -3
- package/dist/outputStyleSeatCapability.js +0 -3
- package/dist/ownKey.d.ts +15 -0
- package/dist/ownKey.js +60 -3
- package/dist/panelReduce.d.ts +15 -9
- package/dist/panelReduce.js +680 -549
- package/dist/panelStateHolder.d.ts +3 -7
- package/dist/panelStateHolder.js +14 -130
- package/dist/peerLaneCapability.d.ts +0 -4
- package/dist/peerLaneCapability.js +0 -6
- package/dist/permissionRulesWriteCapability.d.ts +0 -4
- package/dist/permissionRulesWriteCapability.js +0 -6
- package/dist/permissionWireCaps.d.ts +2 -2
- package/dist/permissionWireCaps.js +2 -0
- package/dist/permissionsAllowGrantCapability.d.ts +0 -4
- package/dist/permissionsAllowGrantCapability.js +0 -6
- package/dist/permissionsDeclaration.d.ts +0 -11
- package/dist/permissionsDeclaration.js +60 -53
- package/dist/pluginHooksWire.d.ts +1 -1
- package/dist/pluginHooksWire.js +3 -6
- package/dist/preemptWire.d.ts +44 -0
- package/dist/preemptWire.js +83 -0
- package/dist/printToolResultFrame.js +15 -4
- package/dist/replayBody.d.ts +3 -0
- package/dist/replayBody.js +14 -0
- package/dist/request/taskRequest.d.ts +0 -1
- package/dist/request/taskRequest.js +0 -3
- package/dist/resumeRefusalCopy.d.ts +2 -1
- package/dist/resumeRefusalCopy.js +38 -2
- package/dist/retryStatus.d.ts +8 -0
- package/dist/retryStatus.js +106 -1
- package/dist/rewindArchiveCapability.d.ts +0 -4
- package/dist/rewindArchiveCapability.js +2 -10
- package/dist/rewindArchiveReading.d.ts +0 -1
- package/dist/rewindArchiveReading.js +0 -3
- package/dist/runCancelContext.d.ts +2 -1
- package/dist/runCancelContext.js +4 -2
- package/dist/runReattachPolicy.d.ts +31 -0
- package/dist/runReattachPolicy.js +46 -0
- package/dist/runTerminal.d.ts +3 -6
- package/dist/runTerminal.js +8 -9
- package/dist/sandboxWire.d.ts +3 -1
- package/dist/sandboxWire.js +76 -27
- package/dist/scenarioWire.js +1 -1
- package/dist/seam.d.ts +24 -2
- package/dist/seam.js +15 -3
- package/dist/seatContract.d.ts +53 -10
- package/dist/seatContract.js +132 -81
- package/dist/sessionPolicyCapability.d.ts +0 -4
- package/dist/sessionPolicyCapability.js +0 -6
- package/dist/sessionSyncFileHistoryCapability.d.ts +0 -3
- package/dist/sessionSyncFileHistoryCapability.js +0 -3
- package/dist/skillToolListsCapability.d.ts +0 -3
- package/dist/skillToolListsCapability.js +0 -3
- package/dist/sqlEngineCapability.d.ts +0 -4
- package/dist/sqlEngineCapability.js +0 -6
- package/dist/steerPriorityCapability.d.ts +0 -3
- package/dist/steerPriorityCapability.js +0 -3
- package/dist/streamDrainingLegs.d.ts +4 -0
- package/dist/streamDrainingLegs.js +6 -1
- package/dist/subagent/engineCompactWire.d.ts +0 -1
- package/dist/subagent/engineCompactWire.js +7 -5
- package/dist/subagent/engineTaskHandleWire.js +4 -7
- package/dist/subagentContentStore.js +1 -11
- package/dist/submitReopen.d.ts +24 -0
- package/dist/submitReopen.js +75 -0
- package/dist/terminalStatuses.d.ts +3 -0
- package/dist/terminalStatuses.js +10 -2
- package/dist/toolResult.d.ts +10 -1
- package/dist/toolResult.js +34 -6
- package/dist/toolRoster.d.ts +0 -2
- package/dist/toolRoster.js +0 -2
- package/dist/turnFailurePresentation.d.ts +28 -0
- package/dist/turnFailurePresentation.js +205 -0
- package/dist/userInvokedSkillsCapability.d.ts +0 -3
- package/dist/userInvokedSkillsCapability.js +0 -3
- package/dist/webSearchBackendCapability.d.ts +0 -4
- package/dist/webSearchBackendCapability.js +0 -6
- package/dist/wireErrorTriage.js +5 -24
- package/dist/wireFailureShape.d.ts +62 -5
- package/dist/wireFailureShape.js +105 -5
- package/dist/wireRefusalCopy.d.ts +12 -2
- package/dist/wireRefusalCopy.js +50 -52
- package/dist/workflowsJournalCapability.d.ts +0 -4
- package/dist/workflowsJournalCapability.js +0 -6
- package/dist/writeProtectionCapability.d.ts +0 -4
- package/dist/writeProtectionCapability.js +0 -6
- package/docs/INTEGRATION-CLIENTS.md +1253 -46
- package/package.json +5 -4
- package/dist/attachmentSeatCapability.d.ts +0 -12
- package/dist/attachmentSeatCapability.js +0 -23
- package/dist/hitl/approvalOutcomeNote.d.ts +0 -10
- package/dist/hitl/approvalOutcomeNote.js +0 -29
- package/dist/sessionReadRedactionCapability.d.ts +0 -13
- package/dist/sessionReadRedactionCapability.js +0 -35
|
@@ -1,51 +1,149 @@
|
|
|
1
1
|
import { hostLog } from '../host.js';
|
|
2
2
|
import { liveFrameCallKey } from './gateIdentity.js';
|
|
3
|
-
import {
|
|
3
|
+
import { decideReceiptReopen } from '../decideReceipt.js';
|
|
4
4
|
export const APPROVAL_SETTLED_HOWS = Object.freeze(['answered', 'interrupted', 'closed_by_engine']);
|
|
5
5
|
export const SETTLED_APPROVALS_MAX_ENTRIES = 4096;
|
|
6
6
|
const nonEmpty = (v) => typeof v === 'string' && v !== '';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
function sameApproval(who, h) {
|
|
8
|
+
const id = h.identity;
|
|
9
|
+
if (nonEmpty(who.approvalId) && nonEmpty(id.approvalId))
|
|
10
|
+
return who.approvalId === id.approvalId;
|
|
11
|
+
if (h.phase !== 'card')
|
|
12
|
+
return false;
|
|
13
|
+
if (!nonEmpty(who.taskId) || !nonEmpty(who.toolCallId) || id.taskId !== who.taskId || id.toolCallId !== who.toolCallId)
|
|
14
|
+
return false;
|
|
15
|
+
if (nonEmpty(who.sessionId) && nonEmpty(id.sessionId) && id.sessionId !== who.sessionId)
|
|
16
|
+
return false;
|
|
17
|
+
return !(nonEmpty(who.askSig) && nonEmpty(id.askSig) && id.askSig !== who.askSig);
|
|
18
|
+
}
|
|
19
|
+
export function approvalHoldFor(who, except) {
|
|
12
20
|
for (const h of approvalDecisionHolds.inFlight.values()) {
|
|
13
|
-
if (h
|
|
21
|
+
if (except?.(h) === true)
|
|
14
22
|
continue;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
continue;
|
|
18
|
-
if (nonEmpty(who.sessionId) && nonEmpty(id.sessionId) && id.sessionId !== who.sessionId)
|
|
19
|
-
continue;
|
|
20
|
-
return h;
|
|
23
|
+
if (sameApproval(who, h))
|
|
24
|
+
return h;
|
|
21
25
|
}
|
|
22
26
|
return undefined;
|
|
23
27
|
}
|
|
24
28
|
export function settledForDurableLane(entry) {
|
|
25
29
|
return entry !== undefined && !entry.parked;
|
|
26
30
|
}
|
|
27
|
-
export function liveCardAnsweredHow(
|
|
28
|
-
return answeredHowOf(approvalResolutionOf(o));
|
|
29
|
-
}
|
|
30
|
-
function answeredHowOf(r) {
|
|
31
|
+
export function liveCardAnsweredHow(r) {
|
|
31
32
|
if (r.kind === 'decided')
|
|
32
33
|
return 'answered';
|
|
33
34
|
return r.kind === 'unsettled' && r.cause === 'interrupted' ? 'interrupted' : undefined;
|
|
34
35
|
}
|
|
35
|
-
|
|
36
|
+
const HOLDER_FREE = Object.freeze({ kind: 'free' });
|
|
37
|
+
function nothingSentHere(asker) {
|
|
38
|
+
return Object.freeze({ kind: 'not_sent', lane: asker, cause: 'retracted' });
|
|
39
|
+
}
|
|
40
|
+
function interruptedThere(asker) {
|
|
41
|
+
return Object.freeze({ kind: 'unsettled', lane: asker, cause: 'interrupted' });
|
|
42
|
+
}
|
|
43
|
+
export async function awaitApprovalHolder(hold, signal, asker) {
|
|
44
|
+
if (hold.lane === 'host')
|
|
45
|
+
return awaitHostHolder(hold, signal, asker);
|
|
36
46
|
const unsubscribe = followCallerSignal(signal, hold.interrupt);
|
|
37
|
-
let o;
|
|
38
47
|
try {
|
|
39
|
-
|
|
48
|
+
if (hold.lane === 'live') {
|
|
49
|
+
let o;
|
|
50
|
+
try {
|
|
51
|
+
o = await hold.outcome;
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return HOLDER_FREE;
|
|
55
|
+
}
|
|
56
|
+
const stillHeld = approvalDecisionHolds.inFlight.get(liveFrameCallKey(hold.identity.approvalId)) === hold;
|
|
57
|
+
const entry = settledApprovalOf(hold.identity.approvalId);
|
|
58
|
+
if (!stillHeld && !settledForDurableLane(entry))
|
|
59
|
+
return HOLDER_FREE;
|
|
60
|
+
return Object.freeze({ kind: 'settled', how: entry?.how === 'answered' ? 'answered' : 'interrupted', outcome: o });
|
|
61
|
+
}
|
|
62
|
+
let r;
|
|
63
|
+
try {
|
|
64
|
+
r = await hold.outcome;
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return HOLDER_FREE;
|
|
68
|
+
}
|
|
69
|
+
if (r.kind === 'decided') {
|
|
70
|
+
if (decideReceiptReopen(r.receipt) !== null)
|
|
71
|
+
return HOLDER_FREE;
|
|
72
|
+
return Object.freeze({ kind: 'settled', how: 'answered', outcome: r });
|
|
73
|
+
}
|
|
74
|
+
if (r.kind !== 'unsettled' || r.cause !== 'interrupted' || hold.trailing === undefined)
|
|
75
|
+
return HOLDER_FREE;
|
|
76
|
+
const landed = await hold.trailing.then(() => true, () => false);
|
|
77
|
+
return landed ? Object.freeze({ kind: 'settled', how: 'interrupted', outcome: r }) : HOLDER_FREE;
|
|
40
78
|
}
|
|
41
|
-
|
|
42
|
-
|
|
79
|
+
finally {
|
|
80
|
+
unsubscribe();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
async function awaitHostHolder(hold, signal, asker) {
|
|
84
|
+
let leave = () => { };
|
|
85
|
+
const left = new Promise((resolve) => {
|
|
86
|
+
leave = () => resolve('left');
|
|
87
|
+
});
|
|
88
|
+
const unsubscribe = followCallerSignal(signal, leave);
|
|
89
|
+
try {
|
|
90
|
+
const r = await Promise.race([hold.released, left]);
|
|
91
|
+
if (r === 'left')
|
|
92
|
+
return Object.freeze({ kind: 'left' });
|
|
93
|
+
if (r === undefined)
|
|
94
|
+
return HOLDER_FREE;
|
|
95
|
+
return Object.freeze({ kind: 'settled', how: r, outcome: r === 'interrupted' ? interruptedThere(asker) : nothingSentHere(asker) });
|
|
43
96
|
}
|
|
44
97
|
finally {
|
|
45
98
|
unsubscribe();
|
|
46
99
|
}
|
|
47
|
-
|
|
48
|
-
|
|
100
|
+
}
|
|
101
|
+
function holdHostCard(identity) {
|
|
102
|
+
const h = approvalDecisionHolds;
|
|
103
|
+
const key = `hitl-host:${++h.clock}`;
|
|
104
|
+
let resolveReleased = () => { };
|
|
105
|
+
const released = new Promise((resolve) => {
|
|
106
|
+
resolveReleased = resolve;
|
|
107
|
+
});
|
|
108
|
+
const frozen = Object.freeze({ ...identity });
|
|
109
|
+
const hold = { lane: 'host', identity: frozen, phase: 'card', released };
|
|
110
|
+
h.inFlight.set(key, hold);
|
|
111
|
+
let done = false;
|
|
112
|
+
return Object.freeze({
|
|
113
|
+
identity: frozen,
|
|
114
|
+
sending: () => {
|
|
115
|
+
if (!done)
|
|
116
|
+
hold.phase = 'respond';
|
|
117
|
+
},
|
|
118
|
+
release: (settled) => {
|
|
119
|
+
if (done)
|
|
120
|
+
return;
|
|
121
|
+
done = true;
|
|
122
|
+
const how = settled === 'answered' || settled === 'interrupted' ? settled : undefined;
|
|
123
|
+
if (how !== undefined && nonEmpty(frozen.approvalId))
|
|
124
|
+
noteSettled(frozen.approvalId, how, false, how === 'interrupted' ? interruptedThere('decide') : nothingSentHere('decide'), true);
|
|
125
|
+
if (h.inFlight.get(key) === hold)
|
|
126
|
+
h.inFlight.delete(key);
|
|
127
|
+
resolveReleased(how);
|
|
128
|
+
},
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
const CLAIM_MAX_ROUNDS = 8;
|
|
132
|
+
export async function claimApprovalCardFor(who, signal) {
|
|
133
|
+
for (let round = 0; round < CLAIM_MAX_ROUNDS; round++) {
|
|
134
|
+
const entry = settledApprovalOf(who.approvalId);
|
|
135
|
+
if (settledForDurableLane(entry) && entry !== undefined)
|
|
136
|
+
return Object.freeze({ kind: 'joined', outcome: { ...entry.outcome, joinedInFlight: true } });
|
|
137
|
+
const holder = approvalHoldFor(who);
|
|
138
|
+
if (holder === undefined)
|
|
139
|
+
return Object.freeze({ kind: 'held', hold: holdHostCard(who) });
|
|
140
|
+
const wait = await awaitApprovalHolder(holder, signal, 'decide');
|
|
141
|
+
if (wait.kind === 'settled')
|
|
142
|
+
return Object.freeze({ kind: 'joined', outcome: { ...wait.outcome, joinedInFlight: true } });
|
|
143
|
+
if (wait.kind === 'left')
|
|
144
|
+
return Object.freeze({ kind: 'joined', outcome: { ...nothingSentHere('decide'), joinedInFlight: true } });
|
|
145
|
+
}
|
|
146
|
+
return Object.freeze({ kind: 'held', hold: holdHostCard(who) });
|
|
49
147
|
}
|
|
50
148
|
export const approvalDecisionHolds = { inFlight: new Map(), settled: new Map(), openReads: new Set(), outcomes: new Map(), clock: 0 };
|
|
51
149
|
export function settledApprovalOf(approvalId) {
|
|
@@ -57,14 +155,17 @@ export function clearSettledApprovals() {
|
|
|
57
155
|
export function anyApprovalSettled() {
|
|
58
156
|
return approvalDecisionHolds.outcomes.size > 0;
|
|
59
157
|
}
|
|
60
|
-
function noteSettled(approvalId, how, parked, outcome) {
|
|
158
|
+
function noteSettled(approvalId, how, parked, outcome, upgradesParked = false) {
|
|
61
159
|
if (typeof approvalId !== 'string' || approvalId === '')
|
|
62
160
|
return;
|
|
63
161
|
if (!APPROVAL_SETTLED_HOWS.includes(how))
|
|
64
162
|
return;
|
|
65
163
|
const t = approvalDecisionHolds.outcomes;
|
|
66
|
-
|
|
164
|
+
const prev = t.get(approvalId);
|
|
165
|
+
if (prev !== undefined && !(upgradesParked && prev.parked && how !== 'closed_by_engine'))
|
|
67
166
|
return;
|
|
167
|
+
if (prev !== undefined)
|
|
168
|
+
t.delete(approvalId);
|
|
68
169
|
t.set(approvalId, Object.freeze({ how, parked, outcome: Object.freeze({ ...outcome }) }));
|
|
69
170
|
while (t.size > SETTLED_APPROVALS_MAX_ENTRIES) {
|
|
70
171
|
const oldest = t.keys().next();
|
|
@@ -73,9 +174,14 @@ function noteSettled(approvalId, how, parked, outcome) {
|
|
|
73
174
|
t.delete(oldest.value);
|
|
74
175
|
}
|
|
75
176
|
}
|
|
76
|
-
|
|
177
|
+
function engineClosedOutcome() {
|
|
178
|
+
return Object.freeze({ kind: 'not_sent', lane: 'respond', cause: 'retracted' });
|
|
179
|
+
}
|
|
77
180
|
export function noteEngineClosedApproval(approvalId, parked) {
|
|
78
|
-
noteSettled(approvalId, 'closed_by_engine', parked,
|
|
181
|
+
noteSettled(approvalId, 'closed_by_engine', parked, engineClosedOutcome());
|
|
182
|
+
}
|
|
183
|
+
export function noteHolderSettledApproval(approvalId, how, outcome) {
|
|
184
|
+
noteSettled(approvalId, how, false, outcome, true);
|
|
79
185
|
}
|
|
80
186
|
export function settledLiveCardOutcome(approvalId) {
|
|
81
187
|
const e = settledApprovalOf(approvalId);
|
|
@@ -1,36 +1,61 @@
|
|
|
1
1
|
import type { DecideReceiptView } from '../decideReceipt.js';
|
|
2
|
-
import type
|
|
3
|
-
import type {
|
|
4
|
-
|
|
2
|
+
import { type HitlSafetyCode } from './hitlBridge.js';
|
|
3
|
+
import type { AskAnsweredOutput } from './gateLedger.js';
|
|
4
|
+
import type { ApprovalDenySettledBy, ToolApprovalRespondAckView, ToolApprovalRespondDecision, ToolApprovalRespondParkingView } from './toolApprovalWire.js';
|
|
5
|
+
import { type DecisionRefusalReading, type RefusalRouteContext } from './decisionRefusal.js';
|
|
6
|
+
export declare const APPROVAL_RESOLUTION_LANES: readonly ["respond", "decide", "ask"];
|
|
7
|
+
export type ApprovalResolutionLane = (typeof APPROVAL_RESOLUTION_LANES)[number];
|
|
8
|
+
export declare const APPROVAL_NOT_SENT_CAUSES: readonly ["retracted", "edit_refused", "no_pending", "wrong_gate", "fetch_failed", "no_input", "card_unavailable", "safety_stop"];
|
|
5
9
|
export type ApprovalNotSentCause = (typeof APPROVAL_NOT_SENT_CAUSES)[number];
|
|
6
|
-
export declare const APPROVAL_UNSETTLED_CAUSES: readonly ["engine_refused", "
|
|
10
|
+
export declare const APPROVAL_UNSETTLED_CAUSES: readonly ["engine_refused", "engine_error", "no_answer", "transport_exhausted", "parking_in_progress", "interrupted", "orchestration", "unreadable"];
|
|
7
11
|
export type ApprovalUnsettledCause = (typeof APPROVAL_UNSETTLED_CAUSES)[number];
|
|
8
|
-
export interface
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
receipt?: DecideReceiptView;
|
|
13
|
-
ack?: ToolApprovalRespondAckView;
|
|
12
|
+
export interface ApprovalDenyFacts {
|
|
13
|
+
readonly settledBy?: ApprovalDenySettledBy;
|
|
14
|
+
readonly reason?: string;
|
|
15
|
+
readonly attributionKey?: 'dropped' | 'renamed';
|
|
14
16
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
detail?: string;
|
|
17
|
+
interface ApprovalResolutionBase {
|
|
18
|
+
readonly lane: ApprovalResolutionLane;
|
|
19
|
+
readonly gatedCallId?: string;
|
|
20
|
+
readonly joinedInFlight?: true;
|
|
20
21
|
}
|
|
21
|
-
export interface
|
|
22
|
-
kind: '
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
22
|
+
export interface ApprovalResolutionDecided extends ApprovalResolutionBase {
|
|
23
|
+
readonly kind: 'decided';
|
|
24
|
+
readonly decision: ToolApprovalRespondDecision;
|
|
25
|
+
readonly deny?: ApprovalDenyFacts;
|
|
26
|
+
readonly receipt?: DecideReceiptView;
|
|
27
|
+
readonly ack?: ToolApprovalRespondAckView;
|
|
28
|
+
readonly answered?: AskAnsweredOutput;
|
|
29
|
+
}
|
|
30
|
+
export interface ApprovalResolutionNotSent extends ApprovalResolutionBase {
|
|
31
|
+
readonly kind: 'not_sent';
|
|
32
|
+
readonly cause: ApprovalNotSentCause;
|
|
33
|
+
readonly safetyCode?: Exclude<HitlSafetyCode, 'binding_mismatch' | 'no_pending' | 'wrong_gate'>;
|
|
34
|
+
readonly detail?: string;
|
|
35
|
+
}
|
|
36
|
+
export interface ApprovalResolutionUnsettled extends ApprovalResolutionBase {
|
|
37
|
+
readonly kind: 'unsettled';
|
|
38
|
+
readonly cause: ApprovalUnsettledCause;
|
|
39
|
+
readonly safetyCode?: 'binding_mismatch';
|
|
40
|
+
readonly refusal?: DecisionRefusalReading;
|
|
41
|
+
readonly parking?: ToolApprovalRespondParkingView;
|
|
42
|
+
readonly detail?: string;
|
|
30
43
|
}
|
|
31
44
|
export type ApprovalResolution = ApprovalResolutionDecided | ApprovalResolutionNotSent | ApprovalResolutionUnsettled;
|
|
32
|
-
export type ApprovalLegOutcome = FsApprovalOutcome | ToolApprovalFrameOutcome;
|
|
33
|
-
export declare function approvalResolutionOf(outcome: ApprovalLegOutcome): ApprovalResolution;
|
|
34
45
|
export declare function isApprovalDecided(r: ApprovalResolution): r is ApprovalResolutionDecided;
|
|
35
46
|
export declare function approvalNotSentCause(r: ApprovalResolution): ApprovalNotSentCause | undefined;
|
|
36
47
|
export declare function approvalUnsettledCause(r: ApprovalResolution): ApprovalUnsettledCause | undefined;
|
|
48
|
+
export declare const APPROVAL_NOTE_RETRACTED_DETAIL = "the card was retracted (this host no longer has a decision port for it)";
|
|
49
|
+
export declare const APPROVAL_NOTE_EDIT_REFUSED_DETAIL = "edits are not accepted on this card";
|
|
50
|
+
export declare function approvalResolutionDetail(r: ApprovalResolution): string | undefined;
|
|
51
|
+
export declare function unsettledCauseOfReading(reading: DecisionRefusalReading): 'engine_refused' | 'engine_error' | 'no_answer';
|
|
52
|
+
export interface DecisionFailureMint {
|
|
53
|
+
readonly lane: ApprovalResolutionLane;
|
|
54
|
+
readonly route: NonNullable<RefusalRouteContext['route']>;
|
|
55
|
+
readonly gatedCallId?: string | undefined;
|
|
56
|
+
readonly detail?: string | undefined;
|
|
57
|
+
readonly attributionCarried?: boolean | undefined;
|
|
58
|
+
}
|
|
59
|
+
export declare function resolutionOfDecisionFailure(e: {} | null | undefined, m: DecisionFailureMint): ApprovalResolution;
|
|
60
|
+
export declare function joinedResolution(r: ApprovalResolution, gatedCallId?: string): ApprovalResolution;
|
|
61
|
+
export {};
|
|
@@ -1,156 +1,120 @@
|
|
|
1
|
+
import { DecideTransportRetryExhaustedError } from './hitlBridge.js';
|
|
2
|
+
import { mintDecisionRefusalReading, refusalCarrierOf } from './decisionRefusal.js';
|
|
3
|
+
import { thrownIsInstanceOf } from '../wireFailureShape.js';
|
|
4
|
+
export const APPROVAL_RESOLUTION_LANES = Object.freeze(['respond', 'decide', 'ask']);
|
|
1
5
|
export const APPROVAL_NOT_SENT_CAUSES = Object.freeze([
|
|
2
6
|
'retracted',
|
|
3
7
|
'edit_refused',
|
|
4
8
|
'no_pending',
|
|
9
|
+
'wrong_gate',
|
|
5
10
|
'fetch_failed',
|
|
6
11
|
'no_input',
|
|
7
12
|
'card_unavailable',
|
|
13
|
+
'safety_stop',
|
|
8
14
|
]);
|
|
9
15
|
export const APPROVAL_UNSETTLED_CAUSES = Object.freeze([
|
|
10
16
|
'engine_refused',
|
|
11
|
-
'
|
|
17
|
+
'engine_error',
|
|
18
|
+
'no_answer',
|
|
12
19
|
'transport_exhausted',
|
|
13
|
-
'safety_stop',
|
|
14
|
-
'respond_failed',
|
|
15
20
|
'parking_in_progress',
|
|
16
21
|
'interrupted',
|
|
17
22
|
'orchestration',
|
|
18
23
|
'unreadable',
|
|
19
24
|
]);
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
return typeof v === 'string' && v.length > 0 ? v : undefined;
|
|
25
|
+
export function isApprovalDecided(r) {
|
|
26
|
+
return typeof r === 'object' && r !== null && r.kind === 'decided';
|
|
23
27
|
}
|
|
24
|
-
function
|
|
25
|
-
|
|
28
|
+
export function approvalNotSentCause(r) {
|
|
29
|
+
if (typeof r !== 'object' || r === null || r.kind !== 'not_sent')
|
|
30
|
+
return undefined;
|
|
31
|
+
return r.cause;
|
|
26
32
|
}
|
|
27
|
-
function
|
|
33
|
+
export function approvalUnsettledCause(r) {
|
|
34
|
+
if (typeof r !== 'object' || r === null || r.kind !== 'unsettled')
|
|
35
|
+
return undefined;
|
|
36
|
+
return r.cause;
|
|
37
|
+
}
|
|
38
|
+
export const APPROVAL_NOTE_RETRACTED_DETAIL = 'the card was retracted (this host no longer has a decision port for it)';
|
|
39
|
+
export const APPROVAL_NOTE_EDIT_REFUSED_DETAIL = 'edits are not accepted on this card';
|
|
40
|
+
const NOT_SENT_SENTENCES = Object.freeze({
|
|
41
|
+
retracted: APPROVAL_NOTE_RETRACTED_DETAIL,
|
|
42
|
+
edit_refused: APPROVAL_NOTE_EDIT_REFUSED_DETAIL,
|
|
43
|
+
no_pending: 'there was no pending approval to decide for this run (it may already have been decided or expired); nothing was sent',
|
|
44
|
+
wrong_gate: 'the pending approval is waiting at a different kind of gate than this card; nothing was sent',
|
|
45
|
+
fetch_failed: 'the pending approval could not be fetched; nothing was sent',
|
|
46
|
+
no_input: 'the approval has no tool input or question to show, so no card was shown; nothing was sent',
|
|
47
|
+
card_unavailable: 'no approval card could be shown on this host; nothing was sent',
|
|
48
|
+
safety_stop: 'the decision was stopped by a local safety check before it was sent; nothing was sent',
|
|
49
|
+
});
|
|
50
|
+
function nonEmpty(v) {
|
|
51
|
+
return typeof v === 'string' && v.length > 0 ? v : undefined;
|
|
52
|
+
}
|
|
53
|
+
function ownStr(o, key) {
|
|
28
54
|
try {
|
|
29
|
-
|
|
55
|
+
if (typeof o !== 'object' || o === null)
|
|
56
|
+
return undefined;
|
|
57
|
+
const d = Object.getOwnPropertyDescriptor(o, key);
|
|
58
|
+
return d !== undefined && Object.hasOwn(d, 'value') ? nonEmpty(d.value) : undefined;
|
|
30
59
|
}
|
|
31
60
|
catch {
|
|
32
61
|
return undefined;
|
|
33
62
|
}
|
|
34
63
|
}
|
|
35
|
-
function
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
if (typeof outcome !== 'object' || outcome === null || Array.isArray(outcome)) {
|
|
40
|
-
return { kind: 'unsettled', cause: 'unreadable' };
|
|
64
|
+
export function approvalResolutionDetail(r) {
|
|
65
|
+
let kind;
|
|
66
|
+
try {
|
|
67
|
+
kind = typeof r === 'object' && r !== null ? r.kind : undefined;
|
|
41
68
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
return fsLegResolution(outcome, kind);
|
|
69
|
+
catch {
|
|
70
|
+
return undefined;
|
|
45
71
|
}
|
|
46
|
-
if (
|
|
47
|
-
|
|
72
|
+
if (kind === 'not_sent') {
|
|
73
|
+
const cause = ownStr(r, 'cause');
|
|
74
|
+
if (cause === undefined || !Object.hasOwn(NOT_SENT_SENTENCES, cause))
|
|
75
|
+
return undefined;
|
|
76
|
+
const sentence = NOT_SENT_SENTENCES[cause];
|
|
77
|
+
const code = cause === 'safety_stop' ? ownStr(r, 'safetyCode') : undefined;
|
|
78
|
+
return code !== undefined ? `${sentence} (${code})` : sentence;
|
|
48
79
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
return {
|
|
56
|
-
kind: 'decided',
|
|
57
|
-
decision: pick(outcome, 'denied') === true ? 'deny' : 'allow',
|
|
58
|
-
...call,
|
|
59
|
-
...opt('receipt', pick(outcome, 'receipt')),
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
if (kind === 'retracted')
|
|
63
|
-
return { kind: 'not_sent', cause: 'retracted', ...call };
|
|
64
|
-
if (kind === 'aborted')
|
|
65
|
-
return { kind: 'unsettled', cause: 'interrupted', ...call };
|
|
66
|
-
const detail = opt('detail', str(pick(outcome, 'reason')));
|
|
67
|
-
const stage = pick(outcome, 'stage');
|
|
68
|
-
if (stage === 'fetch') {
|
|
69
|
-
const cause = pick(outcome, 'code') === 'no_pending' ? 'no_pending' : 'fetch_failed';
|
|
70
|
-
return { kind: 'not_sent', cause, ...call, ...detail };
|
|
80
|
+
if (kind !== 'unsettled')
|
|
81
|
+
return undefined;
|
|
82
|
+
let refusal;
|
|
83
|
+
try {
|
|
84
|
+
const d = Object.getOwnPropertyDescriptor(r, 'refusal');
|
|
85
|
+
refusal = d !== undefined && Object.hasOwn(d, 'value') ? d.value : undefined;
|
|
71
86
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
if (stage === 'card' && pick(outcome, 'editRefused') === true)
|
|
75
|
-
return { kind: 'not_sent', cause: 'edit_refused', ...call, ...detail };
|
|
76
|
-
if (stage === 'card')
|
|
77
|
-
return { kind: 'not_sent', cause: 'card_unavailable', ...call, ...detail };
|
|
78
|
-
if (stage === 'decide') {
|
|
79
|
-
const safetyCode = str(pick(outcome, 'safetyCode'));
|
|
80
|
-
const errorCode = str(pick(outcome, 'errorCode'));
|
|
81
|
-
const engineAnswered = errorCode !== undefined || pick(outcome, 'currentPending') !== undefined;
|
|
82
|
-
const cause = safetyCode !== undefined
|
|
83
|
-
? 'safety_stop'
|
|
84
|
-
: pick(outcome, 'retryExhausted') === true
|
|
85
|
-
? 'transport_exhausted'
|
|
86
|
-
: engineAnswered
|
|
87
|
-
? 'engine_refused'
|
|
88
|
-
: 'decide_failed';
|
|
89
|
-
return {
|
|
90
|
-
kind: 'unsettled',
|
|
91
|
-
cause,
|
|
92
|
-
...call,
|
|
93
|
-
...opt('safetyCode', safetyCode),
|
|
94
|
-
...opt('errorCode', errorCode),
|
|
95
|
-
...detail,
|
|
96
|
-
};
|
|
87
|
+
catch {
|
|
88
|
+
refusal = undefined;
|
|
97
89
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
return { kind: 'unsettled', cause: 'unreadable', ...call, ...detail };
|
|
90
|
+
const parts = [ownStr(refusal, 'errorCode'), ownStr(r, 'detail') ?? ownStr(refusal, 'message')].filter((x) => x !== undefined);
|
|
91
|
+
return parts.length > 0 ? parts.join(' · ') : undefined;
|
|
101
92
|
}
|
|
102
|
-
function
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
const hint = pick(v, 'retryAfterMs');
|
|
107
|
-
const retryAfterMs = typeof hint === 'number' && Number.isFinite(hint) && hint >= 0 ? hint : undefined;
|
|
108
|
-
const decidePath = str(pick(v, 'decidePath'));
|
|
109
|
-
const message = str(pick(v, 'message'));
|
|
110
|
-
return {
|
|
111
|
-
approvalId,
|
|
112
|
-
...(retryAfterMs !== undefined ? { retryAfterMs } : {}),
|
|
113
|
-
...(decidePath !== undefined ? { decidePath } : {}),
|
|
114
|
-
...(message !== undefined ? { message } : {}),
|
|
115
|
-
};
|
|
93
|
+
export function unsettledCauseOfReading(reading) {
|
|
94
|
+
if (reading.standing === 'ambiguous')
|
|
95
|
+
return 'engine_error';
|
|
96
|
+
return reading.standing === undefined ? 'no_answer' : 'engine_refused';
|
|
116
97
|
}
|
|
117
|
-
function
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
return { kind: 'not_sent', cause: 'edit_refused' };
|
|
122
|
-
if (pick(outcome, 'aborted') === true)
|
|
123
|
-
return { kind: 'unsettled', cause: 'interrupted' };
|
|
124
|
-
const parking = parkingViewOf(pick(outcome, 'parking'));
|
|
125
|
-
if (parking !== undefined)
|
|
126
|
-
return { kind: 'unsettled', cause: 'parking_in_progress', parking };
|
|
127
|
-
if (pick(outcome, 'decision') === 'unresolved') {
|
|
128
|
-
const refusal = pick(outcome, 'respondRefusal');
|
|
129
|
-
return {
|
|
130
|
-
kind: 'unsettled',
|
|
131
|
-
cause: 'respond_failed',
|
|
132
|
-
...opt('status', num(pick(refusal, 'status'))),
|
|
133
|
-
...opt('errorCode', str(pick(refusal, 'errorCode'))),
|
|
134
|
-
...opt('detail', str(pick(refusal, 'message'))),
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
const ack = pick(outcome, 'ack');
|
|
138
|
-
return {
|
|
139
|
-
kind: 'decided',
|
|
140
|
-
decision: pick(outcome, 'decision'),
|
|
141
|
-
...(typeof ack === 'object' && ack !== null ? { ack: ack } : {}),
|
|
98
|
+
export function resolutionOfDecisionFailure(e, m) {
|
|
99
|
+
const base = {
|
|
100
|
+
lane: m.lane,
|
|
101
|
+
...(m.gatedCallId !== undefined ? { gatedCallId: m.gatedCallId } : {}),
|
|
142
102
|
};
|
|
103
|
+
const detail = m.detail !== undefined && m.detail.length > 0 ? { detail: m.detail } : {};
|
|
104
|
+
const { local } = refusalCarrierOf(e);
|
|
105
|
+
if (local !== undefined && local !== 'binding_mismatch') {
|
|
106
|
+
if (local === 'no_pending' || local === 'wrong_gate')
|
|
107
|
+
return { kind: 'not_sent', ...base, cause: local, ...detail };
|
|
108
|
+
return { kind: 'not_sent', ...base, cause: 'safety_stop', safetyCode: local, ...detail };
|
|
109
|
+
}
|
|
110
|
+
const refusal = mintDecisionRefusalReading(e, { route: m.route }, m.attributionCarried);
|
|
111
|
+
if (local === 'binding_mismatch')
|
|
112
|
+
return { kind: 'unsettled', ...base, cause: 'engine_refused', safetyCode: 'binding_mismatch', refusal, ...detail };
|
|
113
|
+
if (thrownIsInstanceOf(e, DecideTransportRetryExhaustedError))
|
|
114
|
+
return { kind: 'unsettled', ...base, cause: 'transport_exhausted', refusal, ...detail };
|
|
115
|
+
return { kind: 'unsettled', ...base, cause: unsettledCauseOfReading(refusal), refusal, ...detail };
|
|
143
116
|
}
|
|
144
|
-
export function
|
|
145
|
-
|
|
146
|
-
}
|
|
147
|
-
export function approvalNotSentCause(r) {
|
|
148
|
-
if (typeof r !== 'object' || r === null || r.kind !== 'not_sent')
|
|
149
|
-
return undefined;
|
|
150
|
-
return r.cause;
|
|
151
|
-
}
|
|
152
|
-
export function approvalUnsettledCause(r) {
|
|
153
|
-
if (typeof r !== 'object' || r === null || r.kind !== 'unsettled')
|
|
154
|
-
return undefined;
|
|
155
|
-
return r.cause;
|
|
117
|
+
export function joinedResolution(r, gatedCallId) {
|
|
118
|
+
const carry = r.gatedCallId === undefined && gatedCallId !== undefined && gatedCallId !== '' ? { gatedCallId } : {};
|
|
119
|
+
return { ...r, ...carry, joinedInFlight: true };
|
|
156
120
|
}
|
|
@@ -24,15 +24,6 @@ function readDurablePendingRows(raw) {
|
|
|
24
24
|
return { kind: 'malformed' };
|
|
25
25
|
return { kind: 'present', rows, dropped };
|
|
26
26
|
}
|
|
27
|
-
function baselineDurableDigestThrows(raw) {
|
|
28
|
-
try {
|
|
29
|
-
durableDigestOf(raw);
|
|
30
|
-
return false;
|
|
31
|
-
}
|
|
32
|
-
catch {
|
|
33
|
-
return true;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
27
|
function durableDigestOf(rows) {
|
|
37
28
|
return rows
|
|
38
29
|
.map(r => [r.sessionId ?? '', r.taskId ?? '', r.toolCallId ?? '', r.boundCallId ?? '', r.boundInputHash ?? '', r.toolName ?? '']
|
|
@@ -214,17 +205,11 @@ export function startApprovalsFeed(client, onSnapshot, opts) {
|
|
|
214
205
|
catch {
|
|
215
206
|
durableRead = { kind: 'malformed' };
|
|
216
207
|
}
|
|
217
|
-
|
|
218
|
-
const escapes = badDurable && baselineDurableDigestThrows(rawPending);
|
|
219
|
-
if (durableRead.kind === 'malformed' || escapes) {
|
|
208
|
+
if (durableRead.kind === 'malformed') {
|
|
220
209
|
hostLog('debug', `approvalsFeed: list() body has an unreadable pending section (${via} leg) — snapshot not committed`);
|
|
221
|
-
if (!escapes)
|
|
222
|
-
stats.listErrors++;
|
|
223
210
|
noteTakeMissed(via, seq);
|
|
224
211
|
publishUnknown('unreadable_payload', via, seq);
|
|
225
|
-
|
|
226
|
-
throw new TypeError('approvalsFeed: unreadable pending section (baseline digest would have thrown)');
|
|
227
|
-
return;
|
|
212
|
+
throw new TypeError('approvalsFeed: unreadable pending section');
|
|
228
213
|
}
|
|
229
214
|
rows = durableRead.rows;
|
|
230
215
|
droppedDurable = durableRead.dropped;
|
|
@@ -246,7 +231,10 @@ export function startApprovalsFeed(client, onSnapshot, opts) {
|
|
|
246
231
|
hostLog('debug', `approvalsFeed: dropping stale poll snapshot from leg ${leg} (current ${pollLeg}) — debt untouched`);
|
|
247
232
|
return;
|
|
248
233
|
}
|
|
249
|
-
|
|
234
|
+
if (dropped > 0 || droppedDurable > 0)
|
|
235
|
+
noteTakeMissed(via, seq);
|
|
236
|
+
else
|
|
237
|
+
noteTakeLooked(seq);
|
|
250
238
|
if (seq < lastObservedSeq) {
|
|
251
239
|
hostLog('debug', `approvalsFeed: dropping out-of-order take #${seq} (newest observed #${lastObservedSeq})`);
|
|
252
240
|
return;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { CORE_MODE_ARBITRATION } from '../generated/engineFactTables.js';
|
|
2
|
+
export declare const DEPLOYMENT_LIST_ASK_CLASSES: readonly (keyof typeof CORE_MODE_ARBITRATION)[];
|
|
1
3
|
export type AskClassPairReading = {
|
|
2
4
|
readonly state: 'pair';
|
|
3
5
|
readonly askClass: string;
|
|
@@ -8,11 +8,29 @@ export type { AskAnsweredOutput } from './gateLedger.js';
|
|
|
8
8
|
export { SEMA_COLLATERAL_ABORT_KEY } from './gateLedger.js';
|
|
9
9
|
export { SEMA_DENIAL_KIND_KEY } from './gateLedger.js';
|
|
10
10
|
export type { GateDenyAttribution } from './gateLedger.js';
|
|
11
|
-
export { toAnsweredOutput, isAlreadyResolvedFailure,
|
|
11
|
+
export { toAnsweredOutput, isAlreadyResolvedFailure, nextHopBudget, MAX_GATE_HOPS, MAX_TOTAL_PARKS } from './parkResolver.js';
|
|
12
12
|
export type { HopBudget, HopRound } from './parkResolver.js';
|
|
13
|
-
export type {
|
|
13
|
+
export type { GateFailureCode } from './parkResolver.js';
|
|
14
14
|
export { GATE_FAILURE_CODES } from './hitlBridge.js';
|
|
15
15
|
export declare function bridgeAskUserQuestionGates(source: AsyncGenerator<AgentEvent>, deps: AskGateWireDeps, opts?: {
|
|
16
16
|
signal?: AbortSignal;
|
|
17
17
|
taskId?: string;
|
|
18
18
|
}): AsyncGenerator<AgentEvent>;
|
|
19
|
+
export declare const LATE_DECIDE_OUTCOMES: readonly ["accepted-not-resolved", "resumed", "expired-reaped", "settled-elsewhere", "unknown"];
|
|
20
|
+
export type LateDecideOutcome = (typeof LATE_DECIDE_OUTCOMES)[number];
|
|
21
|
+
export interface LateDecideOutcomeReading {
|
|
22
|
+
readonly kind: LateDecideOutcome;
|
|
23
|
+
readonly taskId?: string;
|
|
24
|
+
readonly executed?: 'allowed' | 'denied';
|
|
25
|
+
readonly probeWorthy?: true;
|
|
26
|
+
}
|
|
27
|
+
export type LateDecideReply = {
|
|
28
|
+
readonly ok: true;
|
|
29
|
+
readonly body: object | null | undefined;
|
|
30
|
+
} | {
|
|
31
|
+
readonly ok: false;
|
|
32
|
+
readonly error: object | null | undefined;
|
|
33
|
+
};
|
|
34
|
+
export declare function lateDecideOutcomeOf(reply: LateDecideReply, opts?: {
|
|
35
|
+
readonly lane?: 'decide' | 'respond';
|
|
36
|
+
}): LateDecideOutcomeReading;
|