@sema-agent/client-core 0.110.0 → 0.111.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 +169 -0
- package/README.md +50 -18
- package/dist/abortableSleep.d.ts +7 -0
- package/dist/abortableSleep.js +37 -0
- package/dist/adapt/arms.js +25 -4
- package/dist/adapt/toolCards.d.ts +3 -1
- package/dist/adapt/toolCards.js +4 -2
- package/dist/adapter/activeRunSelfHeal.d.ts +39 -0
- package/dist/adapter/activeRunSelfHeal.js +171 -3
- package/dist/adapter/downstream/eventToSdkMessage.js +10 -10
- package/dist/adapter/downstream/terminalToSdkResult.d.ts +2 -0
- package/dist/adapter/downstream/terminalToSdkResult.js +11 -0
- package/dist/adapter/runStream.d.ts +5 -0
- package/dist/adapter/runStream.js +15 -3
- package/dist/attachmentRoute.d.ts +20 -0
- package/dist/attachmentRoute.js +39 -0
- package/dist/attachmentsWireCaps.js +1 -1
- package/dist/builtinOutputStyles.d.ts +12 -0
- package/dist/builtinOutputStyles.js +147 -0
- package/dist/compactionStatus.d.ts +9 -0
- package/dist/compactionStatus.js +29 -5
- package/dist/controlRouter.js +2 -1
- package/dist/coreValuePorts.d.ts +39 -1
- package/dist/coreValuePorts.js +10 -0
- package/dist/displayUntrusted.d.ts +1 -0
- package/dist/displayUntrusted.js +6 -0
- package/dist/engineHealthFacts.d.ts +11 -0
- package/dist/engineHealthFacts.js +21 -0
- package/dist/engineHealthProbeVerdict.d.ts +23 -0
- package/dist/engineHealthProbeVerdict.js +115 -0
- package/dist/engineNoticeCodes.js +5 -7
- package/dist/engineRepoint.d.ts +12 -5
- package/dist/engineRepoint.js +44 -19
- package/dist/engineRowRef.d.ts +3 -0
- package/dist/engineRowRef.js +11 -1
- package/dist/engineSwapCrossing.d.ts +57 -0
- package/dist/engineSwapCrossing.js +297 -0
- package/dist/engineUnavailable.d.ts +44 -0
- package/dist/engineUnavailable.js +492 -0
- package/dist/eventLeg.js +3 -3
- package/dist/generated/sdkFactTables.d.ts +1 -1
- package/dist/generated/sdkFactTables.js +1 -0
- package/dist/generated/settingsSchemaTables.d.ts +4 -0
- package/dist/generated/settingsSchemaTables.js +1 -0
- package/dist/hitl/approvalDelivery.d.ts +1 -0
- package/dist/hitl/approvalDelivery.js +1 -1
- package/dist/hitl/approvalResolution.d.ts +1 -1
- package/dist/hitl/approvalResolution.js +2 -1
- package/dist/hitl/askGateWire.js +5 -6
- package/dist/hitl/decisionRefusal.d.ts +2 -0
- package/dist/hitl/decisionRefusal.js +7 -8
- package/dist/hitl/decisionRefusalCarrier.d.ts +3 -0
- package/dist/hitl/decisionRefusalCarrier.js +348 -0
- package/dist/hitl/decisionSend.d.ts +7 -0
- package/dist/hitl/decisionSend.js +34 -12
- package/dist/hitl/editedApprovalAcceptance.js +1 -1
- package/dist/hitl/elicitationRefusal.d.ts +4 -0
- package/dist/hitl/elicitationRefusal.js +23 -0
- package/dist/hitl/frameRouter.d.ts +2 -2
- package/dist/hitl/frameRouter.js +8 -15
- package/dist/hitl/gateIdentity.d.ts +5 -0
- package/dist/hitl/gateIdentity.js +23 -0
- package/dist/hitl/hitlBridge.d.ts +6 -0
- package/dist/hitl/hitlBridge.js +10 -4
- package/dist/hitl/hitlHostSurface.d.ts +2 -1
- package/dist/hitl/hitlHostSurface.js +7 -2
- package/dist/hitl/localAllowRedemption.d.ts +67 -0
- package/dist/hitl/localAllowRedemption.js +256 -0
- package/dist/hitl/parkResolver.js +7 -4
- package/dist/hitl/persistedRulesWire.d.ts +16 -0
- package/dist/hitl/persistedRulesWire.js +70 -0
- package/dist/hitl/planReviewWire.d.ts +3 -0
- package/dist/hitl/planReviewWire.js +23 -6
- package/dist/hitl/policyDenyCause.d.ts +1 -1
- package/dist/hitl/policyDenyCause.js +1 -1
- package/dist/hitl/resumeRunningCard.d.ts +1 -0
- package/dist/hitl/resumeRunningCard.js +1 -0
- package/dist/hitl/screenCardCarriers.d.ts +15 -0
- package/dist/hitl/screenCardCarriers.js +41 -0
- package/dist/hitl/screenDecisionCards.d.ts +98 -0
- package/dist/hitl/screenDecisionCards.js +362 -0
- package/dist/hitl/standingRows.d.ts +3 -1
- package/dist/hitl/standingRows.js +18 -0
- package/dist/hitl/toolApprovalWire.d.ts +30 -8
- package/dist/hitl/toolApprovalWire.js +264 -121
- package/dist/hooksWireCaps.js +3 -3
- package/dist/hostSettingNoticeArm.d.ts +3 -0
- package/dist/hostSettingNoticeArm.js +12 -0
- package/dist/hostTurnSettings.d.ts +3 -0
- package/dist/hostTurnSettings.js +38 -5
- package/dist/humanTurnRead.js +11 -1
- package/dist/i18n/messages.en.d.ts +129 -0
- package/dist/i18n/messages.en.js +135 -7
- package/dist/i18n/messages.zh.js +142 -6
- package/dist/i18n/translate.d.ts +3 -0
- package/dist/i18n/translate.js +78 -10
- package/dist/i18n/zh.d.ts +1 -0
- package/dist/i18n/zh.js +1 -0
- package/dist/index.d.ts +43 -17
- package/dist/index.js +30 -12
- package/dist/interactiveHalt.js +2 -1
- package/dist/interactiveInterrupt.js +20 -2
- package/dist/liveModelCatalog.js +2 -2
- package/dist/localEngineSeatReading.d.ts +2 -2
- package/dist/localEngineSeatReading.js +5 -3
- package/dist/localEngineSpawn.d.ts +0 -7
- package/dist/localEngineSpawn.js +0 -92
- package/dist/localEngineStep.d.ts +2 -2
- package/dist/localEngineStep.js +2 -0
- package/dist/mcpReconnect.js +3 -3
- package/dist/mcpWireCaps.js +1 -1
- package/dist/model/engineModelWords.d.ts +3 -0
- package/dist/model/engineModelWords.js +13 -0
- package/dist/model/subagentModelWord.d.ts +21 -2
- package/dist/model/subagentModelWord.js +100 -29
- package/dist/modelCapabilityProbe.js +3 -40
- package/dist/notifications.d.ts +19 -0
- package/dist/notifications.js +114 -12
- package/dist/ownKey.d.ts +6 -0
- package/dist/ownKey.js +31 -0
- package/dist/pendingUserRow.d.ts +4 -0
- package/dist/pendingUserRow.js +16 -0
- package/dist/permissionsDeclaration.d.ts +1 -0
- package/dist/permissionsDeclaration.js +11 -1
- package/dist/planReviewCardFacts.d.ts +3 -0
- package/dist/planReviewCardFacts.js +52 -2
- package/dist/pluginHooksWire.d.ts +9 -1
- package/dist/pluginHooksWire.js +40 -6
- package/dist/printToolResultFrame.js +4 -2
- package/dist/promptBlockedCopy.js +11 -6
- package/dist/promptSuggestionBatch.d.ts +7 -0
- package/dist/promptSuggestionBatch.js +9 -0
- package/dist/promptSuggestionsTail.d.ts +39 -0
- package/dist/promptSuggestionsTail.js +116 -0
- package/dist/request/taskRequest.js +10 -6
- package/dist/requestCoordinate.d.ts +1 -0
- package/dist/requestCoordinate.js +13 -0
- package/dist/rewindArchiveReading.js +4 -4
- package/dist/runCancelContext.d.ts +2 -1
- package/dist/runCancelContext.js +1 -0
- package/dist/runPermissionModeSwitch.js +2 -2
- package/dist/scenarioRefusal.js +11 -13
- package/dist/scenarioSkills.js +11 -6
- package/dist/seam.d.ts +16 -2
- package/dist/seam.js +10 -0
- package/dist/seatContract.d.ts +109 -9
- package/dist/seatContract.js +218 -15
- package/dist/sessionCostReading.d.ts +70 -0
- package/dist/sessionCostReading.js +150 -0
- package/dist/sessionHooksRoster.d.ts +4 -0
- package/dist/sessionHooksRoster.js +158 -0
- package/dist/sessionMemoryStatus.js +2 -2
- package/dist/sessionReadRedaction.d.ts +7 -0
- package/dist/sessionReadRedaction.js +26 -0
- package/dist/sessionSyncFileHistory.js +8 -9
- package/dist/settingsHooksSalvage.js +2 -1
- package/dist/sseIdleTriage.js +2 -1
- package/dist/storeDurabilityWord.d.ts +15 -0
- package/dist/storeDurabilityWord.js +18 -0
- package/dist/storePostureCapability.d.ts +7 -3
- package/dist/storePostureCapability.js +69 -39
- package/dist/subagent/engineSubagentResume.js +2 -2
- package/dist/subagent/engineSubagentTail.js +2 -1
- package/dist/subagentContentStore.d.ts +11 -0
- package/dist/subagentContentStore.js +28 -2
- package/dist/toolResult.d.ts +1 -0
- package/dist/toolResult.js +2 -0
- package/dist/userAttachmentEnvelope.d.ts +2 -1
- package/dist/userAttachmentEnvelope.js +10 -0
- package/dist/wireErrorTriage.js +2 -1
- package/dist/wireFailureShape.d.ts +4 -0
- package/dist/wireFailureShape.js +141 -19
- package/dist/wireRefusalCopy.d.ts +6 -5
- package/dist/wireRefusalCopy.js +49 -92
- package/docs/INTEGRATION-CLIENTS.md +2118 -17
- package/package.json +6 -2
|
@@ -4,7 +4,7 @@ import { parkGateArmOf } from './frameRouter.js';
|
|
|
4
4
|
import { seatAllowNoteCarriedOf, seatSessionRowOf } from './standingRows.js';
|
|
5
5
|
import { hostLog } from '../host.js';
|
|
6
6
|
import { trimEditedRuleText } from './editedRuleTextPrecheck.js';
|
|
7
|
-
import { appendOwnElement, guardedRead, readAskOrigin, readOwnDataNonEmptyString, readOwnDataValue, readOwnNonEmptyString } from '../ownKey.js';
|
|
7
|
+
import { appendOwnElement, guardedRead, ownSendableField, ownSnapshot, readAskOrigin, readOwnDataNonEmptyString, readOwnDataValue, readOwnNonEmptyString } from '../ownKey.js';
|
|
8
8
|
import { ownReadingSlot } from '../engineWireFor.js';
|
|
9
9
|
import { DEPLOYMENT_LIST_ASK_CLASSES, readAskClassPair } from './askClassPair.js';
|
|
10
10
|
import { approvalAgentIdOf, approvalAskReasonsOf, approvalRequestedByOf } from './approvalAskers.js';
|
|
@@ -17,7 +17,7 @@ import { CORE_SKILL_TOOL_NAME } from '../generated/toolNameTables.js';
|
|
|
17
17
|
import { CORE_ALLOW_ENTRY_INERT_REASONS, CORE_PERSISTED_RULE_MATCHES } from '../generated/engineFactTables.js';
|
|
18
18
|
import { msg, renderMessage } from '../i18n/translate.js';
|
|
19
19
|
import { sessionAllowCarried, sessionAllowEligible } from './sessionAllowRoute.js';
|
|
20
|
-
import { INTERRUPT_DENY_REASON, observeCancelByDeny, surfaceApprovalParking, surfaceAllowNoteNotCarried, surfaceRememberNotApplied, surfaceEditNotForwarded, surfaceEditRefusedOnBlindAsk, surfaceRuleArmNotSent, surfaceRuleArmRejected } from './hitlHostSurface.js';
|
|
20
|
+
import { INTERRUPT_DENY_REASON, interruptDenyLifetime, observeCancelByDeny, surfaceApprovalParking, surfaceAllowNoteNotCarried, surfaceRememberNotApplied, surfaceEditNotForwarded, surfaceEditRefusedOnBlindAsk, surfaceRuleArmNotSent, surfaceRuleArmRejected } from './hitlHostSurface.js';
|
|
21
21
|
import { approvalCallKey, liveFrameCallKey } from './gateIdentity.js';
|
|
22
22
|
import { displayUntrusted, quoteUntrustedForSentence } from '../displayUntrusted.js';
|
|
23
23
|
import { frameBindingOf } from '../frameBinding.js';
|
|
@@ -39,6 +39,7 @@ import { subagentSourceSessionOf } from './subagentSource.js';
|
|
|
39
39
|
import { isPlainRecord } from '../jsonFaithful.js';
|
|
40
40
|
import { DECIDE_WORKFLOW_REMEMBER_UNSUPPORTED } from '../engineErrorCodes.js';
|
|
41
41
|
import { readDecideReceipt } from '../decideReceipt.js';
|
|
42
|
+
import { sourceGenerationBit, sourceGenerationNow } from './screenCardCarriers.js';
|
|
42
43
|
import { RULE_OFFER_MATCHES, RULE_OFFER_BATCH_MEMBER_KINDS, RULE_OFFER_UNCOVERED_REASONS, RULE_OFFERS_ABSENCE_REASONS, ASK_ORIGINS, } from '@sema-agent/sdk';
|
|
43
44
|
export function toolNameIsFsWrite(name) {
|
|
44
45
|
const n = name.replace(/[\s_-]+/g, '').toLowerCase();
|
|
@@ -110,10 +111,9 @@ function withdrawnCardResolution(card, at, logTag) {
|
|
|
110
111
|
hostLog('debug', `${logTag}: card-withdrawn-by-host verdict=${w.rowVerdict.kind}`);
|
|
111
112
|
return { kind: 'not_sent', ...at, cause: 'withdrawn', toldBy: w.toldBy, rowVerdict: w.rowVerdict };
|
|
112
113
|
}
|
|
113
|
-
function parkRowOf(
|
|
114
|
+
function parkRowOf(row, gatedCallId) {
|
|
114
115
|
const d = parkRowDeadlineState(row, Date.now());
|
|
115
116
|
return Object.freeze({
|
|
116
|
-
taskId,
|
|
117
117
|
...(gatedCallId !== undefined && gatedCallId !== '' ? { gatedCallId } : {}),
|
|
118
118
|
...(d.kind !== 'none' ? { deadlineMs: d.deadlineMs } : {}),
|
|
119
119
|
});
|
|
@@ -225,12 +225,10 @@ const PARK_ROW_ARGS_TRUNCATED_NOTE = "this request's tool arguments were too lar
|
|
|
225
225
|
'Edits are not accepted on this card: there is no original input to edit';
|
|
226
226
|
const ARGS_REWRITTEN_NOTE = "this request's tool arguments were changed after the model made the call (for example by a hook) — " +
|
|
227
227
|
'the arguments shown here are the changed ones recorded for this approval, and they differ from the call shown in the conversation';
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
const
|
|
232
|
-
'(missing, or replaced by a size marker on the pending approval record), so the edit cannot be applied — nothing was sent; ' +
|
|
233
|
-
'approve or deny it as it is';
|
|
228
|
+
function argsFromModelCallBitsOf() {
|
|
229
|
+
return { argsUnavailable: true, wireNote: renderMessage(msg('approval.park.argsFromModelCall')) };
|
|
230
|
+
}
|
|
231
|
+
const parkEditRefusedReason = () => renderMessage(msg('approval.editRefusal.parkReason', { stem: msg('approval.editRefusal.stem') }));
|
|
234
232
|
function isParkRowInputSizeMarker(v) {
|
|
235
233
|
if (typeof v !== 'object' || v === null || Array.isArray(v))
|
|
236
234
|
return false;
|
|
@@ -472,6 +470,7 @@ async function joinDurableDecision(hold, deps, signal) {
|
|
|
472
470
|
}
|
|
473
471
|
export async function surfaceFsApprovalAndDecide(deps, taskId, argsByCall, signal, parkGatedCallId, parkToolName) {
|
|
474
472
|
const decidedByReading = decidedByReadingSnapshotOf(deps);
|
|
473
|
+
const sourceGeneration = sourceGenerationNow(deps);
|
|
475
474
|
const readMark = openDurableRead();
|
|
476
475
|
let found;
|
|
477
476
|
let held;
|
|
@@ -501,7 +500,7 @@ export async function surfaceFsApprovalAndDecide(deps, taskId, argsByCall, signa
|
|
|
501
500
|
const fetched = found;
|
|
502
501
|
return holdDurableDecision(durableHoldKey(fetched.pending, callKey), rowIdentity, signal, async (hold) => {
|
|
503
502
|
const slot = {};
|
|
504
|
-
const out = await presentFsApprovalAndDecide(deps, taskId, argsByCall, signal, fetched, decidedByReading, callKey, hold, slot);
|
|
503
|
+
const out = await presentFsApprovalAndDecide(deps, taskId, argsByCall, signal, fetched, decidedByReading, callKey, hold, slot, sourceGeneration);
|
|
505
504
|
noteCallOutcome(slot, out);
|
|
506
505
|
return out;
|
|
507
506
|
});
|
|
@@ -515,7 +514,7 @@ function parkRowHolderIdentity(row, gatedCallId) {
|
|
|
515
514
|
...(askSig !== undefined ? { askSig } : {}),
|
|
516
515
|
};
|
|
517
516
|
}
|
|
518
|
-
async function presentFsApprovalAndDecide(deps, taskId, argsByCall, signal, found, decidedByReading, callKey, hold, ledgerSlot) {
|
|
517
|
+
async function presentFsApprovalAndDecide(deps, taskId, argsByCall, signal, found, decidedByReading, callKey, hold, ledgerSlot, sourceGeneration) {
|
|
519
518
|
const { pending, gatedCallId } = found;
|
|
520
519
|
const at = { lane: 'decide', ...(gatedCallId !== undefined ? { gatedCallId } : {}) };
|
|
521
520
|
const toolName = typeof pending.toolName === 'string' ? pending.toolName : '';
|
|
@@ -548,7 +547,7 @@ async function presentFsApprovalAndDecide(deps, taskId, argsByCall, signal, foun
|
|
|
548
547
|
}
|
|
549
548
|
: {}),
|
|
550
549
|
...(argsRewritten ? { argsRewritten: true, wireNote: ARGS_REWRITTEN_NOTE } : {}),
|
|
551
|
-
...(argsFromModelCall ?
|
|
550
|
+
...(argsFromModelCall ? argsFromModelCallBitsOf() : {}),
|
|
552
551
|
...inputSourceBitOf(reading),
|
|
553
552
|
...(pending.governanceForced === true ? { governanceForced: true } : {}),
|
|
554
553
|
...(readRequiresRealApproval(pending) ? { requiresRealApproval: true } : {}),
|
|
@@ -571,8 +570,9 @@ async function presentFsApprovalAndDecide(deps, taskId, argsByCall, signal, foun
|
|
|
571
570
|
: {}),
|
|
572
571
|
allowSessionCarried: true,
|
|
573
572
|
grantBinding: readApprovalGrantBinding(pending),
|
|
574
|
-
parkRow: parkRowOf(
|
|
573
|
+
parkRow: parkRowOf(pending, gatedCallId),
|
|
575
574
|
...(typeof taskId === 'string' && taskId !== '' ? { taskId } : {}),
|
|
575
|
+
...sourceGenerationBit(sourceGeneration),
|
|
576
576
|
});
|
|
577
577
|
const editAcceptance = editedApprovalAcceptanceOf(cardRequest);
|
|
578
578
|
const card = await surfaceCallTrackedCard(gatedCallId, undefined, ledgerSlot, cardRequest);
|
|
@@ -580,7 +580,7 @@ async function presentFsApprovalAndDecide(deps, taskId, argsByCall, signal, foun
|
|
|
580
580
|
if (editAcceptance.state !== 'accepts' && card.kind === 'allow' && card.updatedInput !== undefined) {
|
|
581
581
|
hostLog('error', `liveToolApprovalWire: approval card for ${gatedCallId ?? `task ${taskId}`} returned an edited approval, but the tool input is ${rowArgsGap === 'truncated' ? 'a size marker on the pending row' : rowArgsGap === 'absent' ? 'missing from both the stream and the pending row' : 'not recorded on the pending row'} — nothing sent (the park stays pending)`);
|
|
582
582
|
surfaceEditRefusedOnBlindAsk();
|
|
583
|
-
return { kind: 'not_sent', ...at, cause: 'edit_refused', detail:
|
|
583
|
+
return { kind: 'not_sent', ...at, cause: 'edit_refused', detail: parkEditRefusedReason() };
|
|
584
584
|
}
|
|
585
585
|
const decideSpan = bridge.openDecideOperation();
|
|
586
586
|
const decideOpts = { ...(signal ? { signal } : {}), operation: decideSpan };
|
|
@@ -595,7 +595,7 @@ async function presentFsApprovalAndDecide(deps, taskId, argsByCall, signal, foun
|
|
|
595
595
|
return withdrawnCardResolution(card, at, 'liveHitlAskWire');
|
|
596
596
|
case 'aborted':
|
|
597
597
|
{
|
|
598
|
-
const cancelDeny = bridge.decideTool({ decision: 'deny', reason: INTERRUPT_DENY_REASON }, gatedCallId,
|
|
598
|
+
const cancelDeny = bridge.decideTool({ decision: 'deny', reason: INTERRUPT_DENY_REASON }, gatedCallId, { signal: interruptDenyLifetime() }, pending);
|
|
599
599
|
hold.trailing = cancelDeny;
|
|
600
600
|
observeCancelByDeny(cancelDeny, taskId);
|
|
601
601
|
}
|
|
@@ -919,14 +919,14 @@ const ANSWER_CARRIAGE_MODEL = Object.freeze({ allowNote: 'model' });
|
|
|
919
919
|
export function answerCarriage(card) {
|
|
920
920
|
return cardIsOnParkRow(card) ? ANSWER_CARRIAGE_MODEL : ANSWER_CARRIAGE_NONE;
|
|
921
921
|
}
|
|
922
|
-
function cardIsOnParkRow(card) {
|
|
922
|
+
export function cardIsOnParkRow(card) {
|
|
923
923
|
try {
|
|
924
924
|
if (typeof card !== 'object' || card === null)
|
|
925
925
|
return false;
|
|
926
926
|
const park = readOwnDataValue(card, 'parkRow');
|
|
927
927
|
if (typeof park !== 'object' || park === null || Array.isArray(park))
|
|
928
928
|
return false;
|
|
929
|
-
return readOwnDataNonEmptyString(
|
|
929
|
+
return readOwnDataNonEmptyString(card, 'taskId') !== undefined;
|
|
930
930
|
}
|
|
931
931
|
catch {
|
|
932
932
|
return false;
|
|
@@ -970,35 +970,43 @@ export function settlementAckOf(read) {
|
|
|
970
970
|
export function readToolApprovalRespondAck(v) {
|
|
971
971
|
if (v === null || typeof v !== 'object')
|
|
972
972
|
return undefined;
|
|
973
|
-
const
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
973
|
+
const s = respondAckSlotsOf(v);
|
|
974
|
+
if (s.accepted.presence === 'unreadable' || s.idempotent.presence === 'unreadable' || s.delivery.presence === 'unreadable')
|
|
975
|
+
return undefined;
|
|
976
|
+
if (slotValueOf(s.accepted) === 'parked_redeemed')
|
|
977
|
+
return readParkedRedeemedAck(s);
|
|
978
|
+
if (slotValueOf(s.idempotent) === true)
|
|
979
|
+
return s.delivery.presence === 'absent' ? readReplayedAck(s) : undefined;
|
|
980
|
+
if (slotValueOf(s.delivery) !== 'applied')
|
|
981
|
+
return undefined;
|
|
982
|
+
const approvalId = slotValueOf(s.approvalId);
|
|
983
|
+
const decision = slotValueOf(s.decision);
|
|
984
|
+
if (typeof approvalId !== 'string' || approvalId.length === 0)
|
|
985
|
+
return undefined;
|
|
986
|
+
if (!isRespondDecision(decision))
|
|
987
|
+
return undefined;
|
|
988
|
+
const rememberApplied = slotValueOf(s.rememberApplied);
|
|
989
|
+
const updatedInputForwarded = slotValueOf(s.updatedInputForwarded);
|
|
990
|
+
const rulePersisted = slotValueOf(s.rulePersisted);
|
|
991
|
+
const ruleRefusal = slotValueOf(s.ruleRefusal);
|
|
992
|
+
const noteRecorded = slotValueOf(s.noteRecorded);
|
|
993
|
+
const persistedRule = slotValueOf(s.persistedRule);
|
|
994
|
+
const persistedRules = slotValueOf(s.persistedRules);
|
|
995
|
+
const anchors = readPersistedRuleAnchors(slotValueOf(s.persistedRuleAnchors));
|
|
985
996
|
const out = {
|
|
986
|
-
approvalId
|
|
997
|
+
approvalId,
|
|
987
998
|
delivery: 'applied',
|
|
988
|
-
decision:
|
|
989
|
-
...(typeof
|
|
990
|
-
...(typeof
|
|
991
|
-
...(typeof
|
|
992
|
-
...(typeof
|
|
993
|
-
? { ruleRefusal:
|
|
999
|
+
decision: decision,
|
|
1000
|
+
...(typeof rememberApplied === 'boolean' ? { rememberApplied } : {}),
|
|
1001
|
+
...(typeof updatedInputForwarded === 'boolean' ? { updatedInputForwarded } : {}),
|
|
1002
|
+
...(typeof rulePersisted === 'boolean' ? { rulePersisted } : {}),
|
|
1003
|
+
...(typeof ruleRefusal === 'string' && ruleRefusal !== ''
|
|
1004
|
+
? { ruleRefusal: ruleRefusal }
|
|
994
1005
|
: {}),
|
|
995
|
-
...(typeof
|
|
996
|
-
...(typeof
|
|
997
|
-
...(isNonEmptyStringArray(
|
|
998
|
-
...(
|
|
999
|
-
const anchors = readPersistedRuleAnchors(o.persistedRuleAnchors);
|
|
1000
|
-
return anchors !== undefined ? { persistedRuleAnchors: anchors } : {};
|
|
1001
|
-
})(),
|
|
1006
|
+
...(typeof noteRecorded === 'boolean' ? { noteRecorded } : {}),
|
|
1007
|
+
...(typeof persistedRule === 'string' && persistedRule !== '' ? { persistedRule } : {}),
|
|
1008
|
+
...(isNonEmptyStringArray(persistedRules) ? { persistedRules: persistedRules.slice() } : {}),
|
|
1009
|
+
...(anchors !== undefined ? { persistedRuleAnchors: anchors } : {}),
|
|
1002
1010
|
};
|
|
1003
1011
|
if (out.persistedRule !== undefined && (out.persistedRules !== undefined || out.persistedRuleAnchors !== undefined)) {
|
|
1004
1012
|
delete out.persistedRule;
|
|
@@ -1019,6 +1027,35 @@ export function readToolApprovalRespondAck(v) {
|
|
|
1019
1027
|
}
|
|
1020
1028
|
return out;
|
|
1021
1029
|
}
|
|
1030
|
+
const RESPOND_ACK_SLOT_KEYS = [
|
|
1031
|
+
'accepted',
|
|
1032
|
+
'idempotent',
|
|
1033
|
+
'delivery',
|
|
1034
|
+
'approvalId',
|
|
1035
|
+
'askId',
|
|
1036
|
+
'decision',
|
|
1037
|
+
'decidedAtMs',
|
|
1038
|
+
'decisionNote',
|
|
1039
|
+
'rememberApplied',
|
|
1040
|
+
'updatedInputForwarded',
|
|
1041
|
+
'rulePersisted',
|
|
1042
|
+
'ruleRefusal',
|
|
1043
|
+
'noteRecorded',
|
|
1044
|
+
'persistedRule',
|
|
1045
|
+
'persistedRules',
|
|
1046
|
+
'persistedRuleAnchors',
|
|
1047
|
+
];
|
|
1048
|
+
function respondAckSlotsOf(o) {
|
|
1049
|
+
const slots = {};
|
|
1050
|
+
for (const key of RESPOND_ACK_SLOT_KEYS) {
|
|
1051
|
+
const slot = slotReadOf(o, key);
|
|
1052
|
+
slots[key] = slot.presence === 'present' ? { presence: 'present', value: ownSnapshot(slot.value) } : slot;
|
|
1053
|
+
}
|
|
1054
|
+
return slots;
|
|
1055
|
+
}
|
|
1056
|
+
function slotValueOf(slot) {
|
|
1057
|
+
return slot.presence === 'present' ? slot.value : undefined;
|
|
1058
|
+
}
|
|
1022
1059
|
export function readToolApprovalRespondParking(v) {
|
|
1023
1060
|
if (typeof v !== 'object' || v === null)
|
|
1024
1061
|
return undefined;
|
|
@@ -1061,6 +1098,17 @@ function replayClaimOf(raw) {
|
|
|
1061
1098
|
}
|
|
1062
1099
|
return { ...(approvalId !== undefined ? { approvalId } : {}), ...(d === 'allow' || d === 'deny' ? { decision: d } : {}), carriesDelivery };
|
|
1063
1100
|
}
|
|
1101
|
+
function idempotentSlotUnreadable(raw) {
|
|
1102
|
+
if (typeof raw !== 'object' || raw === null)
|
|
1103
|
+
return false;
|
|
1104
|
+
try {
|
|
1105
|
+
const d = Object.getOwnPropertyDescriptor(raw, 'idempotent');
|
|
1106
|
+
return d !== undefined && !Object.hasOwn(d, 'value');
|
|
1107
|
+
}
|
|
1108
|
+
catch {
|
|
1109
|
+
return true;
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1064
1112
|
function ownIdempotentTrue(raw) {
|
|
1065
1113
|
if (typeof raw !== 'object' || raw === null)
|
|
1066
1114
|
return false;
|
|
@@ -1072,65 +1120,103 @@ function ownIdempotentTrue(raw) {
|
|
|
1072
1120
|
return false;
|
|
1073
1121
|
}
|
|
1074
1122
|
}
|
|
1075
|
-
function
|
|
1076
|
-
if (
|
|
1123
|
+
export function replayVerdictFrom(raw, parsed, approvalId) {
|
|
1124
|
+
if (parsed !== undefined && isToolApprovalRespondReplayed(parsed) && parsed.approvalId === approvalId)
|
|
1125
|
+
return { kind: 'replayed', firstDecision: parsed.decision, via: 'arm' };
|
|
1126
|
+
if (!(ownIdempotentTrue(raw) || replayedFirstDecisionOf(parsed) !== undefined))
|
|
1127
|
+
return idempotentSlotUnreadable(raw) ? { kind: 'unreadable' } : { kind: 'none' };
|
|
1128
|
+
const claimed = replayClaimOf(raw);
|
|
1129
|
+
if (claimed.approvalId === approvalId && claimed.decision !== undefined && !claimed.carriesDelivery)
|
|
1130
|
+
return { kind: 'replayed', firstDecision: claimed.decision, via: 'claim' };
|
|
1131
|
+
return { kind: 'unreadable' };
|
|
1132
|
+
}
|
|
1133
|
+
const REPLAY_VERDICT_NONE = Object.freeze({ kind: 'not_replay' });
|
|
1134
|
+
const REPLAY_VERDICT_ALLOW = Object.freeze({ kind: 'replayed', firstDecision: 'allow' });
|
|
1135
|
+
const REPLAY_VERDICT_DENY = Object.freeze({ kind: 'replayed', firstDecision: 'deny' });
|
|
1136
|
+
const REPLAY_VERDICT_UNREADABLE = Object.freeze({ kind: 'unreadable' });
|
|
1137
|
+
export function toolApprovalReplayVerdictOf(raw, approvalId) {
|
|
1138
|
+
try {
|
|
1139
|
+
if (typeof approvalId !== 'string' || approvalId === '')
|
|
1140
|
+
return REPLAY_VERDICT_UNREADABLE;
|
|
1141
|
+
const v = replayVerdictFrom(raw, settlementAckOf(readToolApprovalRespondAck(raw)), approvalId);
|
|
1142
|
+
if (v.kind === 'none')
|
|
1143
|
+
return REPLAY_VERDICT_NONE;
|
|
1144
|
+
if (v.kind === 'replayed')
|
|
1145
|
+
return v.firstDecision === 'allow' ? REPLAY_VERDICT_ALLOW : REPLAY_VERDICT_DENY;
|
|
1146
|
+
return REPLAY_VERDICT_UNREADABLE;
|
|
1147
|
+
}
|
|
1148
|
+
catch {
|
|
1149
|
+
return REPLAY_VERDICT_UNREADABLE;
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
function readReplayedAck(s) {
|
|
1153
|
+
const approvalId = slotValueOf(s.approvalId);
|
|
1154
|
+
const askId = slotValueOf(s.askId);
|
|
1155
|
+
const decision = slotValueOf(s.decision);
|
|
1156
|
+
const decidedAtMs = slotValueOf(s.decidedAtMs);
|
|
1157
|
+
const decisionNote = slotValueOf(s.decisionNote);
|
|
1158
|
+
if (typeof approvalId !== 'string' || approvalId.length === 0)
|
|
1077
1159
|
return undefined;
|
|
1078
|
-
if (typeof
|
|
1160
|
+
if (typeof askId !== 'string' || askId.length === 0)
|
|
1079
1161
|
return undefined;
|
|
1080
|
-
if (
|
|
1162
|
+
if (decision !== 'allow' && decision !== 'deny')
|
|
1081
1163
|
return undefined;
|
|
1082
|
-
if (typeof
|
|
1164
|
+
if (typeof decidedAtMs !== 'number' || !Number.isFinite(decidedAtMs) || decidedAtMs < 0)
|
|
1083
1165
|
return undefined;
|
|
1084
1166
|
return {
|
|
1085
|
-
approvalId
|
|
1086
|
-
askId
|
|
1167
|
+
approvalId,
|
|
1168
|
+
askId,
|
|
1087
1169
|
idempotent: true,
|
|
1088
|
-
decision
|
|
1089
|
-
decidedAtMs
|
|
1090
|
-
...(typeof
|
|
1091
|
-
...(
|
|
1170
|
+
decision,
|
|
1171
|
+
decidedAtMs,
|
|
1172
|
+
...(typeof decisionNote === 'string' && decisionNote !== '' ? { decisionNote } : {}),
|
|
1173
|
+
...(slotValueOf(s.rememberApplied) === false ? { rememberApplied: false } : {}),
|
|
1092
1174
|
};
|
|
1093
1175
|
}
|
|
1094
|
-
function readParkedRedeemedAck(
|
|
1095
|
-
if (
|
|
1176
|
+
function readParkedRedeemedAck(s) {
|
|
1177
|
+
if (s.delivery.presence !== 'absent')
|
|
1096
1178
|
return undefined;
|
|
1097
|
-
const text = (
|
|
1098
|
-
const
|
|
1099
|
-
return
|
|
1179
|
+
const text = (slot) => {
|
|
1180
|
+
const v = slotValueOf(slot);
|
|
1181
|
+
return typeof v === 'string' && v !== '' ? v : undefined;
|
|
1100
1182
|
};
|
|
1101
|
-
const approvalId = text(
|
|
1102
|
-
const askId = text(
|
|
1183
|
+
const approvalId = text(s.approvalId);
|
|
1184
|
+
const askId = text(s.askId);
|
|
1103
1185
|
if (approvalId === undefined || askId === undefined)
|
|
1104
1186
|
return undefined;
|
|
1105
|
-
const
|
|
1106
|
-
|
|
1107
|
-
return undefined;
|
|
1108
|
-
const replay = idem.presence === 'present' && idem.value === true;
|
|
1109
|
-
const dec = slotReadOf(o, 'decision');
|
|
1187
|
+
const replay = slotValueOf(s.idempotent) === true;
|
|
1188
|
+
const dec = slotValueOf(s.decision);
|
|
1110
1189
|
let decision;
|
|
1111
1190
|
if (replay) {
|
|
1112
|
-
if (dec
|
|
1191
|
+
if (dec !== 'allow' && dec !== 'deny')
|
|
1113
1192
|
return undefined;
|
|
1114
|
-
decision = dec
|
|
1193
|
+
decision = dec;
|
|
1115
1194
|
}
|
|
1116
1195
|
else {
|
|
1117
|
-
decision =
|
|
1196
|
+
decision = typeof dec === 'string' && dec !== '' ? dec : undefined;
|
|
1118
1197
|
}
|
|
1119
|
-
const remember =
|
|
1198
|
+
const remember = slotValueOf(s.rememberApplied);
|
|
1120
1199
|
return {
|
|
1121
1200
|
approvalId,
|
|
1122
1201
|
askId,
|
|
1123
1202
|
accepted: 'parked_redeemed',
|
|
1124
1203
|
...(replay ? { idempotent: true } : {}),
|
|
1125
1204
|
...(decision !== undefined ? { decision } : {}),
|
|
1126
|
-
...(
|
|
1205
|
+
...(typeof remember === 'boolean' ? { rememberApplied: remember } : {}),
|
|
1127
1206
|
};
|
|
1128
1207
|
}
|
|
1129
1208
|
function replayedDecisionOf(first, sent, ack) {
|
|
1130
1209
|
return { kind: 'decided', lane: 'respond', decision: first, ...(ack !== undefined ? { ack } : {}), settledElsewhere: toolPermissionSettledElsewhereOf(first, sent) };
|
|
1131
1210
|
}
|
|
1132
1211
|
function isNonEmptyStringArray(v) {
|
|
1133
|
-
|
|
1212
|
+
if (!Array.isArray(v) || v.length === 0)
|
|
1213
|
+
return false;
|
|
1214
|
+
for (let i = 0; i < v.length; i++) {
|
|
1215
|
+
const x = v[i];
|
|
1216
|
+
if (typeof x !== 'string' || x === '')
|
|
1217
|
+
return false;
|
|
1218
|
+
}
|
|
1219
|
+
return true;
|
|
1134
1220
|
}
|
|
1135
1221
|
function readPersistedRuleAnchors(v) {
|
|
1136
1222
|
if (!Array.isArray(v) || v.length === 0)
|
|
@@ -1854,6 +1940,67 @@ function subagentBadgeFor(frame) {
|
|
|
1854
1940
|
name = `${name.slice(0, 31)}…`;
|
|
1855
1941
|
return { name, color: 'cyan' };
|
|
1856
1942
|
}
|
|
1943
|
+
const APPROVAL_CARD_FACT_KEYS = [
|
|
1944
|
+
'toolName', 'args', 'toolCallId', 'workerBadge', 'wireNote', 'argsUnavailable', 'inputSource', 'governanceForced', 'delegation', 'ruleOffersReadOnly',
|
|
1945
|
+
'inputHasBidi', 'allowRuleShadow', 'probeCause', 'rememberRefused', 'ruleEvidence', 'requiresRealApproval', 'ruleOffersAbsence', 'denialLimitFallback',
|
|
1946
|
+
'askClass', 'classes', 'agentId', 'askReasons', 'grantBinding', 'unreadableEvidence', 'message', 'approvalCard',
|
|
1947
|
+
'argsRewritten', 'ruleOffers', 'probeReason', 'mandated', 'mandate', 'readRootCandidate', 'origin', 'boundGrants', 'classifierNoRuling',
|
|
1948
|
+
'allowSessionCarried', 'cardPayloadUnreadable', 'cardPayloadUnreadableWhy', 'requestedBy',
|
|
1949
|
+
];
|
|
1950
|
+
const APPROVAL_CARD_HOST_KEYS = ['callKey', 'taskId', 'signal', 'expiresInMs', 'expiresAtMs', 'serverNowMs', 'receivedAtMs', 'sourceGeneration'];
|
|
1951
|
+
const _pinCardRequestPartition = [true, true, true, true, true];
|
|
1952
|
+
void _pinCardRequestPartition;
|
|
1953
|
+
const FACT_KEY_SET = new Set(APPROVAL_CARD_FACT_KEYS);
|
|
1954
|
+
const HOST_KEY_SET = new Set(APPROVAL_CARD_HOST_KEYS);
|
|
1955
|
+
function hostBitInDomain(key, v) {
|
|
1956
|
+
switch (key) {
|
|
1957
|
+
case 'callKey':
|
|
1958
|
+
case 'taskId':
|
|
1959
|
+
return typeof v === 'string' && v !== '';
|
|
1960
|
+
case 'signal':
|
|
1961
|
+
return typeof v === 'object' && v !== null;
|
|
1962
|
+
case 'sourceGeneration':
|
|
1963
|
+
return typeof v === 'number' && Number.isFinite(v);
|
|
1964
|
+
default:
|
|
1965
|
+
return typeof v === 'number' && Number.isFinite(v) && v >= 0;
|
|
1966
|
+
}
|
|
1967
|
+
}
|
|
1968
|
+
function closedKeysListing(from) {
|
|
1969
|
+
try {
|
|
1970
|
+
return { kind: 'listed', keys: Reflect.ownKeys(from) };
|
|
1971
|
+
}
|
|
1972
|
+
catch {
|
|
1973
|
+
return { kind: 'unreadable' };
|
|
1974
|
+
}
|
|
1975
|
+
}
|
|
1976
|
+
function copyClosedKeys(into, from, keys, admit) {
|
|
1977
|
+
const listed = closedKeysListing(from);
|
|
1978
|
+
if (listed.kind === 'unreadable')
|
|
1979
|
+
return;
|
|
1980
|
+
for (let i = 0; i < listed.keys.length; i += 1) {
|
|
1981
|
+
const k = listed.keys[i];
|
|
1982
|
+
if (typeof k !== 'string' || !keys.has(k))
|
|
1983
|
+
continue;
|
|
1984
|
+
const v = guardedRead(() => ownSendableField(from, k));
|
|
1985
|
+
if (v === undefined || (admit !== undefined && !admit(k, v)))
|
|
1986
|
+
continue;
|
|
1987
|
+
into[k] = v;
|
|
1988
|
+
}
|
|
1989
|
+
}
|
|
1990
|
+
function cardRequestOf(facts, host) {
|
|
1991
|
+
const out = {};
|
|
1992
|
+
copyClosedKeys(out, facts, FACT_KEY_SET);
|
|
1993
|
+
copyClosedKeys(out, host, HOST_KEY_SET, (k, v) => hostBitInDomain(k, v));
|
|
1994
|
+
return out;
|
|
1995
|
+
}
|
|
1996
|
+
export function approvalCardRequestOf(facts, host) {
|
|
1997
|
+
if (typeof facts !== 'object' || facts === null || typeof host !== 'object' || host === null)
|
|
1998
|
+
return undefined;
|
|
1999
|
+
const out = cardRequestOf(facts, host);
|
|
2000
|
+
if (typeof out.toolName !== 'string' || typeof out.args !== 'object' || out.args === null || typeof out.callKey !== 'string')
|
|
2001
|
+
return undefined;
|
|
2002
|
+
return out;
|
|
2003
|
+
}
|
|
1857
2004
|
function v1Bit(stamp) {
|
|
1858
2005
|
try {
|
|
1859
2006
|
stamp();
|
|
@@ -1899,7 +2046,7 @@ function cardFactsOf(carrier, leg, opts, liveFacts, approvalId, payloadWhy) {
|
|
|
1899
2046
|
if (reading.from === 'stream' && typeof reading.args === 'object' && reading.args !== null) {
|
|
1900
2047
|
if (blind)
|
|
1901
2048
|
return { args: reading.args, argsUnavailable: true };
|
|
1902
|
-
return { args: reading.args,
|
|
2049
|
+
return { args: reading.args, ...argsFromModelCallBitsOf(), ...inputSourceBitOf(reading) };
|
|
1903
2050
|
}
|
|
1904
2051
|
const omitted = c.argsOmitted === true || reading.shape === 'size_marker';
|
|
1905
2052
|
const fallback = argsFallbackOf(c.message, omitted);
|
|
@@ -2117,7 +2264,9 @@ export async function surfaceApprovalFrameWithId(frame, approvalId, respond, str
|
|
|
2117
2264
|
return approvalIdUnreadableRefusal();
|
|
2118
2265
|
const carriers = openingFrameCarriersOf(frame);
|
|
2119
2266
|
const liveRun = liveCardRunOf(frame, run);
|
|
2120
|
-
const
|
|
2267
|
+
const sourceGenerationRaw = guardedRead(() => readOwnDataValue(run, 'sourceGeneration'));
|
|
2268
|
+
const sourceGeneration = typeof sourceGenerationRaw === 'number' && Number.isFinite(sourceGenerationRaw) ? sourceGenerationRaw : undefined;
|
|
2269
|
+
const entry = { frame, carriers, approvalId, identity: liveCardIdentityOf(approvalId, carriers, liveRun), respond, streamArgs, signal, lane, receivedAtMs, sourceGeneration };
|
|
2121
2270
|
return enterLiveCard(entry);
|
|
2122
2271
|
}
|
|
2123
2272
|
function openingFrameCarriersOf(frame) {
|
|
@@ -2143,7 +2292,7 @@ function enterLiveCard(e) {
|
|
|
2143
2292
|
return joinOtherLaneHolder(e, other);
|
|
2144
2293
|
return holdLiveCard(e.identity, signal, async (hold) => {
|
|
2145
2294
|
const slot = {};
|
|
2146
|
-
const out = await presentToolApprovalFrameAndRespond(e.frame, e.carriers, approvalId, e.respond, e.streamArgs, signal, e.lane, hold, slot, e.receivedAtMs, e.identity.taskId);
|
|
2295
|
+
const out = await presentToolApprovalFrameAndRespond(e.frame, e.carriers, approvalId, e.respond, e.streamArgs, signal, e.lane, hold, slot, e.receivedAtMs, e.identity.taskId, e.sourceGeneration);
|
|
2147
2296
|
noteCallOutcome(slot, out);
|
|
2148
2297
|
return out;
|
|
2149
2298
|
});
|
|
@@ -2227,7 +2376,7 @@ function readApprovalCardClaimSignal(v) {
|
|
|
2227
2376
|
export function claimApprovalCard(identity, options) {
|
|
2228
2377
|
return claimApprovalCardFor(readApprovalHolderIdentity(identity), readApprovalCardClaimSignal(options));
|
|
2229
2378
|
}
|
|
2230
|
-
async function presentToolApprovalFrameAndRespond(frame, carriers, approvalId, respond, streamArgs, signal, lane, hold, ledgerSlot, receivedAtMs, cardTaskId) {
|
|
2379
|
+
async function presentToolApprovalFrameAndRespond(frame, carriers, approvalId, respond, streamArgs, signal, lane, hold, ledgerSlot, receivedAtMs, cardTaskId, sourceGeneration) {
|
|
2231
2380
|
const bodyToolCallId = carriers.body.toolCallId;
|
|
2232
2381
|
const frameToolCallId = typeof bodyToolCallId === 'string' && bodyToolCallId !== '' ? bodyToolCallId : undefined;
|
|
2233
2382
|
const decidedByReading = decidedByReadingSnapshotOf(lane);
|
|
@@ -2235,16 +2384,16 @@ async function presentToolApprovalFrameAndRespond(frame, carriers, approvalId, r
|
|
|
2235
2384
|
const argsNotRealInput = facts.argsUnavailable === true;
|
|
2236
2385
|
const editAcceptance = editedApprovalAcceptanceOf(facts);
|
|
2237
2386
|
const ruleOffers = facts.ruleOffers;
|
|
2238
|
-
if (argsNotRealInput && lane?.argsUnavailable !== true && facts.wireNote !== undefined) {
|
|
2387
|
+
if (argsNotRealInput && lane?.argsUnavailable !== true && facts.wireNote !== undefined && facts.inputSource !== 'stream') {
|
|
2239
2388
|
hostLog('debug', `liveToolApprovalWire: frame ${approvalId} args omitted (>16KiB wire cap) — card falls back to ${Object.hasOwn(facts.args, 'file_path') ? 'the message-derived path' : 'an empty input (no path could be derived from the message)'}`);
|
|
2240
2389
|
}
|
|
2241
|
-
const card = await surfaceCallTrackedCard(frameToolCallId, approvalId, ledgerSlot, {
|
|
2242
|
-
...facts,
|
|
2390
|
+
const card = await surfaceCallTrackedCard(frameToolCallId, approvalId, ledgerSlot, cardRequestOf(facts, {
|
|
2243
2391
|
callKey: liveFrameCallKey(approvalId),
|
|
2244
2392
|
...(cardTaskId !== undefined ? { taskId: cardTaskId } : {}),
|
|
2393
|
+
...sourceGenerationBit(sourceGeneration),
|
|
2245
2394
|
signal: hold.cardSignal,
|
|
2246
2395
|
...approvalWindowKeysOf(frame, { windowIsCurrent: lane?.windowIsCurrent === true, receivedAtMs, ...(carriers.leg === 'generic' ? { unknownShape: true } : {}) }),
|
|
2247
|
-
});
|
|
2396
|
+
}));
|
|
2248
2397
|
if (hold.superseded !== undefined) {
|
|
2249
2398
|
hostLog('debug', `liveToolApprovalWire: ${approvalId} was settled by the engine while its card was up${hold.superseded.parked ? ' (parked)' : ''} — card withdrawn; ` +
|
|
2250
2399
|
`the card came back ${card.kind}; nothing sent`);
|
|
@@ -2263,19 +2412,27 @@ async function presentToolApprovalFrameAndRespond(frame, carriers, approvalId, r
|
|
|
2263
2412
|
hostLog('debug', `liveToolApprovalWire: ${approvalId} card retracted without a decision${card.reason ? ` (${card.reason})` : ''} — nothing sent`);
|
|
2264
2413
|
return { kind: 'not_sent', lane: 'respond', cause: 'retracted' };
|
|
2265
2414
|
}
|
|
2415
|
+
const respondParkingOf = (body) => {
|
|
2416
|
+
const p = readToolApprovalRespondParking(body);
|
|
2417
|
+
return p?.kind === 'parking' ? p.view : undefined;
|
|
2418
|
+
};
|
|
2419
|
+
const deliverOnThisCard = (d, body, carrySignal, deliverySignal, ladder, onLadderStep) => deliverApprovalDecision({
|
|
2420
|
+
approvalId,
|
|
2421
|
+
body,
|
|
2422
|
+
send: (o, sig) => respond(approvalId, d, carrySignal && sig !== undefined ? { ...o, signal: sig } : o),
|
|
2423
|
+
signal: deliverySignal,
|
|
2424
|
+
tally: newSendTally(),
|
|
2425
|
+
ladder,
|
|
2426
|
+
...(onLadderStep !== undefined ? { onLadderStep } : {}),
|
|
2427
|
+
parkingOf: respondParkingOf,
|
|
2428
|
+
});
|
|
2266
2429
|
if (card.kind === 'aborted') {
|
|
2267
2430
|
enterLiveRespondPhase(hold);
|
|
2268
2431
|
const interruptOpts = lane?.approvalDecisionNoteCapable === true ? { note: INTERRUPT_DENY_REASON } : {};
|
|
2269
|
-
|
|
2270
|
-
try {
|
|
2271
|
-
interruptDeny = Promise.resolve(respond(approvalId, 'deny', interruptOpts));
|
|
2272
|
-
}
|
|
2273
|
-
catch (e) {
|
|
2274
|
-
interruptDeny = Promise.reject(e);
|
|
2275
|
-
}
|
|
2432
|
+
const interruptDeny = deliverOnThisCard('deny', interruptOpts, true, interruptDenyLifetime(), { lastCarried: false, dropped: false, renamed: false }).then((delivery) => (delivery.kind === 'thrown' ? Promise.reject(delivery.error) : delivery.raw));
|
|
2276
2433
|
hold.trailing = interruptDeny.then((body) => readToolApprovalRespondParking(body) === undefined, () => false);
|
|
2277
2434
|
observeCancelByDeny(interruptDeny, approvalId);
|
|
2278
|
-
hostLog('debug', `liveToolApprovalWire: ${approvalId} card aborted —
|
|
2435
|
+
hostLog('debug', `liveToolApprovalWire: ${approvalId} card aborted — a tool-level deny issued to settle the pending ask (bounded retry; at most one is accepted)`);
|
|
2279
2436
|
return { kind: 'unsettled', lane: 'respond', cause: 'interrupted' };
|
|
2280
2437
|
}
|
|
2281
2438
|
enterLiveRespondPhase(hold);
|
|
@@ -2398,30 +2555,18 @@ async function presentToolApprovalFrameAndRespond(frame, carriers, approvalId, r
|
|
|
2398
2555
|
if (basePayload !== undefined)
|
|
2399
2556
|
emitAnswerCommitted(liveFrameCallKey(approvalId), 'respond', answerSnapshot, basePayload);
|
|
2400
2557
|
try {
|
|
2401
|
-
const delivery = await
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
hostLog('debug', step === 'renamed'
|
|
2410
|
-
? `liveToolApprovalWire: respond(deny) for ${approvalId} was refused because the settlement note was sent under a name ` +
|
|
2411
|
-
'this engine has retired — re-sending the SAME decision exactly once with that one key renamed to the name the refusal points to ' +
|
|
2558
|
+
const delivery = await deliverOnThisCard(decision, respondOpts, !signalPreAborted, signal, ladder, (step) => {
|
|
2559
|
+
hostLog('debug', step === 'renamed'
|
|
2560
|
+
? `liveToolApprovalWire: respond(deny) for ${approvalId} was refused because the settlement note was sent under a name ` +
|
|
2561
|
+
'this engine has retired — re-sending the SAME decision exactly once with that one key renamed to the name the refusal points to ' +
|
|
2562
|
+
'(the refusal happened before the approval was judged, so nothing was consumed and this is a re-delivery, not a second act)'
|
|
2563
|
+
: step === 'dropped'
|
|
2564
|
+
? `liveToolApprovalWire: respond(deny) for ${approvalId} was refused because the settlement note is not part of ` +
|
|
2565
|
+
'what this deployment signs — re-sending the SAME decision exactly once with that one key removed ' +
|
|
2412
2566
|
'(the refusal happened before the approval was judged, so nothing was consumed and this is a re-delivery, not a second act)'
|
|
2413
|
-
:
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
'(the refusal happened before the approval was judged, so nothing was consumed and this is a re-delivery, not a second act)'
|
|
2417
|
-
: `liveToolApprovalWire: respond(deny) for ${approvalId} was refused again because the settlement note is not part of ` +
|
|
2418
|
-
'what this deployment signs — re-sending the SAME decision exactly once more with that key removed ' +
|
|
2419
|
-
'(still before the approval was judged)');
|
|
2420
|
-
},
|
|
2421
|
-
parkingOf: (body) => {
|
|
2422
|
-
const p = readToolApprovalRespondParking(body);
|
|
2423
|
-
return p?.kind === 'parking' ? p.view : undefined;
|
|
2424
|
-
},
|
|
2567
|
+
: `liveToolApprovalWire: respond(deny) for ${approvalId} was refused again because the settlement note is not part of ` +
|
|
2568
|
+
'what this deployment signs — re-sending the SAME decision exactly once more with that key removed ' +
|
|
2569
|
+
'(still before the approval was judged)');
|
|
2425
2570
|
});
|
|
2426
2571
|
if (delivery.kind === 'thrown') {
|
|
2427
2572
|
deliveryFailure = delivery;
|
|
@@ -2450,15 +2595,13 @@ async function presentToolApprovalFrameAndRespond(frame, carriers, approvalId, r
|
|
|
2450
2595
|
return { kind: 'unsettled', lane: 'respond', cause: 'unreadable' };
|
|
2451
2596
|
}
|
|
2452
2597
|
const parsed = settlementAckOf(readToolApprovalRespondAck(raw));
|
|
2453
|
-
const
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
return replayedDecisionOf(claimed.decision, decision, parsed !== undefined && isToolApprovalRespondParkedRedeemed(parsed) && parsed.approvalId === approvalId ? parsed : undefined);
|
|
2461
|
-
}
|
|
2598
|
+
const replayVerdict = replayVerdictFrom(raw, parsed, approvalId);
|
|
2599
|
+
if (replayVerdict.kind === 'replayed' && replayVerdict.via === 'claim') {
|
|
2600
|
+
hostLog('debug', `liveToolApprovalWire: respond(${decision}) for ${approvalId} answered with a replay (body not in the full replay shape) — the approval was already decided ` +
|
|
2601
|
+
`(${replayVerdict.firstDecision}); this answer was not delivered, reporting the earlier decision`);
|
|
2602
|
+
return replayedDecisionOf(replayVerdict.firstDecision, decision, parsed !== undefined && isToolApprovalRespondParkedRedeemed(parsed) && parsed.approvalId === approvalId ? parsed : undefined);
|
|
2603
|
+
}
|
|
2604
|
+
if (replayVerdict.kind === 'unreadable') {
|
|
2462
2605
|
hostLog('error', `liveToolApprovalWire: respond(${decision}) for ${approvalId} answered with a replay of an earlier decision that cannot be read or names another approval — ` +
|
|
2463
2606
|
'reporting the answer as NOT settled (never as the decision this client sent); not re-sent');
|
|
2464
2607
|
return { kind: 'unsettled', lane: 'respond', cause: 'unreadable' };
|
package/dist/hooksWireCaps.js
CHANGED
|
@@ -9,7 +9,7 @@ import { admittedLayers, layerAdmissionWord } from './settingsLayerAdmission.js'
|
|
|
9
9
|
import { guardedRead, readOwnDataValue } from './ownKey.js';
|
|
10
10
|
import { HOOK_SETTINGS_SOURCE_TEXT, hooksSalvageMaskOf, salvageSettingsHooksEntries, settingsHooksSalvageNotice } from './settingsHooksSalvage.js';
|
|
11
11
|
import { submissionOriginOf } from './request/submissionIdentity.js';
|
|
12
|
-
import { createSettingsHookJudge, decidePluginHooks, decideSessionHooks, dedupeSettingsHookGroups, filterSettingsHookGroups, hooksWirePlanShapeOf, isEngineFiredHookEvent, occupancyOf, } from './pluginHooksWire.js';
|
|
12
|
+
import { createSettingsHookJudge, decidePluginHooks, decideSessionHooks, dedupeSettingsHookGroups, filterSettingsHookGroups, hooksWirePlanShapeOf, hookEntryTypeWordOf, isEngineFiredHookEvent, occupancyOf, } from './pluginHooksWire.js';
|
|
13
13
|
import { MAX_HOOK_NOTICE_TEXT_CHARS } from './notifications.js';
|
|
14
14
|
import { applyHttpHookPolicy, httpHookAdmittedSources, readHttpHookPolicy, wireHasHttpEntry } from './httpHookPolicy.js';
|
|
15
15
|
import { goalStopHookMatcher, __resetGoalStopHookForTests } from './goalStopHook.js';
|
|
@@ -316,8 +316,8 @@ function closedDropRowsOf(source, doc, reason) {
|
|
|
316
316
|
const entries = readOwnDataValue(group, 'hooks');
|
|
317
317
|
if (!Array.isArray(entries))
|
|
318
318
|
return;
|
|
319
|
-
entries.forEach((
|
|
320
|
-
rows.push({ source, event, groupIndex, hookIndex, reason, notRun: true });
|
|
319
|
+
entries.forEach((entry, hookIndex) => {
|
|
320
|
+
rows.push({ source, event, groupIndex, hookIndex, ...hookEntryTypeWordOf(entry), reason, notRun: true });
|
|
321
321
|
});
|
|
322
322
|
});
|
|
323
323
|
}
|