@sema-agent/client-core 0.109.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 +342 -0
- package/README.md +88 -32
- package/dist/abortableSleep.d.ts +7 -0
- package/dist/abortableSleep.js +37 -0
- package/dist/adapt/arms.js +45 -11
- 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 +20 -15
- 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/declared/supportFloorDeclared.js +1 -1
- package/dist/displayUntrusted.d.ts +1 -0
- package/dist/displayUntrusted.js +138 -14
- package/dist/engineErrorCodes.d.ts +3 -0
- package/dist/engineErrorCodes.js +3 -0
- package/dist/engineHealthFacts.d.ts +20 -0
- package/dist/engineHealthFacts.js +42 -1
- package/dist/engineHealthProbeVerdict.d.ts +23 -0
- package/dist/engineHealthProbeVerdict.js +115 -0
- package/dist/engineInlineTaskStats.d.ts +4 -3
- package/dist/engineInlineTaskStats.js +18 -2
- package/dist/engineNoticeCodes.d.ts +10 -0
- package/dist/engineNoticeCodes.js +36 -6
- package/dist/engineRepoint.d.ts +147 -0
- package/dist/engineRepoint.js +310 -0
- package/dist/engineRowRef.d.ts +3 -0
- package/dist/engineRowRef.js +13 -1
- package/dist/engineSessionMessages.d.ts +2 -1
- package/dist/engineSessionMessages.js +5 -0
- 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/errorSupplementRoles.js +2 -1
- package/dist/eventLeg.js +3 -3
- package/dist/fleet/fleetProjection.js +3 -2
- package/dist/generated/engineFactTables.d.ts +2 -0
- package/dist/generated/engineFactTables.js +12 -0
- package/dist/generated/sdkFactTables.d.ts +2 -1
- package/dist/generated/sdkFactTables.js +5 -0
- package/dist/generated/settingsSchemaTables.d.ts +4 -0
- package/dist/generated/settingsSchemaTables.js +1 -0
- package/dist/hitl/approvalAskers.d.ts +6 -0
- package/dist/hitl/approvalAskers.js +30 -0
- package/dist/hitl/approvalCardReasons.js +6 -3
- package/dist/hitl/approvalDelivery.d.ts +1 -0
- package/dist/hitl/approvalDelivery.js +1 -1
- package/dist/hitl/approvalRequestFrameReading.d.ts +7 -0
- package/dist/hitl/approvalRequestFrameReading.js +11 -0
- package/dist/hitl/approvalResolution.d.ts +9 -2
- package/dist/hitl/approvalResolution.js +6 -1
- package/dist/hitl/askGateWire.js +5 -8
- package/dist/hitl/automaticAnswerVerdict.js +2 -2
- package/dist/hitl/decisionConflict.js +6 -3
- package/dist/hitl/decisionRefusal.d.ts +2 -0
- package/dist/hitl/decisionRefusal.js +8 -8
- package/dist/hitl/decisionRefusalCarrier.d.ts +3 -0
- package/dist/hitl/decisionRefusalCarrier.js +348 -0
- package/dist/hitl/decisionSend.d.ts +10 -0
- package/dist/hitl/decisionSend.js +57 -17
- package/dist/hitl/editedApprovalAcceptance.d.ts +25 -0
- package/dist/hitl/editedApprovalAcceptance.js +26 -0
- 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 +12 -33
- package/dist/hitl/gateIdentity.d.ts +5 -0
- package/dist/hitl/gateIdentity.js +23 -0
- package/dist/hitl/gateLedger.d.ts +0 -4
- package/dist/hitl/gateLedger.js +0 -19
- package/dist/hitl/hitlBridge.d.ts +7 -0
- package/dist/hitl/hitlBridge.js +14 -8
- package/dist/hitl/hitlHostSurface.d.ts +3 -1
- package/dist/hitl/hitlHostSurface.js +14 -4
- package/dist/hitl/hostWithdrawal.d.ts +15 -0
- package/dist/hitl/hostWithdrawal.js +38 -0
- package/dist/hitl/localAllowRedemption.d.ts +67 -0
- package/dist/hitl/localAllowRedemption.js +256 -0
- package/dist/hitl/parkResolver.js +32 -13
- package/dist/hitl/persistedRulesWire.d.ts +16 -0
- package/dist/hitl/persistedRulesWire.js +72 -2
- package/dist/hitl/planReviewWire.d.ts +3 -0
- package/dist/hitl/planReviewWire.js +37 -10
- 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/sessionPolicyWire.js +6 -4
- package/dist/hitl/standingRows.d.ts +4 -1
- package/dist/hitl/standingRows.js +33 -1
- package/dist/hitl/toolApprovalWire.d.ts +64 -15
- package/dist/hitl/toolApprovalWire.js +470 -125
- package/dist/hooksWireCaps.js +31 -1
- package/dist/hostSettingNoticeArm.d.ts +3 -0
- package/dist/hostSettingNoticeArm.js +12 -0
- package/dist/hostTurnSettings.d.ts +13 -4
- package/dist/hostTurnSettings.js +150 -10
- package/dist/humanTurnRead.js +11 -1
- package/dist/i18n/messages.en.d.ts +212 -0
- package/dist/i18n/messages.en.js +217 -5
- package/dist/i18n/messages.zh.js +235 -5
- 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 +56 -16
- package/dist/index.js +40 -12
- package/dist/inheritEnvCapability.js +2 -0
- package/dist/inputAuthor.d.ts +16 -0
- package/dist/inputAuthor.js +44 -0
- package/dist/interactiveHalt.js +2 -1
- package/dist/interactiveInterrupt.js +20 -2
- package/dist/interruptRefusalNote.d.ts +2 -0
- package/dist/interruptRefusalNote.js +17 -0
- package/dist/liveModelCatalog.d.ts +2 -0
- package/dist/liveModelCatalog.js +23 -9
- package/dist/liveQuestionStore.d.ts +4 -1
- package/dist/liveQuestionStore.js +12 -3
- 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/mcpEngineLeg.d.ts +3 -0
- package/dist/mcpEngineLeg.js +38 -1
- package/dist/mcpPanel.js +2 -0
- package/dist/mcpReconnect.d.ts +9 -1
- package/dist/mcpReconnect.js +124 -19
- 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 +7 -43
- package/dist/modsFace.d.ts +8 -1
- package/dist/modsFace.js +27 -0
- package/dist/notifications.d.ts +36 -6
- package/dist/notifications.js +170 -20
- package/dist/ownKey.d.ts +6 -5
- package/dist/ownKey.js +31 -7
- package/dist/peerFrames.d.ts +40 -2
- package/dist/peerFrames.js +158 -3
- 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 +10 -1
- package/dist/pluginHooksWire.js +96 -7
- 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/replayBody.js +10 -2
- package/dist/request/taskRequest.d.ts +5 -0
- package/dist/request/taskRequest.js +142 -21
- package/dist/requestCoordinate.d.ts +1 -0
- package/dist/requestCoordinate.js +13 -0
- package/dist/resumeRefusalCopy.d.ts +1 -3
- package/dist/resumeRefusalCopy.js +2 -1
- package/dist/retryStatus.d.ts +2 -2
- package/dist/retryStatus.js +2 -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 +27 -2
- package/dist/seam.js +17 -1
- package/dist/seatContract.d.ts +189 -12
- package/dist/seatContract.js +401 -9
- package/dist/sessionBackground.js +2 -1
- package/dist/sessionBackgroundHandoff.js +2 -1
- package/dist/sessionCostReading.d.ts +70 -0
- package/dist/sessionCostReading.js +150 -0
- package/dist/sessionEngine.d.ts +2 -0
- package/dist/sessionEngine.js +111 -0
- package/dist/sessionHooksRoster.d.ts +4 -0
- package/dist/sessionHooksRoster.js +158 -0
- package/dist/sessionMemoryStatus.d.ts +2 -1
- package/dist/sessionMemoryStatus.js +2 -2
- package/dist/sessionReadRedaction.d.ts +7 -0
- package/dist/sessionReadRedaction.js +26 -0
- package/dist/sessionSyncFileHistory.d.ts +4 -0
- package/dist/sessionSyncFileHistory.js +27 -0
- package/dist/settingsHooksSalvage.js +2 -1
- package/dist/sseIdleTriage.d.ts +13 -1
- package/dist/sseIdleTriage.js +25 -6
- 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 +8 -1
- package/dist/subagentContentStore.d.ts +11 -0
- package/dist/subagentContentStore.js +28 -2
- package/dist/terminalStatuses.d.ts +1 -0
- package/dist/terminalStatuses.js +4 -1
- package/dist/toolResult.d.ts +1 -0
- package/dist/toolResult.js +2 -0
- package/dist/turnFailurePresentation.js +9 -2
- package/dist/typePins.d.ts +11 -0
- package/dist/usageAnalytics.d.ts +17 -0
- package/dist/usageAnalytics.js +44 -2
- package/dist/userAttachmentEnvelope.d.ts +2 -1
- package/dist/userAttachmentEnvelope.js +10 -0
- package/dist/wireErrorTriage.js +2 -1
- package/dist/wireFailureShape.d.ts +6 -5
- package/dist/wireFailureShape.js +150 -38
- package/dist/wireRefusalCopy.d.ts +16 -5
- package/dist/wireRefusalCopy.js +119 -86
- package/docs/INTEGRATION-CLIENTS.md +4228 -21
- package/package.json +7 -3
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { APPROVAL_CARD_PORT_KEY_MISMATCH_REASON, DEFAULT_DENY_REASON, HitlBridge, NO_APPROVAL_CARD_PORT_REASON, denyReasonForWire, findPendingForTask, readWireErrorCodeReading, } from './hitlBridge.js';
|
|
2
2
|
import { askParkRowArm } from './askParkRowRouting.js';
|
|
3
3
|
import { parkGateArmOf } from './frameRouter.js';
|
|
4
|
-
import { seatSessionRowOf } from './standingRows.js';
|
|
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
|
-
import { approvalAgentIdOf, approvalAskReasonsOf } from './approvalAskers.js';
|
|
10
|
+
import { approvalAgentIdOf, approvalAskReasonsOf, approvalRequestedByOf } from './approvalAskers.js';
|
|
11
11
|
import { invokeHostCallbackIsolated } from '../hostCallbackGuard.js';
|
|
12
12
|
import { approvalWindowKeysOf, readApprovalCardWord, readRequiresRealApproval } from './approvalCardReading.js';
|
|
13
13
|
import { readAllowRuleShadowFromWire, retiredAllowRuleShadowKeyPresent, RETIRED_SHADOW_EVIDENCE_LABEL } from './allowRuleShadow.js';
|
|
@@ -17,26 +17,29 @@ 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, 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';
|
|
24
24
|
import { carriesAttributionKey, deliverWithAttributionLadder } from './attributionLadder.js';
|
|
25
25
|
import { deliverApprovalDecision, newSendTally } from './approvalDelivery.js';
|
|
26
26
|
import { approvalDecisionHolds, approvalHoldFor, awaitApprovalHolder, claimApprovalCardFor, enterLiveRespondPhase, holdLiveCard, joinLiveCard, liveCardHoldOf, clearSettledApprovals, noteHolderSettledApproval, settledApprovalOf, settledForDurableLane, settledLiveCardOutcome } from './approvalHolds.js';
|
|
27
|
-
import { directFailureVerdictOf, directSafetyStopOf, joinedResolution, resolutionOfDecisionFailure } from './approvalResolution.js';
|
|
27
|
+
import { directFailureVerdictOf, directSafetyStopOf, joinedResolution, resolutionOfDecisionFailure, toolPermissionSettledElsewhereOf } from './approvalResolution.js';
|
|
28
|
+
import { hostWithdrawalOf } from './hostWithdrawal.js';
|
|
28
29
|
import { parkRowDeadlineState } from './parkExpiryJudgements.js';
|
|
29
30
|
import { isApprovalMandateWord } from '../gateVocabulary.js';
|
|
30
31
|
import { approvalDecidedByAdmitted } from '../approvalDecidedByCapability.js';
|
|
31
32
|
import { decideFailureNote } from '../decideFailureNote.js';
|
|
33
|
+
import { editedApprovalAcceptanceOf } from './editedApprovalAcceptance.js';
|
|
32
34
|
import { readPolicyDenyCause } from './policyDenyCause.js';
|
|
33
|
-
import { inValueOf, slotPresenceOf, wireFailureTextsOf } from '../wireFailureShape.js';
|
|
35
|
+
import { inValueOf, slotPresenceOf, slotReadOf, wireFailureTextsOf } from '../wireFailureShape.js';
|
|
34
36
|
import { APPROVAL_LIVE_FACE_KEYS, approvalLiveFaceOf, hasOwnStrictTrue } from './approvalLiveFace.js';
|
|
35
|
-
import { approvalFrameUnreadableWhyOf, approvalRequestFrameReadingThrowing, } from './approvalRequestFrameReading.js';
|
|
37
|
+
import { approvalFrameUnreadableWhyOf, approvalRequestFrameReadingThrowing, cardPayloadReadingOf, } from './approvalRequestFrameReading.js';
|
|
36
38
|
import { subagentSourceSessionOf } from './subagentSource.js';
|
|
37
39
|
import { isPlainRecord } from '../jsonFaithful.js';
|
|
38
40
|
import { DECIDE_WORKFLOW_REMEMBER_UNSUPPORTED } from '../engineErrorCodes.js';
|
|
39
41
|
import { readDecideReceipt } from '../decideReceipt.js';
|
|
42
|
+
import { sourceGenerationBit, sourceGenerationNow } from './screenCardCarriers.js';
|
|
40
43
|
import { RULE_OFFER_MATCHES, RULE_OFFER_BATCH_MEMBER_KINDS, RULE_OFFER_UNCOVERED_REASONS, RULE_OFFERS_ABSENCE_REASONS, ASK_ORIGINS, } from '@sema-agent/sdk';
|
|
41
44
|
export function toolNameIsFsWrite(name) {
|
|
42
45
|
const n = name.replace(/[\s_-]+/g, '').toLowerCase();
|
|
@@ -98,10 +101,19 @@ export function readApprovalDenySettledBy(decision) {
|
|
|
98
101
|
: undefined;
|
|
99
102
|
}
|
|
100
103
|
export const RETRACTED_CARD_DECISION_KIND = 'retracted';
|
|
101
|
-
|
|
104
|
+
export const WITHDRAWN_CARD_DECISION_KIND = 'withdrawn';
|
|
105
|
+
function withdrawnCardResolution(card, at, logTag) {
|
|
106
|
+
const w = hostWithdrawalOf(card);
|
|
107
|
+
if (w === undefined) {
|
|
108
|
+
hostLog('debug', `${logTag}: card-withdrawn-unreadable as=retracted`);
|
|
109
|
+
return { kind: 'not_sent', ...at, cause: 'retracted' };
|
|
110
|
+
}
|
|
111
|
+
hostLog('debug', `${logTag}: card-withdrawn-by-host verdict=${w.rowVerdict.kind}`);
|
|
112
|
+
return { kind: 'not_sent', ...at, cause: 'withdrawn', toldBy: w.toldBy, rowVerdict: w.rowVerdict };
|
|
113
|
+
}
|
|
114
|
+
function parkRowOf(row, gatedCallId) {
|
|
102
115
|
const d = parkRowDeadlineState(row, Date.now());
|
|
103
116
|
return Object.freeze({
|
|
104
|
-
taskId,
|
|
105
117
|
...(gatedCallId !== undefined && gatedCallId !== '' ? { gatedCallId } : {}),
|
|
106
118
|
...(d.kind !== 'none' ? { deadlineMs: d.deadlineMs } : {}),
|
|
107
119
|
});
|
|
@@ -174,6 +186,16 @@ export function rememberRefusalOf(error) {
|
|
|
174
186
|
function rememberRefusalIn(reading) {
|
|
175
187
|
return reading.state === 'code' ? REMEMBER_REFUSAL_CODES.find((c) => c === reading.code) : undefined;
|
|
176
188
|
}
|
|
189
|
+
const FEEDBACK_REFUSAL_CODES = Object.freeze(['feedback_not_in_proof']);
|
|
190
|
+
function feedbackRefusalOf(error) {
|
|
191
|
+
const reading = readWireErrorCodeReading(error);
|
|
192
|
+
return reading.state === 'code' && FEEDBACK_REFUSAL_CODES.some((c) => c === reading.code);
|
|
193
|
+
}
|
|
194
|
+
function approveBodyWithoutFeedback(body) {
|
|
195
|
+
const { feedback: _feedback, ...rest } = body;
|
|
196
|
+
void _feedback;
|
|
197
|
+
return rest;
|
|
198
|
+
}
|
|
177
199
|
function logAfterDecided(msg) {
|
|
178
200
|
try {
|
|
179
201
|
hostLog('debug', msg);
|
|
@@ -203,12 +225,10 @@ const PARK_ROW_ARGS_TRUNCATED_NOTE = "this request's tool arguments were too lar
|
|
|
203
225
|
'Edits are not accepted on this card: there is no original input to edit';
|
|
204
226
|
const ARGS_REWRITTEN_NOTE = "this request's tool arguments were changed after the model made the call (for example by a hook) — " +
|
|
205
227
|
'the arguments shown here are the changed ones recorded for this approval, and they differ from the call shown in the conversation';
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
const
|
|
210
|
-
'(missing, or replaced by a size marker on the pending approval record), so the edit cannot be applied — nothing was sent; ' +
|
|
211
|
-
'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') }));
|
|
212
232
|
function isParkRowInputSizeMarker(v) {
|
|
213
233
|
if (typeof v !== 'object' || v === null || Array.isArray(v))
|
|
214
234
|
return false;
|
|
@@ -249,6 +269,14 @@ function cardInputOf(recorded, stream) {
|
|
|
249
269
|
return { from: 'stream', args: stream, shape };
|
|
250
270
|
return { from: 'none', shape, recorded };
|
|
251
271
|
}
|
|
272
|
+
function inputSourceBitOf(reading) {
|
|
273
|
+
return reading.from === 'recorded' ? { inputSource: 'record' } : reading.from === 'stream' ? { inputSource: 'stream' } : {};
|
|
274
|
+
}
|
|
275
|
+
function approvalInputSourceOf(card) {
|
|
276
|
+
const raw = ownDataValue(card, 'inputSource');
|
|
277
|
+
const known = { record: true, stream: true };
|
|
278
|
+
return typeof raw === 'string' && Object.hasOwn(known, raw) ? raw : undefined;
|
|
279
|
+
}
|
|
252
280
|
const CARD_ARGS_COMPARE_MAX_NODES = 20_000;
|
|
253
281
|
const CARD_ARGS_COMPARE_MAX_DEPTH = 256;
|
|
254
282
|
const NOT_COMPARABLE = Symbol('not comparable');
|
|
@@ -442,6 +470,7 @@ async function joinDurableDecision(hold, deps, signal) {
|
|
|
442
470
|
}
|
|
443
471
|
export async function surfaceFsApprovalAndDecide(deps, taskId, argsByCall, signal, parkGatedCallId, parkToolName) {
|
|
444
472
|
const decidedByReading = decidedByReadingSnapshotOf(deps);
|
|
473
|
+
const sourceGeneration = sourceGenerationNow(deps);
|
|
445
474
|
const readMark = openDurableRead();
|
|
446
475
|
let found;
|
|
447
476
|
let held;
|
|
@@ -471,7 +500,7 @@ export async function surfaceFsApprovalAndDecide(deps, taskId, argsByCall, signa
|
|
|
471
500
|
const fetched = found;
|
|
472
501
|
return holdDurableDecision(durableHoldKey(fetched.pending, callKey), rowIdentity, signal, async (hold) => {
|
|
473
502
|
const slot = {};
|
|
474
|
-
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);
|
|
475
504
|
noteCallOutcome(slot, out);
|
|
476
505
|
return out;
|
|
477
506
|
});
|
|
@@ -485,7 +514,7 @@ function parkRowHolderIdentity(row, gatedCallId) {
|
|
|
485
514
|
...(askSig !== undefined ? { askSig } : {}),
|
|
486
515
|
};
|
|
487
516
|
}
|
|
488
|
-
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) {
|
|
489
518
|
const { pending, gatedCallId } = found;
|
|
490
519
|
const at = { lane: 'decide', ...(gatedCallId !== undefined ? { gatedCallId } : {}) };
|
|
491
520
|
const toolName = typeof pending.toolName === 'string' ? pending.toolName : '';
|
|
@@ -518,7 +547,8 @@ async function presentFsApprovalAndDecide(deps, taskId, argsByCall, signal, foun
|
|
|
518
547
|
}
|
|
519
548
|
: {}),
|
|
520
549
|
...(argsRewritten ? { argsRewritten: true, wireNote: ARGS_REWRITTEN_NOTE } : {}),
|
|
521
|
-
...(argsFromModelCall ?
|
|
550
|
+
...(argsFromModelCall ? argsFromModelCallBitsOf() : {}),
|
|
551
|
+
...inputSourceBitOf(reading),
|
|
522
552
|
...(pending.governanceForced === true ? { governanceForced: true } : {}),
|
|
523
553
|
...(readRequiresRealApproval(pending) ? { requiresRealApproval: true } : {}),
|
|
524
554
|
...approvalLiveFaceOf(pending).facts,
|
|
@@ -540,14 +570,17 @@ async function presentFsApprovalAndDecide(deps, taskId, argsByCall, signal, foun
|
|
|
540
570
|
: {}),
|
|
541
571
|
allowSessionCarried: true,
|
|
542
572
|
grantBinding: readApprovalGrantBinding(pending),
|
|
543
|
-
parkRow: parkRowOf(
|
|
573
|
+
parkRow: parkRowOf(pending, gatedCallId),
|
|
574
|
+
...(typeof taskId === 'string' && taskId !== '' ? { taskId } : {}),
|
|
575
|
+
...sourceGenerationBit(sourceGeneration),
|
|
544
576
|
});
|
|
577
|
+
const editAcceptance = editedApprovalAcceptanceOf(cardRequest);
|
|
545
578
|
const card = await surfaceCallTrackedCard(gatedCallId, undefined, ledgerSlot, cardRequest);
|
|
546
579
|
hold.phase = 'respond';
|
|
547
|
-
if (
|
|
580
|
+
if (editAcceptance.state !== 'accepts' && card.kind === 'allow' && card.updatedInput !== undefined) {
|
|
548
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)`);
|
|
549
582
|
surfaceEditRefusedOnBlindAsk();
|
|
550
|
-
return { kind: 'not_sent', ...at, cause: 'edit_refused', detail:
|
|
583
|
+
return { kind: 'not_sent', ...at, cause: 'edit_refused', detail: parkEditRefusedReason() };
|
|
551
584
|
}
|
|
552
585
|
const decideSpan = bridge.openDecideOperation();
|
|
553
586
|
const decideOpts = { ...(signal ? { signal } : {}), operation: decideSpan };
|
|
@@ -558,9 +591,11 @@ async function presentFsApprovalAndDecide(deps, taskId, argsByCall, signal, foun
|
|
|
558
591
|
case 'retracted':
|
|
559
592
|
hostLog('debug', `liveHitlAskWire: approval card retracted without a decision for ${gatedCallId ?? '(no call)'} — nothing sent`);
|
|
560
593
|
return { kind: 'not_sent', ...at, cause: 'retracted' };
|
|
594
|
+
case WITHDRAWN_CARD_DECISION_KIND:
|
|
595
|
+
return withdrawnCardResolution(card, at, 'liveHitlAskWire');
|
|
561
596
|
case 'aborted':
|
|
562
597
|
{
|
|
563
|
-
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);
|
|
564
599
|
hold.trailing = cancelDeny;
|
|
565
600
|
observeCancelByDeny(cancelDeny, taskId);
|
|
566
601
|
}
|
|
@@ -578,11 +613,30 @@ async function presentFsApprovalAndDecide(deps, taskId, argsByCall, signal, foun
|
|
|
578
613
|
const { remember: _remember, ...plainApproveBody } = approveBody;
|
|
579
614
|
void _remember;
|
|
580
615
|
emitAnswerCommitted(callKey, 'decide', answered, approveBody);
|
|
616
|
+
let feedbackDropped = false;
|
|
617
|
+
const sendApprove = async (body) => {
|
|
618
|
+
const wire = feedbackDropped ? approveBodyWithoutFeedback(body) : body;
|
|
619
|
+
try {
|
|
620
|
+
return await bridge.decideTool(wire, gatedCallId, decideOpts, pending);
|
|
621
|
+
}
|
|
622
|
+
catch (e) {
|
|
623
|
+
if (wire.feedback === undefined || !feedbackRefusalOf(e))
|
|
624
|
+
throw e;
|
|
625
|
+
const verdict = directFailureVerdictOf(e, directSafetyStopOf(e));
|
|
626
|
+
if (verdict.yields) {
|
|
627
|
+
rememberStop = ownReadingSlot(verdict, 'directStop');
|
|
628
|
+
throw e;
|
|
629
|
+
}
|
|
630
|
+
feedbackDropped = true;
|
|
631
|
+
logAfterDecided(`liveToolApprovalWire: decide(approve+feedback) refused the feedback part (${String(e)}) — resending without the note`);
|
|
632
|
+
return await bridge.decideTool(approveBodyWithoutFeedback(wire), gatedCallId, decideOpts, pending);
|
|
633
|
+
}
|
|
634
|
+
};
|
|
581
635
|
if (approveBody.remember === 'session') {
|
|
582
636
|
let sessionReceipt;
|
|
583
637
|
let sessionDecided = false;
|
|
584
638
|
try {
|
|
585
|
-
const raw = await
|
|
639
|
+
const raw = await sendApprove(approveBody);
|
|
586
640
|
sessionReceipt = readDecideReceipt(raw);
|
|
587
641
|
sessionDecided = true;
|
|
588
642
|
}
|
|
@@ -600,13 +654,17 @@ async function presentFsApprovalAndDecide(deps, taskId, argsByCall, signal, foun
|
|
|
600
654
|
if (sessionDecided) {
|
|
601
655
|
if (sessionReceipt?.rememberApplied === false)
|
|
602
656
|
surfaceRememberNotApplied();
|
|
657
|
+
if (feedbackDropped)
|
|
658
|
+
surfaceAllowNoteNotCarried(allowNoteNotCarriedSentence());
|
|
603
659
|
return { kind: 'decided', ...at, decision: 'allow', ...(sessionReceipt !== undefined ? { receipt: sessionReceipt } : {}) };
|
|
604
660
|
}
|
|
605
661
|
}
|
|
606
|
-
const raw = await
|
|
662
|
+
const raw = await sendApprove(plainApproveBody);
|
|
607
663
|
const receipt = readDecideReceipt(raw);
|
|
608
664
|
if (rememberRefused || sessionDowngraded)
|
|
609
665
|
surfaceRememberNotApplied();
|
|
666
|
+
if (feedbackDropped)
|
|
667
|
+
surfaceAllowNoteNotCarried(allowNoteNotCarriedSentence());
|
|
610
668
|
return { kind: 'decided', ...at, decision: 'allow', ...(receipt !== undefined ? { receipt } : {}) };
|
|
611
669
|
}
|
|
612
670
|
catch (e) {
|
|
@@ -770,6 +828,12 @@ export function toolPermissionRequestAskBits(card, requestId) {
|
|
|
770
828
|
const origin = readAskOrigin(card);
|
|
771
829
|
const ruleOffersAbsence = readOwnNonEmptyString(card, 'ruleOffersAbsence');
|
|
772
830
|
const askClassPair = readAskClassPair(card);
|
|
831
|
+
const probeLayer = probeCarrierOf(card);
|
|
832
|
+
const probe = probeFactsAt(probeLayer);
|
|
833
|
+
const onTop = probeLayer === card;
|
|
834
|
+
const requestedBy = onTop ? approvalRequestedByOf(card) : undefined;
|
|
835
|
+
const payload = onTop ? cardPayloadReadingOf(card) : undefined;
|
|
836
|
+
const inputSource = onTop ? approvalInputSourceOf(card) : undefined;
|
|
773
837
|
return {
|
|
774
838
|
...(mandated ? { mandated: true } : {}),
|
|
775
839
|
...(mandate !== undefined ? { mandate } : {}),
|
|
@@ -777,6 +841,12 @@ export function toolPermissionRequestAskBits(card, requestId) {
|
|
|
777
841
|
...(ruleOffersAbsence !== undefined ? { ruleOffersAbsence } : {}),
|
|
778
842
|
...(askClassPair ?? {}),
|
|
779
843
|
...(seatSessionRowOf(card, requestId) ? { sessionRow: true } : {}),
|
|
844
|
+
...(probe.prose !== undefined ? { probeReason: probe.prose } : {}),
|
|
845
|
+
...(probe.cause !== undefined ? { probeCause: probe.cause } : {}),
|
|
846
|
+
...(seatAllowNoteCarriedOf(card, requestId) ? { feedbackCapable: true } : {}),
|
|
847
|
+
...(requestedBy !== undefined ? { requestedBy } : {}),
|
|
848
|
+
...(payload !== undefined && payload.payloadUnreadable && payload.why !== undefined ? { frameReading: payload.why } : {}),
|
|
849
|
+
...(inputSource !== undefined ? { inputSource } : {}),
|
|
780
850
|
};
|
|
781
851
|
}
|
|
782
852
|
function isToolApprovalDelegation(v) {
|
|
@@ -803,6 +873,14 @@ function respondDecisionOfAnswer(answer) {
|
|
|
803
873
|
return answer.allowSession ? 'allow_session' : 'allow';
|
|
804
874
|
return answer.kind === 'deny' ? 'deny' : undefined;
|
|
805
875
|
}
|
|
876
|
+
export function allowNoteReadingOf(answer) {
|
|
877
|
+
const note = readOwnDataValue(answer, 'note');
|
|
878
|
+
if (note === undefined)
|
|
879
|
+
return { kind: 'absent' };
|
|
880
|
+
if (typeof note !== 'string')
|
|
881
|
+
return { kind: 'invalid' };
|
|
882
|
+
return note.trim() === '' ? { kind: 'blank' } : { kind: 'text', text: note };
|
|
883
|
+
}
|
|
806
884
|
function respondNoteGate(reason, capable) {
|
|
807
885
|
if (reason === undefined || reason.trim() === '')
|
|
808
886
|
return { dropped: 'blank' };
|
|
@@ -821,10 +899,14 @@ export function answerPayloadFor(answer, lane, caps) {
|
|
|
821
899
|
const reason = answer.kind === 'deny' && typeof answer.reason === 'string' ? answer.reason : undefined;
|
|
822
900
|
return Object.freeze({ decision: 'deny', reason: denyReasonForWire(reason, 'answer') ?? DEFAULT_DENY_REASON });
|
|
823
901
|
}
|
|
902
|
+
const fb = allowNoteReadingOf(answer);
|
|
903
|
+
if (fb.kind === 'invalid')
|
|
904
|
+
hostLog('error', `answerPayloadFor: the allow note must be a string (got ${typeof readOwnDataValue(answer, 'note')}) — not sent as feedback; the decision itself is sent`);
|
|
824
905
|
return Object.freeze({
|
|
825
906
|
decision: 'approve',
|
|
826
907
|
...(word === 'allow_session' ? { remember: 'session' } : {}),
|
|
827
908
|
...(answer.updatedInput !== undefined ? { updatedInput: answer.updatedInput } : {}),
|
|
909
|
+
...(fb.kind === 'text' ? { feedback: fb.text } : {}),
|
|
828
910
|
});
|
|
829
911
|
}
|
|
830
912
|
if (answer.kind === 'allow')
|
|
@@ -833,9 +915,25 @@ export function answerPayloadFor(answer, lane, caps) {
|
|
|
833
915
|
return Object.freeze({ decision: word, ...('note' in gate ? { note: gate.note } : {}) });
|
|
834
916
|
}
|
|
835
917
|
const ANSWER_CARRIAGE_NONE = Object.freeze({ allowNote: 'none' });
|
|
918
|
+
const ANSWER_CARRIAGE_MODEL = Object.freeze({ allowNote: 'model' });
|
|
836
919
|
export function answerCarriage(card) {
|
|
837
|
-
|
|
838
|
-
|
|
920
|
+
return cardIsOnParkRow(card) ? ANSWER_CARRIAGE_MODEL : ANSWER_CARRIAGE_NONE;
|
|
921
|
+
}
|
|
922
|
+
export function cardIsOnParkRow(card) {
|
|
923
|
+
try {
|
|
924
|
+
if (typeof card !== 'object' || card === null)
|
|
925
|
+
return false;
|
|
926
|
+
const park = readOwnDataValue(card, 'parkRow');
|
|
927
|
+
if (typeof park !== 'object' || park === null || Array.isArray(park))
|
|
928
|
+
return false;
|
|
929
|
+
return readOwnDataNonEmptyString(card, 'taskId') !== undefined;
|
|
930
|
+
}
|
|
931
|
+
catch {
|
|
932
|
+
return false;
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
export function allowNoteNotCarriedSentence(lang) {
|
|
936
|
+
return renderMessage(msg('approval.allowNote.notCarried'), lang);
|
|
839
937
|
}
|
|
840
938
|
export function observeApprovalAnswerCommitted(listener) {
|
|
841
939
|
answerCommittedListeners.add(listener);
|
|
@@ -852,37 +950,63 @@ function emitAnswerCommitted(callKey, lane, answer, payload) {
|
|
|
852
950
|
invokeHostCallbackIsolated('liveToolApprovalWire: answer-committed listener', () => l(event));
|
|
853
951
|
}
|
|
854
952
|
export function isToolApprovalRespondReplayed(ack) {
|
|
855
|
-
return typeof ack === 'object' && ack !== null && ack.idempotent === true;
|
|
953
|
+
return typeof ack === 'object' && ack !== null && ack.idempotent === true && ack.accepted !== 'parked_redeemed';
|
|
954
|
+
}
|
|
955
|
+
export function isToolApprovalRespondParkedRedeemed(ack) {
|
|
956
|
+
return typeof ack === 'object' && ack !== null && ack.accepted === 'parked_redeemed';
|
|
957
|
+
}
|
|
958
|
+
export function replayedFirstDecisionOf(ack) {
|
|
959
|
+
if (ack === undefined)
|
|
960
|
+
return undefined;
|
|
961
|
+
if (isToolApprovalRespondReplayed(ack))
|
|
962
|
+
return ack.decision;
|
|
963
|
+
if (isToolApprovalRespondParkedRedeemed(ack) && ack.idempotent === true)
|
|
964
|
+
return ack.decision === 'allow' || ack.decision === 'deny' ? ack.decision : undefined;
|
|
965
|
+
return undefined;
|
|
966
|
+
}
|
|
967
|
+
export function settlementAckOf(read) {
|
|
968
|
+
return read !== undefined && isToolApprovalRespondParkedRedeemed(read) && read.idempotent !== true ? undefined : read;
|
|
856
969
|
}
|
|
857
970
|
export function readToolApprovalRespondAck(v) {
|
|
858
971
|
if (v === null || typeof v !== 'object')
|
|
859
972
|
return undefined;
|
|
860
|
-
const
|
|
861
|
-
if (
|
|
862
|
-
return
|
|
863
|
-
if (
|
|
864
|
-
return
|
|
865
|
-
if (
|
|
866
|
-
return undefined;
|
|
867
|
-
if (
|
|
868
|
-
return undefined;
|
|
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));
|
|
869
996
|
const out = {
|
|
870
|
-
approvalId
|
|
997
|
+
approvalId,
|
|
871
998
|
delivery: 'applied',
|
|
872
|
-
decision:
|
|
873
|
-
...(typeof
|
|
874
|
-
...(typeof
|
|
875
|
-
...(typeof
|
|
876
|
-
...(typeof
|
|
877
|
-
? { 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 }
|
|
878
1005
|
: {}),
|
|
879
|
-
...(typeof
|
|
880
|
-
...(typeof
|
|
881
|
-
...(isNonEmptyStringArray(
|
|
882
|
-
...(
|
|
883
|
-
const anchors = readPersistedRuleAnchors(o.persistedRuleAnchors);
|
|
884
|
-
return anchors !== undefined ? { persistedRuleAnchors: anchors } : {};
|
|
885
|
-
})(),
|
|
1006
|
+
...(typeof noteRecorded === 'boolean' ? { noteRecorded } : {}),
|
|
1007
|
+
...(typeof persistedRule === 'string' && persistedRule !== '' ? { persistedRule } : {}),
|
|
1008
|
+
...(isNonEmptyStringArray(persistedRules) ? { persistedRules: persistedRules.slice() } : {}),
|
|
1009
|
+
...(anchors !== undefined ? { persistedRuleAnchors: anchors } : {}),
|
|
886
1010
|
};
|
|
887
1011
|
if (out.persistedRule !== undefined && (out.persistedRules !== undefined || out.persistedRuleAnchors !== undefined)) {
|
|
888
1012
|
delete out.persistedRule;
|
|
@@ -903,6 +1027,35 @@ export function readToolApprovalRespondAck(v) {
|
|
|
903
1027
|
}
|
|
904
1028
|
return out;
|
|
905
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
|
+
}
|
|
906
1059
|
export function readToolApprovalRespondParking(v) {
|
|
907
1060
|
if (typeof v !== 'object' || v === null)
|
|
908
1061
|
return undefined;
|
|
@@ -945,6 +1098,17 @@ function replayClaimOf(raw) {
|
|
|
945
1098
|
}
|
|
946
1099
|
return { ...(approvalId !== undefined ? { approvalId } : {}), ...(d === 'allow' || d === 'deny' ? { decision: d } : {}), carriesDelivery };
|
|
947
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
|
+
}
|
|
948
1112
|
function ownIdempotentTrue(raw) {
|
|
949
1113
|
if (typeof raw !== 'object' || raw === null)
|
|
950
1114
|
return false;
|
|
@@ -956,27 +1120,103 @@ function ownIdempotentTrue(raw) {
|
|
|
956
1120
|
return false;
|
|
957
1121
|
}
|
|
958
1122
|
}
|
|
959
|
-
function
|
|
960
|
-
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)
|
|
961
1159
|
return undefined;
|
|
962
|
-
if (typeof
|
|
1160
|
+
if (typeof askId !== 'string' || askId.length === 0)
|
|
963
1161
|
return undefined;
|
|
964
|
-
if (
|
|
1162
|
+
if (decision !== 'allow' && decision !== 'deny')
|
|
965
1163
|
return undefined;
|
|
966
|
-
if (typeof
|
|
1164
|
+
if (typeof decidedAtMs !== 'number' || !Number.isFinite(decidedAtMs) || decidedAtMs < 0)
|
|
967
1165
|
return undefined;
|
|
968
1166
|
return {
|
|
969
|
-
approvalId
|
|
970
|
-
askId
|
|
1167
|
+
approvalId,
|
|
1168
|
+
askId,
|
|
971
1169
|
idempotent: true,
|
|
972
|
-
decision
|
|
973
|
-
decidedAtMs
|
|
974
|
-
...(typeof
|
|
975
|
-
...(
|
|
1170
|
+
decision,
|
|
1171
|
+
decidedAtMs,
|
|
1172
|
+
...(typeof decisionNote === 'string' && decisionNote !== '' ? { decisionNote } : {}),
|
|
1173
|
+
...(slotValueOf(s.rememberApplied) === false ? { rememberApplied: false } : {}),
|
|
976
1174
|
};
|
|
977
1175
|
}
|
|
1176
|
+
function readParkedRedeemedAck(s) {
|
|
1177
|
+
if (s.delivery.presence !== 'absent')
|
|
1178
|
+
return undefined;
|
|
1179
|
+
const text = (slot) => {
|
|
1180
|
+
const v = slotValueOf(slot);
|
|
1181
|
+
return typeof v === 'string' && v !== '' ? v : undefined;
|
|
1182
|
+
};
|
|
1183
|
+
const approvalId = text(s.approvalId);
|
|
1184
|
+
const askId = text(s.askId);
|
|
1185
|
+
if (approvalId === undefined || askId === undefined)
|
|
1186
|
+
return undefined;
|
|
1187
|
+
const replay = slotValueOf(s.idempotent) === true;
|
|
1188
|
+
const dec = slotValueOf(s.decision);
|
|
1189
|
+
let decision;
|
|
1190
|
+
if (replay) {
|
|
1191
|
+
if (dec !== 'allow' && dec !== 'deny')
|
|
1192
|
+
return undefined;
|
|
1193
|
+
decision = dec;
|
|
1194
|
+
}
|
|
1195
|
+
else {
|
|
1196
|
+
decision = typeof dec === 'string' && dec !== '' ? dec : undefined;
|
|
1197
|
+
}
|
|
1198
|
+
const remember = slotValueOf(s.rememberApplied);
|
|
1199
|
+
return {
|
|
1200
|
+
approvalId,
|
|
1201
|
+
askId,
|
|
1202
|
+
accepted: 'parked_redeemed',
|
|
1203
|
+
...(replay ? { idempotent: true } : {}),
|
|
1204
|
+
...(decision !== undefined ? { decision } : {}),
|
|
1205
|
+
...(typeof remember === 'boolean' ? { rememberApplied: remember } : {}),
|
|
1206
|
+
};
|
|
1207
|
+
}
|
|
1208
|
+
function replayedDecisionOf(first, sent, ack) {
|
|
1209
|
+
return { kind: 'decided', lane: 'respond', decision: first, ...(ack !== undefined ? { ack } : {}), settledElsewhere: toolPermissionSettledElsewhereOf(first, sent) };
|
|
1210
|
+
}
|
|
978
1211
|
function isNonEmptyStringArray(v) {
|
|
979
|
-
|
|
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;
|
|
980
1220
|
}
|
|
981
1221
|
function readPersistedRuleAnchors(v) {
|
|
982
1222
|
if (!Array.isArray(v) || v.length === 0)
|
|
@@ -1080,19 +1320,44 @@ function readProbeReason(v) {
|
|
|
1080
1320
|
function usableProbeReason(raw) {
|
|
1081
1321
|
return typeof raw === 'string' && raw.trim() !== '' ? raw : undefined;
|
|
1082
1322
|
}
|
|
1323
|
+
function probeFactsAt(at) {
|
|
1324
|
+
const prose = usableProbeReason(ownDataValue(at, 'probeReason'));
|
|
1325
|
+
let cause;
|
|
1326
|
+
try {
|
|
1327
|
+
const raw = ownDataValue(at, 'probeCause');
|
|
1328
|
+
if (isWireRecordCarrier(raw))
|
|
1329
|
+
cause = raw;
|
|
1330
|
+
}
|
|
1331
|
+
catch {
|
|
1332
|
+
cause = undefined;
|
|
1333
|
+
}
|
|
1334
|
+
return { prose, cause };
|
|
1335
|
+
}
|
|
1336
|
+
function probeCarrierOf(carrier) {
|
|
1337
|
+
let d;
|
|
1338
|
+
try {
|
|
1339
|
+
d = Object.getOwnPropertyDescriptor(carrier, 'riskDescriptor');
|
|
1340
|
+
}
|
|
1341
|
+
catch {
|
|
1342
|
+
return undefined;
|
|
1343
|
+
}
|
|
1344
|
+
if (d === undefined)
|
|
1345
|
+
return carrier;
|
|
1346
|
+
return Object.hasOwn(d, 'value') ? d.value : undefined;
|
|
1347
|
+
}
|
|
1083
1348
|
const PROBE_CAUSE_CODE_WORD = /^[a-z][a-z0-9_]{0,31}(?:\.[a-z][a-z0-9_]{0,31}){1,3}$/;
|
|
1084
1349
|
export function askProbeReasonDetail(card, lang) {
|
|
1085
|
-
const prose =
|
|
1350
|
+
const { prose, cause } = probeFactsAt(card);
|
|
1086
1351
|
const shown = prose === undefined ? '' : displayUntrusted(prose);
|
|
1087
|
-
const sentence = probeCauseSentence(
|
|
1352
|
+
const sentence = probeCauseSentence(cause, shown !== '', lang);
|
|
1088
1353
|
if (sentence === undefined)
|
|
1089
1354
|
return shown === '' ? undefined : shown;
|
|
1090
1355
|
return shown === '' ? sentence : renderMessage(msg('approval.probe.proseJoin', { sentence, prose: shown }), lang);
|
|
1091
1356
|
}
|
|
1092
1357
|
function probeCauseSentence(cause, withProse, lang) {
|
|
1358
|
+
if (cause === undefined)
|
|
1359
|
+
return undefined;
|
|
1093
1360
|
try {
|
|
1094
|
-
if (!isWireRecordCarrier(cause))
|
|
1095
|
-
return undefined;
|
|
1096
1361
|
const code = ownDataValue(cause, 'code');
|
|
1097
1362
|
const withCode = typeof code === 'string' && PROBE_CAUSE_CODE_WORD.test(code);
|
|
1098
1363
|
const key = withProse
|
|
@@ -1675,6 +1940,67 @@ function subagentBadgeFor(frame) {
|
|
|
1675
1940
|
name = `${name.slice(0, 31)}…`;
|
|
1676
1941
|
return { name, color: 'cyan' };
|
|
1677
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
|
+
}
|
|
1678
2004
|
function v1Bit(stamp) {
|
|
1679
2005
|
try {
|
|
1680
2006
|
stamp();
|
|
@@ -1713,12 +2039,14 @@ function cardFactsOf(carrier, leg, opts, liveFacts, approvalId, payloadWhy) {
|
|
|
1713
2039
|
if (reading.from === 'recorded') {
|
|
1714
2040
|
if (blind)
|
|
1715
2041
|
return { args: reading.args, argsUnavailable: true };
|
|
1716
|
-
return reading.rewritten
|
|
2042
|
+
return reading.rewritten
|
|
2043
|
+
? { args: reading.args, argsRewritten: true, wireNote: ARGS_REWRITTEN_NOTE, ...inputSourceBitOf(reading) }
|
|
2044
|
+
: { args: reading.args, ...inputSourceBitOf(reading) };
|
|
1717
2045
|
}
|
|
1718
2046
|
if (reading.from === 'stream' && typeof reading.args === 'object' && reading.args !== null) {
|
|
1719
2047
|
if (blind)
|
|
1720
2048
|
return { args: reading.args, argsUnavailable: true };
|
|
1721
|
-
return { args: reading.args,
|
|
2049
|
+
return { args: reading.args, ...argsFromModelCallBitsOf(), ...inputSourceBitOf(reading) };
|
|
1722
2050
|
}
|
|
1723
2051
|
const omitted = c.argsOmitted === true || reading.shape === 'size_marker';
|
|
1724
2052
|
const fallback = argsFallbackOf(c.message, omitted);
|
|
@@ -1749,6 +2077,8 @@ function cardFactsOf(carrier, leg, opts, liveFacts, approvalId, payloadWhy) {
|
|
|
1749
2077
|
out.argsUnavailable = true;
|
|
1750
2078
|
if (argsPart.argsRewritten === true)
|
|
1751
2079
|
out.argsRewritten = true;
|
|
2080
|
+
if (argsPart.inputSource !== undefined)
|
|
2081
|
+
out.inputSource = argsPart.inputSource;
|
|
1752
2082
|
if (full) {
|
|
1753
2083
|
v1Bit(() => {
|
|
1754
2084
|
if (c.governanceForced === true)
|
|
@@ -1784,6 +2114,11 @@ function cardFactsOf(carrier, leg, opts, liveFacts, approvalId, payloadWhy) {
|
|
|
1784
2114
|
if (r !== undefined)
|
|
1785
2115
|
out.probeReason = r;
|
|
1786
2116
|
});
|
|
2117
|
+
v1Bit(() => {
|
|
2118
|
+
const by = approvalRequestedByOf(live);
|
|
2119
|
+
if (by !== undefined)
|
|
2120
|
+
out.requestedBy = by;
|
|
2121
|
+
});
|
|
1787
2122
|
}
|
|
1788
2123
|
v1Bit(() => {
|
|
1789
2124
|
if (readApprovalRememberRefused(carrier))
|
|
@@ -1928,7 +2263,10 @@ export async function surfaceApprovalFrameWithId(frame, approvalId, respond, str
|
|
|
1928
2263
|
if (typeof approvalId !== 'string' || approvalId === '')
|
|
1929
2264
|
return approvalIdUnreadableRefusal();
|
|
1930
2265
|
const carriers = openingFrameCarriersOf(frame);
|
|
1931
|
-
const
|
|
2266
|
+
const liveRun = liveCardRunOf(frame, run);
|
|
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 };
|
|
1932
2270
|
return enterLiveCard(entry);
|
|
1933
2271
|
}
|
|
1934
2272
|
function openingFrameCarriersOf(frame) {
|
|
@@ -1954,7 +2292,7 @@ function enterLiveCard(e) {
|
|
|
1954
2292
|
return joinOtherLaneHolder(e, other);
|
|
1955
2293
|
return holdLiveCard(e.identity, signal, async (hold) => {
|
|
1956
2294
|
const slot = {};
|
|
1957
|
-
const out = await presentToolApprovalFrameAndRespond(e.frame, e.carriers, approvalId, e.respond, e.streamArgs, signal, e.lane, hold, slot, e.receivedAtMs);
|
|
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);
|
|
1958
2296
|
noteCallOutcome(slot, out);
|
|
1959
2297
|
return out;
|
|
1960
2298
|
});
|
|
@@ -1969,15 +2307,20 @@ async function joinOtherLaneHolder(e, other) {
|
|
|
1969
2307
|
return { kind: 'not_sent', lane: 'respond', cause: 'retracted', joinedInFlight: true };
|
|
1970
2308
|
return enterLiveCard(e);
|
|
1971
2309
|
}
|
|
1972
|
-
function
|
|
2310
|
+
function liveCardRunOf(frame, run) {
|
|
2311
|
+
const source = frameBindingOf(frame) ?? run;
|
|
2312
|
+
return {
|
|
2313
|
+
taskId: guardedRead(() => readOwnDataNonEmptyString(source, 'taskId')),
|
|
2314
|
+
sessionId: guardedRead(() => readOwnDataNonEmptyString(source, 'sessionId')),
|
|
2315
|
+
};
|
|
2316
|
+
}
|
|
2317
|
+
function liveCardIdentityOf(approvalId, carriers, liveRun) {
|
|
1973
2318
|
const body = carriers.body;
|
|
1974
2319
|
const toolCallId = typeof body.toolCallId === 'string' && body.toolCallId !== '' ? body.toolCallId : undefined;
|
|
1975
2320
|
const fromSubagent = isFromSubagent(carriers.body);
|
|
1976
|
-
const
|
|
1977
|
-
const source = bound ?? run;
|
|
1978
|
-
const ownRun = fromSubagent ? subagentSourceSessionOf(carriers.body) : source?.taskId;
|
|
2321
|
+
const ownRun = fromSubagent ? subagentSourceSessionOf(carriers.body) : liveRun.taskId;
|
|
1979
2322
|
const taskId = typeof ownRun === 'string' && ownRun !== '' ? ownRun : undefined;
|
|
1980
|
-
const sessionId =
|
|
2323
|
+
const sessionId = fromSubagent ? undefined : liveRun.sessionId;
|
|
1981
2324
|
const askSig = carrierAskSig(carriers.body, carriers.live);
|
|
1982
2325
|
return {
|
|
1983
2326
|
approvalId,
|
|
@@ -2033,22 +2376,24 @@ function readApprovalCardClaimSignal(v) {
|
|
|
2033
2376
|
export function claimApprovalCard(identity, options) {
|
|
2034
2377
|
return claimApprovalCardFor(readApprovalHolderIdentity(identity), readApprovalCardClaimSignal(options));
|
|
2035
2378
|
}
|
|
2036
|
-
async function presentToolApprovalFrameAndRespond(frame, carriers, approvalId, respond, streamArgs, signal, lane, hold, ledgerSlot, receivedAtMs) {
|
|
2379
|
+
async function presentToolApprovalFrameAndRespond(frame, carriers, approvalId, respond, streamArgs, signal, lane, hold, ledgerSlot, receivedAtMs, cardTaskId, sourceGeneration) {
|
|
2037
2380
|
const bodyToolCallId = carriers.body.toolCallId;
|
|
2038
2381
|
const frameToolCallId = typeof bodyToolCallId === 'string' && bodyToolCallId !== '' ? bodyToolCallId : undefined;
|
|
2039
2382
|
const decidedByReading = decidedByReadingSnapshotOf(lane);
|
|
2040
2383
|
const facts = cardFactsOf(carriers.body, carriers.leg, { streamArgs, ...(lane?.argsUnavailable === true ? { argsUnavailable: true } : {}) }, carriers.live, approvalId, carriers.why);
|
|
2041
2384
|
const argsNotRealInput = facts.argsUnavailable === true;
|
|
2385
|
+
const editAcceptance = editedApprovalAcceptanceOf(facts);
|
|
2042
2386
|
const ruleOffers = facts.ruleOffers;
|
|
2043
|
-
if (argsNotRealInput && lane?.argsUnavailable !== true && facts.wireNote !== undefined) {
|
|
2387
|
+
if (argsNotRealInput && lane?.argsUnavailable !== true && facts.wireNote !== undefined && facts.inputSource !== 'stream') {
|
|
2044
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)'}`);
|
|
2045
2389
|
}
|
|
2046
|
-
const card = await surfaceCallTrackedCard(frameToolCallId, approvalId, ledgerSlot, {
|
|
2047
|
-
...facts,
|
|
2390
|
+
const card = await surfaceCallTrackedCard(frameToolCallId, approvalId, ledgerSlot, cardRequestOf(facts, {
|
|
2048
2391
|
callKey: liveFrameCallKey(approvalId),
|
|
2392
|
+
...(cardTaskId !== undefined ? { taskId: cardTaskId } : {}),
|
|
2393
|
+
...sourceGenerationBit(sourceGeneration),
|
|
2049
2394
|
signal: hold.cardSignal,
|
|
2050
2395
|
...approvalWindowKeysOf(frame, { windowIsCurrent: lane?.windowIsCurrent === true, receivedAtMs, ...(carriers.leg === 'generic' ? { unknownShape: true } : {}) }),
|
|
2051
|
-
});
|
|
2396
|
+
}));
|
|
2052
2397
|
if (hold.superseded !== undefined) {
|
|
2053
2398
|
hostLog('debug', `liveToolApprovalWire: ${approvalId} was settled by the engine while its card was up${hold.superseded.parked ? ' (parked)' : ''} — card withdrawn; ` +
|
|
2054
2399
|
`the card came back ${card.kind}; nothing sent`);
|
|
@@ -2056,28 +2401,38 @@ async function presentToolApprovalFrameAndRespond(frame, carriers, approvalId, r
|
|
|
2056
2401
|
surfaceApprovalParking();
|
|
2057
2402
|
return { kind: 'not_sent', lane: 'respond', cause: 'retracted' };
|
|
2058
2403
|
}
|
|
2059
|
-
if (
|
|
2404
|
+
if (editAcceptance.state !== 'accepts' && card.kind === 'allow' && card.updatedInput !== undefined) {
|
|
2060
2405
|
hostLog('error', `liveToolApprovalWire: ${approvalId} card returned an edited approval on a card whose arguments are not the tool's real input (${lane?.argsUnavailable === true ? 'args-unavailable ask' : 'arguments omitted or absent on the frame'}) — nothing sent (the ask stays pending)`);
|
|
2061
2406
|
surfaceEditRefusedOnBlindAsk();
|
|
2062
2407
|
return { kind: 'not_sent', lane: 'respond', cause: 'edit_refused' };
|
|
2063
2408
|
}
|
|
2409
|
+
if (card.kind === WITHDRAWN_CARD_DECISION_KIND)
|
|
2410
|
+
return withdrawnCardResolution(card, { lane: 'respond' }, 'liveToolApprovalWire');
|
|
2064
2411
|
if (card.kind === RETRACTED_CARD_DECISION_KIND) {
|
|
2065
2412
|
hostLog('debug', `liveToolApprovalWire: ${approvalId} card retracted without a decision${card.reason ? ` (${card.reason})` : ''} — nothing sent`);
|
|
2066
2413
|
return { kind: 'not_sent', lane: 'respond', cause: 'retracted' };
|
|
2067
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
|
+
});
|
|
2068
2429
|
if (card.kind === 'aborted') {
|
|
2069
2430
|
enterLiveRespondPhase(hold);
|
|
2070
2431
|
const interruptOpts = lane?.approvalDecisionNoteCapable === true ? { note: INTERRUPT_DENY_REASON } : {};
|
|
2071
|
-
|
|
2072
|
-
try {
|
|
2073
|
-
interruptDeny = Promise.resolve(respond(approvalId, 'deny', interruptOpts));
|
|
2074
|
-
}
|
|
2075
|
-
catch (e) {
|
|
2076
|
-
interruptDeny = Promise.reject(e);
|
|
2077
|
-
}
|
|
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));
|
|
2078
2433
|
hold.trailing = interruptDeny.then((body) => readToolApprovalRespondParking(body) === undefined, () => false);
|
|
2079
2434
|
observeCancelByDeny(interruptDeny, approvalId);
|
|
2080
|
-
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)`);
|
|
2081
2436
|
return { kind: 'unsettled', lane: 'respond', cause: 'interrupted' };
|
|
2082
2437
|
}
|
|
2083
2438
|
enterLiveRespondPhase(hold);
|
|
@@ -2094,8 +2449,10 @@ async function presentToolApprovalFrameAndRespond(frame, carriers, approvalId, r
|
|
|
2094
2449
|
: card;
|
|
2095
2450
|
const basePayload = answerPayloadFor(answerSnapshot, 'respond', { approvalDecisionNoteCapable: noteCapable });
|
|
2096
2451
|
const decision = basePayload?.decision ?? 'deny';
|
|
2097
|
-
|
|
2098
|
-
|
|
2452
|
+
const allowNoteText = decision !== 'deny' ? allowNoteReadingOf(answerSnapshot) : { kind: 'absent' };
|
|
2453
|
+
const allowNoteDropped = allowNoteText.kind === 'text' && answerCarriage({ callKey: liveFrameCallKey(approvalId) }).allowNote === 'none';
|
|
2454
|
+
if (allowNoteDropped && allowNoteText.kind === 'text') {
|
|
2455
|
+
hostLog('debug', `liveToolApprovalWire: ${approvalId} card carried a note on Yes (len=${allowNoteText.text.length}) — this approval door has no field that brings it to the model, so it was not sent`);
|
|
2099
2456
|
}
|
|
2100
2457
|
const denySettledByForWire = card.kind === 'deny' ? readApprovalDenySettledBy(card) : undefined;
|
|
2101
2458
|
const denyPolicyCauseForWire = card.kind === 'deny' ? readPolicyDenyCause(card) : undefined;
|
|
@@ -2198,30 +2555,18 @@ async function presentToolApprovalFrameAndRespond(frame, carriers, approvalId, r
|
|
|
2198
2555
|
if (basePayload !== undefined)
|
|
2199
2556
|
emitAnswerCommitted(liveFrameCallKey(approvalId), 'respond', answerSnapshot, basePayload);
|
|
2200
2557
|
try {
|
|
2201
|
-
const delivery = await
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
hostLog('debug', step === 'renamed'
|
|
2210
|
-
? `liveToolApprovalWire: respond(deny) for ${approvalId} was refused because the settlement note was sent under a name ` +
|
|
2211
|
-
'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 ' +
|
|
2212
2566
|
'(the refusal happened before the approval was judged, so nothing was consumed and this is a re-delivery, not a second act)'
|
|
2213
|
-
:
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
'(the refusal happened before the approval was judged, so nothing was consumed and this is a re-delivery, not a second act)'
|
|
2217
|
-
: `liveToolApprovalWire: respond(deny) for ${approvalId} was refused again because the settlement note is not part of ` +
|
|
2218
|
-
'what this deployment signs — re-sending the SAME decision exactly once more with that key removed ' +
|
|
2219
|
-
'(still before the approval was judged)');
|
|
2220
|
-
},
|
|
2221
|
-
parkingOf: (body) => {
|
|
2222
|
-
const p = readToolApprovalRespondParking(body);
|
|
2223
|
-
return p?.kind === 'parking' ? p.view : undefined;
|
|
2224
|
-
},
|
|
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)');
|
|
2225
2570
|
});
|
|
2226
2571
|
if (delivery.kind === 'thrown') {
|
|
2227
2572
|
deliveryFailure = delivery;
|
|
@@ -2249,16 +2594,14 @@ async function presentToolApprovalFrameAndRespond(frame, carriers, approvalId, r
|
|
|
2249
2594
|
'reporting the answer as NOT settled (never as decided, never as parked); not re-sent');
|
|
2250
2595
|
return { kind: 'unsettled', lane: 'respond', cause: 'unreadable' };
|
|
2251
2596
|
}
|
|
2252
|
-
const parsed = readToolApprovalRespondAck(raw);
|
|
2253
|
-
const
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
return { kind: 'decided', lane: 'respond', decision: claimed.decision };
|
|
2261
|
-
}
|
|
2597
|
+
const parsed = settlementAckOf(readToolApprovalRespondAck(raw));
|
|
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') {
|
|
2262
2605
|
hostLog('error', `liveToolApprovalWire: respond(${decision}) for ${approvalId} answered with a replay of an earlier decision that cannot be read or names another approval — ` +
|
|
2263
2606
|
'reporting the answer as NOT settled (never as the decision this client sent); not re-sent');
|
|
2264
2607
|
return { kind: 'unsettled', lane: 'respond', cause: 'unreadable' };
|
|
@@ -2327,6 +2670,8 @@ async function presentToolApprovalFrameAndRespond(frame, carriers, approvalId, r
|
|
|
2327
2670
|
}
|
|
2328
2671
|
if (replayed === undefined && sessionDowngraded)
|
|
2329
2672
|
surfaceRememberNotApplied();
|
|
2673
|
+
if (replayed === undefined && allowNoteDropped)
|
|
2674
|
+
surfaceAllowNoteNotCarried(allowNoteNotCarriedSentence());
|
|
2330
2675
|
if (respondOpts.updatedInput !== undefined && applied?.updatedInputForwarded === false) {
|
|
2331
2676
|
logAfterDecided(`liveToolApprovalWire: ${approvalId} edited args were NOT forwarded (ack.updatedInputForwarded=false) — the tool runs on the ORIGINAL input`);
|
|
2332
2677
|
surfaceEditNotForwarded();
|
|
@@ -2338,7 +2683,7 @@ async function presentToolApprovalFrameAndRespond(frame, carriers, approvalId, r
|
|
|
2338
2683
|
if (replayed !== undefined) {
|
|
2339
2684
|
hostLog('debug', `liveToolApprovalWire: respond(${decision}) for ${approvalId} answered with a replay — the approval was already decided (${replayed.decision}); ` +
|
|
2340
2685
|
'this answer was not delivered, reporting the earlier decision');
|
|
2341
|
-
return
|
|
2686
|
+
return replayedDecisionOf(replayed.decision, decision, replayed);
|
|
2342
2687
|
}
|
|
2343
2688
|
const deny = decision === 'deny' ? denyFactsOf(denySettledByForWire, denyReasonSnapshot, attributionDropped, attributionRenamed, denyPolicyCauseForWire) : undefined;
|
|
2344
2689
|
return { kind: 'decided', lane: 'respond', decision, ...(ack !== undefined ? { ack } : {}), ...(deny !== undefined ? { deny } : {}) };
|