@sema-agent/client-core 0.109.0 → 0.110.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 +173 -0
- package/README.md +46 -22
- package/dist/adapt/arms.js +20 -7
- package/dist/adapter/downstream/eventToSdkMessage.js +11 -6
- package/dist/declared/supportFloorDeclared.js +1 -1
- package/dist/displayUntrusted.js +132 -14
- package/dist/engineErrorCodes.d.ts +3 -0
- package/dist/engineErrorCodes.js +3 -0
- package/dist/engineHealthFacts.d.ts +9 -0
- package/dist/engineHealthFacts.js +21 -1
- package/dist/engineInlineTaskStats.d.ts +4 -3
- package/dist/engineInlineTaskStats.js +18 -2
- package/dist/engineNoticeCodes.d.ts +10 -0
- package/dist/engineNoticeCodes.js +33 -1
- package/dist/engineRepoint.d.ts +140 -0
- package/dist/engineRepoint.js +285 -0
- package/dist/engineRowRef.js +2 -0
- package/dist/engineSessionMessages.d.ts +2 -1
- package/dist/engineSessionMessages.js +5 -0
- package/dist/errorSupplementRoles.js +2 -1
- 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 +1 -0
- package/dist/generated/sdkFactTables.js +4 -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/approvalRequestFrameReading.d.ts +7 -0
- package/dist/hitl/approvalRequestFrameReading.js +11 -0
- package/dist/hitl/approvalResolution.d.ts +8 -1
- package/dist/hitl/approvalResolution.js +4 -0
- package/dist/hitl/askGateWire.js +0 -2
- package/dist/hitl/automaticAnswerVerdict.js +2 -2
- package/dist/hitl/decisionConflict.js +6 -3
- package/dist/hitl/decisionRefusal.js +1 -0
- package/dist/hitl/decisionSend.d.ts +3 -0
- package/dist/hitl/decisionSend.js +29 -11
- package/dist/hitl/editedApprovalAcceptance.d.ts +25 -0
- package/dist/hitl/editedApprovalAcceptance.js +26 -0
- package/dist/hitl/frameRouter.js +4 -18
- package/dist/hitl/gateLedger.d.ts +0 -4
- package/dist/hitl/gateLedger.js +0 -19
- package/dist/hitl/hitlBridge.d.ts +1 -0
- package/dist/hitl/hitlBridge.js +4 -4
- package/dist/hitl/hitlHostSurface.d.ts +1 -0
- package/dist/hitl/hitlHostSurface.js +7 -2
- package/dist/hitl/hostWithdrawal.d.ts +15 -0
- package/dist/hitl/hostWithdrawal.js +38 -0
- package/dist/hitl/parkResolver.js +25 -9
- package/dist/hitl/persistedRulesWire.js +2 -2
- package/dist/hitl/planReviewWire.js +14 -4
- package/dist/hitl/sessionPolicyWire.js +6 -4
- package/dist/hitl/standingRows.d.ts +1 -0
- package/dist/hitl/standingRows.js +15 -1
- package/dist/hitl/toolApprovalWire.d.ts +35 -8
- package/dist/hitl/toolApprovalWire.js +235 -33
- package/dist/hooksWireCaps.js +31 -1
- package/dist/hostTurnSettings.d.ts +10 -4
- package/dist/hostTurnSettings.js +112 -5
- package/dist/i18n/messages.en.d.ts +83 -0
- package/dist/i18n/messages.en.js +86 -2
- package/dist/i18n/messages.zh.js +96 -2
- package/dist/index.d.ts +21 -7
- package/dist/index.js +14 -4
- package/dist/inheritEnvCapability.js +2 -0
- package/dist/inputAuthor.d.ts +16 -0
- package/dist/inputAuthor.js +44 -0
- package/dist/interruptRefusalNote.d.ts +2 -0
- package/dist/interruptRefusalNote.js +17 -0
- package/dist/liveModelCatalog.d.ts +2 -0
- package/dist/liveModelCatalog.js +21 -7
- package/dist/liveQuestionStore.d.ts +4 -1
- package/dist/liveQuestionStore.js +12 -3
- 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 +121 -16
- package/dist/modelCapabilityProbe.js +4 -3
- package/dist/modsFace.d.ts +8 -1
- package/dist/modsFace.js +27 -0
- package/dist/notifications.d.ts +17 -6
- package/dist/notifications.js +67 -19
- package/dist/ownKey.d.ts +0 -5
- package/dist/ownKey.js +0 -7
- package/dist/peerFrames.d.ts +40 -2
- package/dist/peerFrames.js +158 -3
- package/dist/pluginHooksWire.d.ts +2 -1
- package/dist/pluginHooksWire.js +56 -1
- package/dist/replayBody.js +10 -2
- package/dist/request/taskRequest.d.ts +5 -0
- package/dist/request/taskRequest.js +138 -21
- 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/seam.d.ts +12 -1
- package/dist/seam.js +7 -1
- package/dist/seatContract.d.ts +86 -9
- package/dist/seatContract.js +196 -7
- package/dist/sessionBackground.js +2 -1
- package/dist/sessionBackgroundHandoff.js +2 -1
- package/dist/sessionEngine.d.ts +2 -0
- package/dist/sessionEngine.js +111 -0
- package/dist/sessionMemoryStatus.d.ts +2 -1
- package/dist/sessionSyncFileHistory.d.ts +4 -0
- package/dist/sessionSyncFileHistory.js +28 -0
- package/dist/sseIdleTriage.d.ts +13 -1
- package/dist/sseIdleTriage.js +24 -6
- package/dist/subagent/engineSubagentTail.js +6 -0
- package/dist/terminalStatuses.d.ts +1 -0
- package/dist/terminalStatuses.js +4 -1
- 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/wireFailureShape.d.ts +2 -5
- package/dist/wireFailureShape.js +10 -20
- package/dist/wireRefusalCopy.d.ts +10 -0
- package/dist/wireRefusalCopy.js +76 -0
- package/docs/INTEGRATION-CLIENTS.md +2126 -20
- package/package.json +3 -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
7
|
import { appendOwnElement, guardedRead, 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,22 +17,24 @@ 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, 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';
|
|
@@ -98,6 +100,16 @@ export function readApprovalDenySettledBy(decision) {
|
|
|
98
100
|
: undefined;
|
|
99
101
|
}
|
|
100
102
|
export const RETRACTED_CARD_DECISION_KIND = 'retracted';
|
|
103
|
+
export const WITHDRAWN_CARD_DECISION_KIND = 'withdrawn';
|
|
104
|
+
function withdrawnCardResolution(card, at, logTag) {
|
|
105
|
+
const w = hostWithdrawalOf(card);
|
|
106
|
+
if (w === undefined) {
|
|
107
|
+
hostLog('debug', `${logTag}: card-withdrawn-unreadable as=retracted`);
|
|
108
|
+
return { kind: 'not_sent', ...at, cause: 'retracted' };
|
|
109
|
+
}
|
|
110
|
+
hostLog('debug', `${logTag}: card-withdrawn-by-host verdict=${w.rowVerdict.kind}`);
|
|
111
|
+
return { kind: 'not_sent', ...at, cause: 'withdrawn', toldBy: w.toldBy, rowVerdict: w.rowVerdict };
|
|
112
|
+
}
|
|
101
113
|
function parkRowOf(taskId, row, gatedCallId) {
|
|
102
114
|
const d = parkRowDeadlineState(row, Date.now());
|
|
103
115
|
return Object.freeze({
|
|
@@ -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);
|
|
@@ -249,6 +271,14 @@ function cardInputOf(recorded, stream) {
|
|
|
249
271
|
return { from: 'stream', args: stream, shape };
|
|
250
272
|
return { from: 'none', shape, recorded };
|
|
251
273
|
}
|
|
274
|
+
function inputSourceBitOf(reading) {
|
|
275
|
+
return reading.from === 'recorded' ? { inputSource: 'record' } : reading.from === 'stream' ? { inputSource: 'stream' } : {};
|
|
276
|
+
}
|
|
277
|
+
function approvalInputSourceOf(card) {
|
|
278
|
+
const raw = ownDataValue(card, 'inputSource');
|
|
279
|
+
const known = { record: true, stream: true };
|
|
280
|
+
return typeof raw === 'string' && Object.hasOwn(known, raw) ? raw : undefined;
|
|
281
|
+
}
|
|
252
282
|
const CARD_ARGS_COMPARE_MAX_NODES = 20_000;
|
|
253
283
|
const CARD_ARGS_COMPARE_MAX_DEPTH = 256;
|
|
254
284
|
const NOT_COMPARABLE = Symbol('not comparable');
|
|
@@ -519,6 +549,7 @@ async function presentFsApprovalAndDecide(deps, taskId, argsByCall, signal, foun
|
|
|
519
549
|
: {}),
|
|
520
550
|
...(argsRewritten ? { argsRewritten: true, wireNote: ARGS_REWRITTEN_NOTE } : {}),
|
|
521
551
|
...(argsFromModelCall ? { argsUnavailable: true, wireNote: renderMessage(msg('approval.park.argsFromModelCall')) } : {}),
|
|
552
|
+
...inputSourceBitOf(reading),
|
|
522
553
|
...(pending.governanceForced === true ? { governanceForced: true } : {}),
|
|
523
554
|
...(readRequiresRealApproval(pending) ? { requiresRealApproval: true } : {}),
|
|
524
555
|
...approvalLiveFaceOf(pending).facts,
|
|
@@ -541,10 +572,12 @@ async function presentFsApprovalAndDecide(deps, taskId, argsByCall, signal, foun
|
|
|
541
572
|
allowSessionCarried: true,
|
|
542
573
|
grantBinding: readApprovalGrantBinding(pending),
|
|
543
574
|
parkRow: parkRowOf(taskId, pending, gatedCallId),
|
|
575
|
+
...(typeof taskId === 'string' && taskId !== '' ? { taskId } : {}),
|
|
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
583
|
return { kind: 'not_sent', ...at, cause: 'edit_refused', detail: PARK_EDIT_REFUSED_REASON };
|
|
@@ -558,6 +591,8 @@ 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
598
|
const cancelDeny = bridge.decideTool({ decision: 'deny', reason: INTERRUPT_DENY_REASON }, gatedCallId, undefined, pending);
|
|
@@ -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
|
+
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(park, '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,12 +950,30 @@ 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
973
|
const o = v;
|
|
974
|
+
const accepted = slotReadOf(o, 'accepted');
|
|
975
|
+
if (accepted.presence === 'present' && accepted.value === 'parked_redeemed')
|
|
976
|
+
return readParkedRedeemedAck(o);
|
|
861
977
|
if (o.idempotent === true)
|
|
862
978
|
return o.delivery === undefined ? readReplayedAck(o) : undefined;
|
|
863
979
|
if (o.delivery !== 'applied')
|
|
@@ -975,6 +1091,44 @@ function readReplayedAck(o) {
|
|
|
975
1091
|
...(o.rememberApplied === false ? { rememberApplied: false } : {}),
|
|
976
1092
|
};
|
|
977
1093
|
}
|
|
1094
|
+
function readParkedRedeemedAck(o) {
|
|
1095
|
+
if (slotReadOf(o, 'delivery').presence !== 'absent')
|
|
1096
|
+
return undefined;
|
|
1097
|
+
const text = (key) => {
|
|
1098
|
+
const slot = slotReadOf(o, key);
|
|
1099
|
+
return slot.presence === 'present' && typeof slot.value === 'string' && slot.value !== '' ? slot.value : undefined;
|
|
1100
|
+
};
|
|
1101
|
+
const approvalId = text('approvalId');
|
|
1102
|
+
const askId = text('askId');
|
|
1103
|
+
if (approvalId === undefined || askId === undefined)
|
|
1104
|
+
return undefined;
|
|
1105
|
+
const idem = slotReadOf(o, 'idempotent');
|
|
1106
|
+
if (idem.presence === 'unreadable')
|
|
1107
|
+
return undefined;
|
|
1108
|
+
const replay = idem.presence === 'present' && idem.value === true;
|
|
1109
|
+
const dec = slotReadOf(o, 'decision');
|
|
1110
|
+
let decision;
|
|
1111
|
+
if (replay) {
|
|
1112
|
+
if (dec.presence !== 'present' || (dec.value !== 'allow' && dec.value !== 'deny'))
|
|
1113
|
+
return undefined;
|
|
1114
|
+
decision = dec.value === 'allow' ? 'allow' : 'deny';
|
|
1115
|
+
}
|
|
1116
|
+
else {
|
|
1117
|
+
decision = dec.presence === 'present' && typeof dec.value === 'string' && dec.value !== '' ? dec.value : undefined;
|
|
1118
|
+
}
|
|
1119
|
+
const remember = slotReadOf(o, 'rememberApplied');
|
|
1120
|
+
return {
|
|
1121
|
+
approvalId,
|
|
1122
|
+
askId,
|
|
1123
|
+
accepted: 'parked_redeemed',
|
|
1124
|
+
...(replay ? { idempotent: true } : {}),
|
|
1125
|
+
...(decision !== undefined ? { decision } : {}),
|
|
1126
|
+
...(remember.presence === 'present' && typeof remember.value === 'boolean' ? { rememberApplied: remember.value } : {}),
|
|
1127
|
+
};
|
|
1128
|
+
}
|
|
1129
|
+
function replayedDecisionOf(first, sent, ack) {
|
|
1130
|
+
return { kind: 'decided', lane: 'respond', decision: first, ...(ack !== undefined ? { ack } : {}), settledElsewhere: toolPermissionSettledElsewhereOf(first, sent) };
|
|
1131
|
+
}
|
|
978
1132
|
function isNonEmptyStringArray(v) {
|
|
979
1133
|
return Array.isArray(v) && v.length > 0 && v.every(x => typeof x === 'string' && x !== '');
|
|
980
1134
|
}
|
|
@@ -1080,19 +1234,44 @@ function readProbeReason(v) {
|
|
|
1080
1234
|
function usableProbeReason(raw) {
|
|
1081
1235
|
return typeof raw === 'string' && raw.trim() !== '' ? raw : undefined;
|
|
1082
1236
|
}
|
|
1237
|
+
function probeFactsAt(at) {
|
|
1238
|
+
const prose = usableProbeReason(ownDataValue(at, 'probeReason'));
|
|
1239
|
+
let cause;
|
|
1240
|
+
try {
|
|
1241
|
+
const raw = ownDataValue(at, 'probeCause');
|
|
1242
|
+
if (isWireRecordCarrier(raw))
|
|
1243
|
+
cause = raw;
|
|
1244
|
+
}
|
|
1245
|
+
catch {
|
|
1246
|
+
cause = undefined;
|
|
1247
|
+
}
|
|
1248
|
+
return { prose, cause };
|
|
1249
|
+
}
|
|
1250
|
+
function probeCarrierOf(carrier) {
|
|
1251
|
+
let d;
|
|
1252
|
+
try {
|
|
1253
|
+
d = Object.getOwnPropertyDescriptor(carrier, 'riskDescriptor');
|
|
1254
|
+
}
|
|
1255
|
+
catch {
|
|
1256
|
+
return undefined;
|
|
1257
|
+
}
|
|
1258
|
+
if (d === undefined)
|
|
1259
|
+
return carrier;
|
|
1260
|
+
return Object.hasOwn(d, 'value') ? d.value : undefined;
|
|
1261
|
+
}
|
|
1083
1262
|
const PROBE_CAUSE_CODE_WORD = /^[a-z][a-z0-9_]{0,31}(?:\.[a-z][a-z0-9_]{0,31}){1,3}$/;
|
|
1084
1263
|
export function askProbeReasonDetail(card, lang) {
|
|
1085
|
-
const prose =
|
|
1264
|
+
const { prose, cause } = probeFactsAt(card);
|
|
1086
1265
|
const shown = prose === undefined ? '' : displayUntrusted(prose);
|
|
1087
|
-
const sentence = probeCauseSentence(
|
|
1266
|
+
const sentence = probeCauseSentence(cause, shown !== '', lang);
|
|
1088
1267
|
if (sentence === undefined)
|
|
1089
1268
|
return shown === '' ? undefined : shown;
|
|
1090
1269
|
return shown === '' ? sentence : renderMessage(msg('approval.probe.proseJoin', { sentence, prose: shown }), lang);
|
|
1091
1270
|
}
|
|
1092
1271
|
function probeCauseSentence(cause, withProse, lang) {
|
|
1272
|
+
if (cause === undefined)
|
|
1273
|
+
return undefined;
|
|
1093
1274
|
try {
|
|
1094
|
-
if (!isWireRecordCarrier(cause))
|
|
1095
|
-
return undefined;
|
|
1096
1275
|
const code = ownDataValue(cause, 'code');
|
|
1097
1276
|
const withCode = typeof code === 'string' && PROBE_CAUSE_CODE_WORD.test(code);
|
|
1098
1277
|
const key = withProse
|
|
@@ -1713,12 +1892,14 @@ function cardFactsOf(carrier, leg, opts, liveFacts, approvalId, payloadWhy) {
|
|
|
1713
1892
|
if (reading.from === 'recorded') {
|
|
1714
1893
|
if (blind)
|
|
1715
1894
|
return { args: reading.args, argsUnavailable: true };
|
|
1716
|
-
return reading.rewritten
|
|
1895
|
+
return reading.rewritten
|
|
1896
|
+
? { args: reading.args, argsRewritten: true, wireNote: ARGS_REWRITTEN_NOTE, ...inputSourceBitOf(reading) }
|
|
1897
|
+
: { args: reading.args, ...inputSourceBitOf(reading) };
|
|
1717
1898
|
}
|
|
1718
1899
|
if (reading.from === 'stream' && typeof reading.args === 'object' && reading.args !== null) {
|
|
1719
1900
|
if (blind)
|
|
1720
1901
|
return { args: reading.args, argsUnavailable: true };
|
|
1721
|
-
return { args: reading.args, wireNote: ARGS_FROM_MODEL_CALL_NOTE };
|
|
1902
|
+
return { args: reading.args, wireNote: ARGS_FROM_MODEL_CALL_NOTE, ...inputSourceBitOf(reading) };
|
|
1722
1903
|
}
|
|
1723
1904
|
const omitted = c.argsOmitted === true || reading.shape === 'size_marker';
|
|
1724
1905
|
const fallback = argsFallbackOf(c.message, omitted);
|
|
@@ -1749,6 +1930,8 @@ function cardFactsOf(carrier, leg, opts, liveFacts, approvalId, payloadWhy) {
|
|
|
1749
1930
|
out.argsUnavailable = true;
|
|
1750
1931
|
if (argsPart.argsRewritten === true)
|
|
1751
1932
|
out.argsRewritten = true;
|
|
1933
|
+
if (argsPart.inputSource !== undefined)
|
|
1934
|
+
out.inputSource = argsPart.inputSource;
|
|
1752
1935
|
if (full) {
|
|
1753
1936
|
v1Bit(() => {
|
|
1754
1937
|
if (c.governanceForced === true)
|
|
@@ -1784,6 +1967,11 @@ function cardFactsOf(carrier, leg, opts, liveFacts, approvalId, payloadWhy) {
|
|
|
1784
1967
|
if (r !== undefined)
|
|
1785
1968
|
out.probeReason = r;
|
|
1786
1969
|
});
|
|
1970
|
+
v1Bit(() => {
|
|
1971
|
+
const by = approvalRequestedByOf(live);
|
|
1972
|
+
if (by !== undefined)
|
|
1973
|
+
out.requestedBy = by;
|
|
1974
|
+
});
|
|
1787
1975
|
}
|
|
1788
1976
|
v1Bit(() => {
|
|
1789
1977
|
if (readApprovalRememberRefused(carrier))
|
|
@@ -1928,7 +2116,8 @@ export async function surfaceApprovalFrameWithId(frame, approvalId, respond, str
|
|
|
1928
2116
|
if (typeof approvalId !== 'string' || approvalId === '')
|
|
1929
2117
|
return approvalIdUnreadableRefusal();
|
|
1930
2118
|
const carriers = openingFrameCarriersOf(frame);
|
|
1931
|
-
const
|
|
2119
|
+
const liveRun = liveCardRunOf(frame, run);
|
|
2120
|
+
const entry = { frame, carriers, approvalId, identity: liveCardIdentityOf(approvalId, carriers, liveRun), respond, streamArgs, signal, lane, receivedAtMs };
|
|
1932
2121
|
return enterLiveCard(entry);
|
|
1933
2122
|
}
|
|
1934
2123
|
function openingFrameCarriersOf(frame) {
|
|
@@ -1954,7 +2143,7 @@ function enterLiveCard(e) {
|
|
|
1954
2143
|
return joinOtherLaneHolder(e, other);
|
|
1955
2144
|
return holdLiveCard(e.identity, signal, async (hold) => {
|
|
1956
2145
|
const slot = {};
|
|
1957
|
-
const out = await presentToolApprovalFrameAndRespond(e.frame, e.carriers, approvalId, e.respond, e.streamArgs, signal, e.lane, hold, slot, e.receivedAtMs);
|
|
2146
|
+
const out = await presentToolApprovalFrameAndRespond(e.frame, e.carriers, approvalId, e.respond, e.streamArgs, signal, e.lane, hold, slot, e.receivedAtMs, e.identity.taskId);
|
|
1958
2147
|
noteCallOutcome(slot, out);
|
|
1959
2148
|
return out;
|
|
1960
2149
|
});
|
|
@@ -1969,15 +2158,20 @@ async function joinOtherLaneHolder(e, other) {
|
|
|
1969
2158
|
return { kind: 'not_sent', lane: 'respond', cause: 'retracted', joinedInFlight: true };
|
|
1970
2159
|
return enterLiveCard(e);
|
|
1971
2160
|
}
|
|
1972
|
-
function
|
|
2161
|
+
function liveCardRunOf(frame, run) {
|
|
2162
|
+
const source = frameBindingOf(frame) ?? run;
|
|
2163
|
+
return {
|
|
2164
|
+
taskId: guardedRead(() => readOwnDataNonEmptyString(source, 'taskId')),
|
|
2165
|
+
sessionId: guardedRead(() => readOwnDataNonEmptyString(source, 'sessionId')),
|
|
2166
|
+
};
|
|
2167
|
+
}
|
|
2168
|
+
function liveCardIdentityOf(approvalId, carriers, liveRun) {
|
|
1973
2169
|
const body = carriers.body;
|
|
1974
2170
|
const toolCallId = typeof body.toolCallId === 'string' && body.toolCallId !== '' ? body.toolCallId : undefined;
|
|
1975
2171
|
const fromSubagent = isFromSubagent(carriers.body);
|
|
1976
|
-
const
|
|
1977
|
-
const source = bound ?? run;
|
|
1978
|
-
const ownRun = fromSubagent ? subagentSourceSessionOf(carriers.body) : source?.taskId;
|
|
2172
|
+
const ownRun = fromSubagent ? subagentSourceSessionOf(carriers.body) : liveRun.taskId;
|
|
1979
2173
|
const taskId = typeof ownRun === 'string' && ownRun !== '' ? ownRun : undefined;
|
|
1980
|
-
const sessionId =
|
|
2174
|
+
const sessionId = fromSubagent ? undefined : liveRun.sessionId;
|
|
1981
2175
|
const askSig = carrierAskSig(carriers.body, carriers.live);
|
|
1982
2176
|
return {
|
|
1983
2177
|
approvalId,
|
|
@@ -2033,12 +2227,13 @@ function readApprovalCardClaimSignal(v) {
|
|
|
2033
2227
|
export function claimApprovalCard(identity, options) {
|
|
2034
2228
|
return claimApprovalCardFor(readApprovalHolderIdentity(identity), readApprovalCardClaimSignal(options));
|
|
2035
2229
|
}
|
|
2036
|
-
async function presentToolApprovalFrameAndRespond(frame, carriers, approvalId, respond, streamArgs, signal, lane, hold, ledgerSlot, receivedAtMs) {
|
|
2230
|
+
async function presentToolApprovalFrameAndRespond(frame, carriers, approvalId, respond, streamArgs, signal, lane, hold, ledgerSlot, receivedAtMs, cardTaskId) {
|
|
2037
2231
|
const bodyToolCallId = carriers.body.toolCallId;
|
|
2038
2232
|
const frameToolCallId = typeof bodyToolCallId === 'string' && bodyToolCallId !== '' ? bodyToolCallId : undefined;
|
|
2039
2233
|
const decidedByReading = decidedByReadingSnapshotOf(lane);
|
|
2040
2234
|
const facts = cardFactsOf(carriers.body, carriers.leg, { streamArgs, ...(lane?.argsUnavailable === true ? { argsUnavailable: true } : {}) }, carriers.live, approvalId, carriers.why);
|
|
2041
2235
|
const argsNotRealInput = facts.argsUnavailable === true;
|
|
2236
|
+
const editAcceptance = editedApprovalAcceptanceOf(facts);
|
|
2042
2237
|
const ruleOffers = facts.ruleOffers;
|
|
2043
2238
|
if (argsNotRealInput && lane?.argsUnavailable !== true && facts.wireNote !== undefined) {
|
|
2044
2239
|
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)'}`);
|
|
@@ -2046,6 +2241,7 @@ async function presentToolApprovalFrameAndRespond(frame, carriers, approvalId, r
|
|
|
2046
2241
|
const card = await surfaceCallTrackedCard(frameToolCallId, approvalId, ledgerSlot, {
|
|
2047
2242
|
...facts,
|
|
2048
2243
|
callKey: liveFrameCallKey(approvalId),
|
|
2244
|
+
...(cardTaskId !== undefined ? { taskId: cardTaskId } : {}),
|
|
2049
2245
|
signal: hold.cardSignal,
|
|
2050
2246
|
...approvalWindowKeysOf(frame, { windowIsCurrent: lane?.windowIsCurrent === true, receivedAtMs, ...(carriers.leg === 'generic' ? { unknownShape: true } : {}) }),
|
|
2051
2247
|
});
|
|
@@ -2056,11 +2252,13 @@ async function presentToolApprovalFrameAndRespond(frame, carriers, approvalId, r
|
|
|
2056
2252
|
surfaceApprovalParking();
|
|
2057
2253
|
return { kind: 'not_sent', lane: 'respond', cause: 'retracted' };
|
|
2058
2254
|
}
|
|
2059
|
-
if (
|
|
2255
|
+
if (editAcceptance.state !== 'accepts' && card.kind === 'allow' && card.updatedInput !== undefined) {
|
|
2060
2256
|
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
2257
|
surfaceEditRefusedOnBlindAsk();
|
|
2062
2258
|
return { kind: 'not_sent', lane: 'respond', cause: 'edit_refused' };
|
|
2063
2259
|
}
|
|
2260
|
+
if (card.kind === WITHDRAWN_CARD_DECISION_KIND)
|
|
2261
|
+
return withdrawnCardResolution(card, { lane: 'respond' }, 'liveToolApprovalWire');
|
|
2064
2262
|
if (card.kind === RETRACTED_CARD_DECISION_KIND) {
|
|
2065
2263
|
hostLog('debug', `liveToolApprovalWire: ${approvalId} card retracted without a decision${card.reason ? ` (${card.reason})` : ''} — nothing sent`);
|
|
2066
2264
|
return { kind: 'not_sent', lane: 'respond', cause: 'retracted' };
|
|
@@ -2094,8 +2292,10 @@ async function presentToolApprovalFrameAndRespond(frame, carriers, approvalId, r
|
|
|
2094
2292
|
: card;
|
|
2095
2293
|
const basePayload = answerPayloadFor(answerSnapshot, 'respond', { approvalDecisionNoteCapable: noteCapable });
|
|
2096
2294
|
const decision = basePayload?.decision ?? 'deny';
|
|
2097
|
-
|
|
2098
|
-
|
|
2295
|
+
const allowNoteText = decision !== 'deny' ? allowNoteReadingOf(answerSnapshot) : { kind: 'absent' };
|
|
2296
|
+
const allowNoteDropped = allowNoteText.kind === 'text' && answerCarriage({ callKey: liveFrameCallKey(approvalId) }).allowNote === 'none';
|
|
2297
|
+
if (allowNoteDropped && allowNoteText.kind === 'text') {
|
|
2298
|
+
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
2299
|
}
|
|
2100
2300
|
const denySettledByForWire = card.kind === 'deny' ? readApprovalDenySettledBy(card) : undefined;
|
|
2101
2301
|
const denyPolicyCauseForWire = card.kind === 'deny' ? readPolicyDenyCause(card) : undefined;
|
|
@@ -2249,15 +2449,15 @@ async function presentToolApprovalFrameAndRespond(frame, carriers, approvalId, r
|
|
|
2249
2449
|
'reporting the answer as NOT settled (never as decided, never as parked); not re-sent');
|
|
2250
2450
|
return { kind: 'unsettled', lane: 'respond', cause: 'unreadable' };
|
|
2251
2451
|
}
|
|
2252
|
-
const parsed = readToolApprovalRespondAck(raw);
|
|
2452
|
+
const parsed = settlementAckOf(readToolApprovalRespondAck(raw));
|
|
2253
2453
|
const replayedForThisCard = parsed !== undefined && isToolApprovalRespondReplayed(parsed) && parsed.approvalId === approvalId;
|
|
2254
|
-
const claimsReplay = ownIdempotentTrue(raw) || (parsed !== undefined
|
|
2454
|
+
const claimsReplay = ownIdempotentTrue(raw) || replayedFirstDecisionOf(parsed) !== undefined;
|
|
2255
2455
|
if (claimsReplay && !replayedForThisCard) {
|
|
2256
2456
|
const claimed = replayClaimOf(raw);
|
|
2257
2457
|
if (claimed.approvalId === approvalId && claimed.decision !== undefined && !claimed.carriesDelivery) {
|
|
2258
2458
|
hostLog('debug', `liveToolApprovalWire: respond(${decision}) for ${approvalId} answered with a replay (body not in the full replay shape) — the approval was already decided ` +
|
|
2259
2459
|
`(${claimed.decision}); this answer was not delivered, reporting the earlier decision`);
|
|
2260
|
-
return
|
|
2460
|
+
return replayedDecisionOf(claimed.decision, decision, parsed !== undefined && isToolApprovalRespondParkedRedeemed(parsed) && parsed.approvalId === approvalId ? parsed : undefined);
|
|
2261
2461
|
}
|
|
2262
2462
|
hostLog('error', `liveToolApprovalWire: respond(${decision}) for ${approvalId} answered with a replay of an earlier decision that cannot be read or names another approval — ` +
|
|
2263
2463
|
'reporting the answer as NOT settled (never as the decision this client sent); not re-sent');
|
|
@@ -2327,6 +2527,8 @@ async function presentToolApprovalFrameAndRespond(frame, carriers, approvalId, r
|
|
|
2327
2527
|
}
|
|
2328
2528
|
if (replayed === undefined && sessionDowngraded)
|
|
2329
2529
|
surfaceRememberNotApplied();
|
|
2530
|
+
if (replayed === undefined && allowNoteDropped)
|
|
2531
|
+
surfaceAllowNoteNotCarried(allowNoteNotCarriedSentence());
|
|
2330
2532
|
if (respondOpts.updatedInput !== undefined && applied?.updatedInputForwarded === false) {
|
|
2331
2533
|
logAfterDecided(`liveToolApprovalWire: ${approvalId} edited args were NOT forwarded (ack.updatedInputForwarded=false) — the tool runs on the ORIGINAL input`);
|
|
2332
2534
|
surfaceEditNotForwarded();
|
|
@@ -2338,7 +2540,7 @@ async function presentToolApprovalFrameAndRespond(frame, carriers, approvalId, r
|
|
|
2338
2540
|
if (replayed !== undefined) {
|
|
2339
2541
|
hostLog('debug', `liveToolApprovalWire: respond(${decision}) for ${approvalId} answered with a replay — the approval was already decided (${replayed.decision}); ` +
|
|
2340
2542
|
'this answer was not delivered, reporting the earlier decision');
|
|
2341
|
-
return
|
|
2543
|
+
return replayedDecisionOf(replayed.decision, decision, replayed);
|
|
2342
2544
|
}
|
|
2343
2545
|
const deny = decision === 'deny' ? denyFactsOf(denySettledByForWire, denyReasonSnapshot, attributionDropped, attributionRenamed, denyPolicyCauseForWire) : undefined;
|
|
2344
2546
|
return { kind: 'decided', lane: 'respond', decision, ...(ack !== undefined ? { ack } : {}), ...(deny !== undefined ? { deny } : {}) };
|
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, occupancyOf, } from './pluginHooksWire.js';
|
|
12
|
+
import { createSettingsHookJudge, decidePluginHooks, decideSessionHooks, dedupeSettingsHookGroups, filterSettingsHookGroups, hooksWirePlanShapeOf, 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';
|
|
@@ -300,6 +300,32 @@ function withheldRowsOf(candidates, trust, layers) {
|
|
|
300
300
|
}
|
|
301
301
|
return rows;
|
|
302
302
|
}
|
|
303
|
+
function closedDropRowsOf(source, doc, reason) {
|
|
304
|
+
const rows = [];
|
|
305
|
+
try {
|
|
306
|
+
const hooks = readOwnDataValue(doc, 'hooks');
|
|
307
|
+
if (typeof hooks !== 'object' || hooks === null || Array.isArray(hooks))
|
|
308
|
+
return rows;
|
|
309
|
+
for (const event of Object.keys(hooks)) {
|
|
310
|
+
const groups = readOwnDataValue(hooks, event);
|
|
311
|
+
if (!Array.isArray(groups))
|
|
312
|
+
continue;
|
|
313
|
+
groups.forEach((group, groupIndex) => {
|
|
314
|
+
if (typeof group !== 'object' || group === null)
|
|
315
|
+
return;
|
|
316
|
+
const entries = readOwnDataValue(group, 'hooks');
|
|
317
|
+
if (!Array.isArray(entries))
|
|
318
|
+
return;
|
|
319
|
+
entries.forEach((_entry, hookIndex) => {
|
|
320
|
+
rows.push({ source, event, groupIndex, hookIndex, reason, notRun: true });
|
|
321
|
+
});
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
catch {
|
|
326
|
+
}
|
|
327
|
+
return rows;
|
|
328
|
+
}
|
|
303
329
|
function buildHooksWirePlan(read, engine, shellRuns, promptAuthoredByUser, suppressedLocally, readerNotRead, compactionOnShell = false) {
|
|
304
330
|
const settingsDropped = [];
|
|
305
331
|
const settingsVerdicts = [];
|
|
@@ -333,6 +359,8 @@ function buildHooksWirePlan(read, engine, shellRuns, promptAuthoredByUser, suppr
|
|
|
333
359
|
});
|
|
334
360
|
const closedPlan = (reason) => {
|
|
335
361
|
closedBy = reason;
|
|
362
|
+
for (const source of ALL_HOOK_SOURCES)
|
|
363
|
+
settingsDropped.push(...closedDropRowsOf(source, read.layers[source].doc, reason));
|
|
336
364
|
sessionReader = read.sessionHooks.state;
|
|
337
365
|
const pr = read.plugins;
|
|
338
366
|
if (pr.reading === undefined)
|
|
@@ -472,6 +500,8 @@ function buildHooksWirePlan(read, engine, shellRuns, promptAuthoredByUser, suppr
|
|
|
472
500
|
settingsDropped.push(...kept.drops);
|
|
473
501
|
settingsVerdicts.push(...kept.verdicts);
|
|
474
502
|
settingsExcluded.push(...kept.excluded);
|
|
503
|
+
if (!isEngineFiredHookEvent(event))
|
|
504
|
+
continue;
|
|
475
505
|
settingsStripped += kept.stripped;
|
|
476
506
|
if (kept.groups.length === 0)
|
|
477
507
|
continue;
|