@sema-agent/client-core 0.108.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 +294 -0
- package/README.md +77 -40
- package/dist/adapt/arms.js +41 -13
- package/dist/adapt/textStream.d.ts +2 -0
- package/dist/adapt/textStream.js +37 -16
- package/dist/adapter/activeRunSelfHeal.js +1 -1
- package/dist/adapter/downstream/eventToSdkMessage.js +11 -5
- package/dist/agentSession/engineAgentRegistryRead.js +2 -0
- package/dist/bashExitReading.d.ts +12 -0
- package/dist/bashExitReading.js +44 -0
- package/dist/checkpointRowVerdict.d.ts +1 -1
- package/dist/checkpointRowVerdict.js +4 -2
- package/dist/compensations.js +1 -1
- package/dist/declared/supportFloorDeclared.js +1 -1
- package/dist/displayUntrusted.js +132 -14
- package/dist/engineAgentAbsence.d.ts +2 -0
- package/dist/engineAgentAbsence.js +28 -0
- package/dist/engineErrorCodes.d.ts +7 -0
- package/dist/engineErrorCodes.js +7 -0
- package/dist/engineHealthFacts.d.ts +26 -0
- package/dist/engineHealthFacts.js +63 -4
- package/dist/engineInlineTaskStats.d.ts +4 -3
- package/dist/engineInlineTaskStats.js +18 -2
- package/dist/engineNoticeCodes.d.ts +138 -0
- package/dist/engineNoticeCodes.js +662 -55
- 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 +5 -1
- package/dist/fleet/fleetProjection.js +3 -2
- package/dist/fleetTaskDesc.js +3 -3
- package/dist/generated/engineFactTables.d.ts +3 -0
- package/dist/generated/engineFactTables.js +18 -0
- package/dist/generated/engineNoticeTables.js +3 -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 +25 -4
- package/dist/hitl/approvalRequestFrameReading.d.ts +21 -0
- package/dist/hitl/approvalRequestFrameReading.js +90 -0
- package/dist/hitl/approvalResolution.d.ts +8 -1
- package/dist/hitl/approvalResolution.js +4 -0
- package/dist/hitl/approvalsFeed.js +1 -1
- package/dist/hitl/askGateWire.js +0 -2
- package/dist/hitl/askParkRowRouting.js +5 -2
- package/dist/hitl/automaticAnswerVerdict.d.ts +5 -2
- package/dist/hitl/automaticAnswerVerdict.js +18 -4
- package/dist/hitl/decisionConflict.d.ts +2 -1
- package/dist/hitl/decisionConflict.js +10 -4
- 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 +13 -19
- package/dist/hitl/gateLedger.d.ts +0 -4
- package/dist/hitl/gateLedger.js +0 -19
- package/dist/hitl/hitlBridge.d.ts +5 -0
- package/dist/hitl/hitlBridge.js +13 -9
- 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/livePendingAsk.js +17 -16
- package/dist/hitl/localAllowRule.js +2 -1
- package/dist/hitl/noAllowCause.d.ts +1 -1
- package/dist/hitl/noAllowCause.js +4 -2
- package/dist/hitl/parkExpiryJudgements.js +26 -1
- package/dist/hitl/parkOwnership.d.ts +2 -0
- package/dist/hitl/parkOwnership.js +48 -8
- package/dist/hitl/parkResolver.js +32 -16
- package/dist/hitl/parkedUnresumable.d.ts +13 -0
- package/dist/hitl/parkedUnresumable.js +80 -0
- package/dist/hitl/permissionRuleScope.d.ts +4 -0
- package/dist/hitl/permissionRuleScope.js +31 -0
- package/dist/hitl/persistedRulesWire.d.ts +2 -0
- package/dist/hitl/persistedRulesWire.js +13 -12
- package/dist/hitl/planReviewWire.js +14 -4
- package/dist/hitl/sessionAllowRoute.js +5 -4
- package/dist/hitl/sessionPolicyWire.js +6 -4
- package/dist/hitl/standingRows.d.ts +2 -5
- package/dist/hitl/standingRows.js +30 -15
- package/dist/hitl/toolApprovalWire.d.ts +42 -9
- package/dist/hitl/toolApprovalWire.js +267 -44
- package/dist/hooksWireCaps.js +35 -4
- package/dist/hostSettingsSource.js +2 -0
- package/dist/hostTurnSettings.d.ts +10 -4
- package/dist/hostTurnSettings.js +112 -5
- package/dist/i18n/messages.en.d.ts +251 -0
- package/dist/i18n/messages.en.js +254 -2
- package/dist/i18n/messages.zh.js +264 -2
- package/dist/index.d.ts +48 -12
- package/dist/index.js +29 -7
- 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/localEngineJudge.d.ts +75 -0
- package/dist/localEngineJudge.js +242 -0
- package/dist/localEngineOccupancy.d.ts +88 -0
- package/dist/localEngineOccupancy.js +269 -0
- package/dist/localEngineSeatReading.d.ts +29 -0
- package/dist/localEngineSeatReading.js +294 -0
- package/dist/localEngineSpawn.d.ts +113 -0
- package/dist/localEngineSpawn.js +486 -0
- package/dist/localEngineStep.d.ts +286 -0
- package/dist/localEngineStep.js +1086 -0
- package/dist/localEngineStopLadder.d.ts +29 -0
- package/dist/localEngineStopLadder.js +139 -0
- package/dist/localEngineSwapCard.d.ts +43 -0
- package/dist/localEngineSwapCard.js +205 -0
- package/dist/localEngineTiming.d.ts +8 -0
- package/dist/localEngineTiming.js +8 -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 +132 -20
- package/dist/mcpWireCaps.js +2 -2
- package/dist/memoryEntriesWire.d.ts +1 -1
- package/dist/memoryEntriesWire.js +5 -0
- package/dist/modelCapabilityProbe.js +4 -3
- package/dist/modsFace.d.ts +8 -1
- package/dist/modsFace.js +27 -0
- package/dist/noticePresentation.d.ts +2 -0
- package/dist/noticePresentation.js +79 -1
- package/dist/notifications.d.ts +17 -6
- package/dist/notifications.js +67 -19
- package/dist/ownKey.d.ts +5 -0
- package/dist/ownKey.js +8 -1
- 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/ruleReadings.js +1 -1
- package/dist/seam.d.ts +24 -2
- package/dist/seam.js +15 -2
- package/dist/seatContract.d.ts +125 -10
- package/dist/seatContract.js +373 -7
- package/dist/sessionBackground.js +4 -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/subagentContentStore.d.ts +12 -0
- package/dist/subagentContentStore.js +72 -11
- package/dist/terminalStatuses.d.ts +1 -0
- package/dist/terminalStatuses.js +4 -1
- package/dist/toolResult.js +18 -5
- 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 +22 -5
- package/dist/wireFailureShape.js +47 -26
- package/dist/wireRefusalCopy.d.ts +31 -1
- package/dist/wireRefusalCopy.js +167 -2
- package/docs/INTEGRATION-CLIENTS.md +3269 -21
- package/package.json +5 -5
|
@@ -2,7 +2,9 @@ import { displayUntrusted } from '../displayUntrusted.js';
|
|
|
2
2
|
import { msg, renderMessage } from '../i18n/translate.js';
|
|
3
3
|
import { approvalMandateDetail, askOriginNoteOf } from '../gateVocabulary.js';
|
|
4
4
|
import { readAskOrigin, readOwnDataValue, guardedRead } from '../ownKey.js';
|
|
5
|
+
import { elideMiddleForDisplay } from '../noticePresentation.js';
|
|
5
6
|
import { allowRuleShadowSentence } from './allowRuleShadow.js';
|
|
7
|
+
import { cardPayloadReadingOf } from './approvalRequestFrameReading.js';
|
|
6
8
|
import { mandatedApprovalDetailOf } from './automaticAnswerVerdict.js';
|
|
7
9
|
import { approvalBoundGrantsDetail, approvalIsMandated, approvalPriorCardsDetail, askProbeReasonDetail, classifierNoRulingDetail, readApprovalBoundGrants, readApprovalClassifierNoRuling, readApprovalMandate, readDenialLimitFallback, } from './toolApprovalWire.js';
|
|
8
10
|
export const APPROVAL_CARD_REASON_SOURCES = Object.freeze([
|
|
@@ -21,8 +23,24 @@ export const APPROVAL_CARD_REASON_SOURCES = Object.freeze([
|
|
|
21
23
|
]);
|
|
22
24
|
export const APPROVAL_CARD_REASONS_DEFAULT_MAX_LINES = 4;
|
|
23
25
|
const MESSAGE_DISPLAY_MAX = 300;
|
|
24
|
-
function
|
|
25
|
-
|
|
26
|
+
function engineMessageLine(engineMessage) {
|
|
27
|
+
const shown = displayUntrusted(engineMessage);
|
|
28
|
+
if (shown.length <= MESSAGE_DISPLAY_MAX)
|
|
29
|
+
return shown;
|
|
30
|
+
const settled = displayUntrusted(elideMiddleForDisplay(shown, MESSAGE_DISPLAY_MAX));
|
|
31
|
+
return settled.length <= MESSAGE_DISPLAY_MAX ? settled : displayUntrusted(engineMessage, { max: MESSAGE_DISPLAY_MAX });
|
|
32
|
+
}
|
|
33
|
+
function payloadUnreadableDetail(why, lang) {
|
|
34
|
+
switch (why) {
|
|
35
|
+
case 'version_unknown':
|
|
36
|
+
return renderMessage(msg('approval.card.payloadUnreadable.versionUnknown'), lang);
|
|
37
|
+
case 'kind_unknown':
|
|
38
|
+
return renderMessage(msg('approval.card.payloadUnreadable.partUnknown'), lang);
|
|
39
|
+
case 'unreadable_fields':
|
|
40
|
+
return renderMessage(msg('approval.card.payloadUnreadable.fieldsMalformed'), lang);
|
|
41
|
+
default:
|
|
42
|
+
return renderMessage(msg('approval.card.payloadUnreadable'), lang);
|
|
43
|
+
}
|
|
26
44
|
}
|
|
27
45
|
function moreDetail(n, lang) {
|
|
28
46
|
return renderMessage(n === 1 ? msg('approval.card.more.one') : msg('approval.card.more.other', { count: n }), lang);
|
|
@@ -64,7 +82,10 @@ export function approvalCardReasons(card, opts, lang) {
|
|
|
64
82
|
catch {
|
|
65
83
|
denialLimitReadable = false;
|
|
66
84
|
}
|
|
67
|
-
add('payload_unreadable', () =>
|
|
85
|
+
add('payload_unreadable', () => {
|
|
86
|
+
const reading = cardPayloadReadingOf(card);
|
|
87
|
+
return reading.payloadUnreadable ? payloadUnreadableDetail(reading.why, lang) : undefined;
|
|
88
|
+
});
|
|
68
89
|
add('prior_cards', () => approvalPriorCardsDetail(card, lang));
|
|
69
90
|
add('message', () => {
|
|
70
91
|
const engineMessage = ownData(card, 'message');
|
|
@@ -73,7 +94,7 @@ export function approvalCardReasons(card, opts, lang) {
|
|
|
73
94
|
const tool = ownData(card, 'toolName');
|
|
74
95
|
if (typeof tool === 'string' && engineMessage.trim() === `approval required for "${tool}"`)
|
|
75
96
|
return undefined;
|
|
76
|
-
return
|
|
97
|
+
return engineMessageLine(engineMessage);
|
|
77
98
|
});
|
|
78
99
|
add('mandated', () => (approvalIsMandated(card) ? mandatedApprovalDetailOf(card, lang) : undefined));
|
|
79
100
|
add('mandate', () => {
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare const APPROVAL_REQUEST_FRAME_UNREADABLE_WHYS: readonly ["version_unknown", "kind_unknown", "unreadable_fields"];
|
|
2
|
+
export type ApprovalRequestFrameUnreadableWhy = (typeof APPROVAL_REQUEST_FRAME_UNREADABLE_WHYS)[number];
|
|
3
|
+
export type ApprovalRequestFrameReading = {
|
|
4
|
+
readonly v1: true;
|
|
5
|
+
} | {
|
|
6
|
+
readonly v1: false;
|
|
7
|
+
readonly why: ApprovalRequestFrameUnreadableWhy;
|
|
8
|
+
readonly schemaVersion?: string;
|
|
9
|
+
readonly kind?: string;
|
|
10
|
+
};
|
|
11
|
+
export declare function approvalRequestFrameReadingThrowing(frame: object | null | undefined): ApprovalRequestFrameReading;
|
|
12
|
+
export declare function approvalRequestFrameReadingOf(frame: object | null | undefined): ApprovalRequestFrameReading;
|
|
13
|
+
export declare function approvalUnreadableWhyWordOf(v: string): ApprovalRequestFrameUnreadableWhy | undefined;
|
|
14
|
+
export type CardPayloadReading = {
|
|
15
|
+
readonly payloadUnreadable: false;
|
|
16
|
+
} | {
|
|
17
|
+
readonly payloadUnreadable: true;
|
|
18
|
+
readonly why?: ApprovalRequestFrameUnreadableWhy;
|
|
19
|
+
};
|
|
20
|
+
export declare function cardPayloadReadingOf(card: object | null | undefined): CardPayloadReading;
|
|
21
|
+
export declare function approvalFrameUnreadableWhyOf(reading: ApprovalRequestFrameReading | null | undefined): ApprovalRequestFrameUnreadableWhy | undefined;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { isApprovalRequestFrameV1 } from '@sema-agent/sdk';
|
|
2
|
+
import { displayUntrusted } from '../displayUntrusted.js';
|
|
3
|
+
import { guardedRead, readOwnDataValue } from '../ownKey.js';
|
|
4
|
+
export const APPROVAL_REQUEST_FRAME_UNREADABLE_WHYS = Object.freeze(['version_unknown', 'kind_unknown', 'unreadable_fields']);
|
|
5
|
+
const KNOWN_FRAME_TYPE = 'approval_request';
|
|
6
|
+
const KNOWN_SCHEMA_VERSION = 1;
|
|
7
|
+
const KNOWN_KIND = 'permission';
|
|
8
|
+
const FRAME_READING_VALUE_MAX = 24;
|
|
9
|
+
const FRAME_READING_VALUE_PREFIX = 128;
|
|
10
|
+
const V1_READING = Object.freeze({ v1: true });
|
|
11
|
+
const UNREADABLE_READING = Object.freeze({ v1: false, why: 'unreadable_fields' });
|
|
12
|
+
function displayableScalar(v) {
|
|
13
|
+
let raw;
|
|
14
|
+
if (typeof v === 'string')
|
|
15
|
+
raw = v.length > FRAME_READING_VALUE_PREFIX ? v.slice(0, FRAME_READING_VALUE_PREFIX) : v;
|
|
16
|
+
else if (typeof v === 'number' && Number.isFinite(v))
|
|
17
|
+
raw = String(v);
|
|
18
|
+
else
|
|
19
|
+
return undefined;
|
|
20
|
+
const shown = displayUntrusted(raw, { max: FRAME_READING_VALUE_MAX });
|
|
21
|
+
return shown === '' ? undefined : shown;
|
|
22
|
+
}
|
|
23
|
+
export function approvalRequestFrameReadingThrowing(frame) {
|
|
24
|
+
if (typeof frame !== 'object' || frame === null)
|
|
25
|
+
return UNREADABLE_READING;
|
|
26
|
+
const x = frame;
|
|
27
|
+
const type = x.type;
|
|
28
|
+
const schemaVersion = x.schemaVersion;
|
|
29
|
+
const kind = x.kind;
|
|
30
|
+
const pinned = Object.create(frame, {
|
|
31
|
+
type: { value: type, enumerable: true },
|
|
32
|
+
schemaVersion: { value: schemaVersion, enumerable: true },
|
|
33
|
+
kind: { value: kind, enumerable: true },
|
|
34
|
+
});
|
|
35
|
+
if (isApprovalRequestFrameV1(pinned))
|
|
36
|
+
return V1_READING;
|
|
37
|
+
const why = type !== KNOWN_FRAME_TYPE
|
|
38
|
+
? 'unreadable_fields'
|
|
39
|
+
: schemaVersion !== KNOWN_SCHEMA_VERSION
|
|
40
|
+
? 'version_unknown'
|
|
41
|
+
: kind !== KNOWN_KIND
|
|
42
|
+
? 'kind_unknown'
|
|
43
|
+
: 'unreadable_fields';
|
|
44
|
+
const shownVersion = displayableScalar(schemaVersion);
|
|
45
|
+
const shownKind = displayableScalar(kind);
|
|
46
|
+
return Object.freeze({
|
|
47
|
+
v1: false,
|
|
48
|
+
why,
|
|
49
|
+
...(shownVersion !== undefined ? { schemaVersion: shownVersion } : {}),
|
|
50
|
+
...(shownKind !== undefined ? { kind: shownKind } : {}),
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
export function approvalRequestFrameReadingOf(frame) {
|
|
54
|
+
try {
|
|
55
|
+
return approvalRequestFrameReadingThrowing(frame);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return UNREADABLE_READING;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
export function approvalUnreadableWhyWordOf(v) {
|
|
62
|
+
return APPROVAL_REQUEST_FRAME_UNREADABLE_WHYS.find((w) => w === v);
|
|
63
|
+
}
|
|
64
|
+
export function cardPayloadReadingOf(card) {
|
|
65
|
+
if (typeof card !== 'object' || card === null)
|
|
66
|
+
return Object.freeze({ payloadUnreadable: false });
|
|
67
|
+
const flag = guardedRead(() => readOwnDataValue(card, 'cardPayloadUnreadable'));
|
|
68
|
+
if (flag !== true)
|
|
69
|
+
return Object.freeze({ payloadUnreadable: false });
|
|
70
|
+
const word = guardedRead(() => readOwnDataValue(card, 'cardPayloadUnreadableWhy'));
|
|
71
|
+
const why = typeof word === 'string' ? approvalUnreadableWhyWordOf(word) : undefined;
|
|
72
|
+
return why === undefined ? Object.freeze({ payloadUnreadable: true }) : Object.freeze({ payloadUnreadable: true, why });
|
|
73
|
+
}
|
|
74
|
+
export function approvalFrameUnreadableWhyOf(reading) {
|
|
75
|
+
try {
|
|
76
|
+
if (typeof reading !== 'object' || reading === null)
|
|
77
|
+
return undefined;
|
|
78
|
+
const v1 = Object.getOwnPropertyDescriptor(reading, 'v1');
|
|
79
|
+
const why = Object.getOwnPropertyDescriptor(reading, 'why');
|
|
80
|
+
if (v1 === undefined || !Object.hasOwn(v1, 'value') || v1.value !== false)
|
|
81
|
+
return undefined;
|
|
82
|
+
if (why === undefined || !Object.hasOwn(why, 'value'))
|
|
83
|
+
return undefined;
|
|
84
|
+
const word = why.value;
|
|
85
|
+
return typeof word === 'string' ? approvalUnreadableWhyWordOf(word) : undefined;
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -8,7 +8,7 @@ import { type DeliveredReading, type LadderSafetyStop } from './attributionLadde
|
|
|
8
8
|
import { type CheckpointRowVerdictReading } from '../checkpointRowVerdict.js';
|
|
9
9
|
export declare const APPROVAL_RESOLUTION_LANES: readonly ["respond", "decide", "ask"];
|
|
10
10
|
export type ApprovalResolutionLane = (typeof APPROVAL_RESOLUTION_LANES)[number];
|
|
11
|
-
export declare const APPROVAL_NOT_SENT_CAUSES: readonly ["retracted", "edit_refused", "no_pending", "wrong_gate", "fetch_failed", "no_input", "card_unavailable", "safety_stop", "row_unresumable"];
|
|
11
|
+
export declare const APPROVAL_NOT_SENT_CAUSES: readonly ["retracted", "edit_refused", "no_pending", "wrong_gate", "fetch_failed", "no_input", "card_unavailable", "safety_stop", "row_unresumable", "withdrawn"];
|
|
12
12
|
export type ApprovalNotSentCause = (typeof APPROVAL_NOT_SENT_CAUSES)[number];
|
|
13
13
|
export declare const APPROVAL_UNSETTLED_CAUSES: readonly ["engine_refused", "engine_error", "no_answer", "transport_exhausted", "parking_in_progress", "interrupted", "orchestration", "unreadable"];
|
|
14
14
|
export type ApprovalUnsettledCause = (typeof APPROVAL_UNSETTLED_CAUSES)[number];
|
|
@@ -18,6 +18,11 @@ export interface ApprovalDenyFacts {
|
|
|
18
18
|
readonly policyCause?: PolicyDenyCause;
|
|
19
19
|
readonly attributionKey?: 'dropped' | 'renamed';
|
|
20
20
|
}
|
|
21
|
+
export interface ToolPermissionSettledElsewhere {
|
|
22
|
+
readonly firstDecision: 'allow' | 'deny';
|
|
23
|
+
readonly contrary: boolean;
|
|
24
|
+
}
|
|
25
|
+
export declare function toolPermissionSettledElsewhereOf(first: 'allow' | 'deny', sent: ToolApprovalRespondDecision | 'approve'): ToolPermissionSettledElsewhere;
|
|
21
26
|
interface ApprovalResolutionBase {
|
|
22
27
|
readonly lane: ApprovalResolutionLane;
|
|
23
28
|
readonly gatedCallId?: string;
|
|
@@ -30,6 +35,7 @@ export interface ApprovalResolutionDecided extends ApprovalResolutionBase {
|
|
|
30
35
|
readonly receipt?: DecideReceiptView;
|
|
31
36
|
readonly ack?: ToolApprovalRespondAckView;
|
|
32
37
|
readonly answered?: AskAnsweredOutput;
|
|
38
|
+
readonly settledElsewhere?: ToolPermissionSettledElsewhere;
|
|
33
39
|
}
|
|
34
40
|
export interface ApprovalResolutionNotSent extends ApprovalResolutionBase {
|
|
35
41
|
readonly kind: 'not_sent';
|
|
@@ -38,6 +44,7 @@ export interface ApprovalResolutionNotSent extends ApprovalResolutionBase {
|
|
|
38
44
|
readonly rowVerdict?: Exclude<CheckpointRowVerdictReading, {
|
|
39
45
|
readonly kind: 'ok';
|
|
40
46
|
}>;
|
|
47
|
+
readonly toldBy?: 'host';
|
|
41
48
|
readonly detail?: string;
|
|
42
49
|
}
|
|
43
50
|
export interface ApprovalResolutionUnsettled extends ApprovalResolutionBase {
|
|
@@ -16,6 +16,7 @@ export const APPROVAL_NOT_SENT_CAUSES = Object.freeze([
|
|
|
16
16
|
'card_unavailable',
|
|
17
17
|
'safety_stop',
|
|
18
18
|
'row_unresumable',
|
|
19
|
+
'withdrawn',
|
|
19
20
|
]);
|
|
20
21
|
export const APPROVAL_UNSETTLED_CAUSES = Object.freeze([
|
|
21
22
|
'engine_refused',
|
|
@@ -27,6 +28,9 @@ export const APPROVAL_UNSETTLED_CAUSES = Object.freeze([
|
|
|
27
28
|
'orchestration',
|
|
28
29
|
'unreadable',
|
|
29
30
|
]);
|
|
31
|
+
export function toolPermissionSettledElsewhereOf(first, sent) {
|
|
32
|
+
return Object.freeze({ firstDecision: first, contrary: (first === 'deny') !== (sent === 'deny') });
|
|
33
|
+
}
|
|
30
34
|
export function isApprovalDecided(r) {
|
|
31
35
|
return typeof r === 'object' && r !== null && r.kind === 'decided';
|
|
32
36
|
}
|
|
@@ -51,7 +51,7 @@ function readDurablePendingRows(raw) {
|
|
|
51
51
|
}
|
|
52
52
|
function durableDigestOf(rows) {
|
|
53
53
|
return rows
|
|
54
|
-
.map(r => [r.sessionId ?? '', r.taskId ?? '', r.toolCallId ?? '', r.boundCallId ?? '', r.boundInputHash ?? '', r.toolName ?? '', JSON.stringify(checkpointRowVerdictOf(r) ?? null), JSON.stringify(parkRowDelegationLinksOf(r) ?? null)]
|
|
54
|
+
.map(r => [r.sessionId ?? '', r.taskId ?? '', r.toolCallId ?? '', r.boundCallId ?? '', r.boundInputHash ?? '', r.toolName ?? '', r.gateKind ?? '', JSON.stringify(checkpointRowVerdictOf(r) ?? null), JSON.stringify(parkRowDelegationLinksOf(r) ?? null)]
|
|
55
55
|
.join(''))
|
|
56
56
|
.sort()
|
|
57
57
|
.join('');
|
package/dist/hitl/askGateWire.js
CHANGED
|
@@ -91,7 +91,6 @@ export async function* bridgeAskUserQuestionGates(source, deps, opts) {
|
|
|
91
91
|
await abortableSleep(reopenAfterMs, opts?.signal ?? new AbortController().signal);
|
|
92
92
|
if (!opts?.signal?.aborted) {
|
|
93
93
|
const seq = led.lastSeq();
|
|
94
|
-
led.beginStreamSegment();
|
|
95
94
|
stream = deps.runsEvents(taskId.current, {
|
|
96
95
|
...(seq !== undefined ? { lastEventId: seq } : {}),
|
|
97
96
|
...(opts?.signal ? { signal: opts.signal } : {}),
|
|
@@ -170,7 +169,6 @@ export async function* bridgeAskUserQuestionGates(source, deps, opts) {
|
|
|
170
169
|
led.forgetRunScopedState();
|
|
171
170
|
}
|
|
172
171
|
const seq = handoff !== undefined ? undefined : led.lastSeq();
|
|
173
|
-
led.beginStreamSegment();
|
|
174
172
|
stream = deps.runsEvents(taskId.current, {
|
|
175
173
|
...(seq !== undefined ? { lastEventId: seq } : {}),
|
|
176
174
|
...(opts?.signal ? { signal: opts.signal } : {}),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { askParkForeignGateKind, durableDecideLegOf } from '../adapter/activeRunSelfHeal.js';
|
|
2
2
|
import { isAskTool, questionCardVerdict } from './frameRouter.js';
|
|
3
3
|
import { approvalCallKey } from './gateIdentity.js';
|
|
4
|
-
import { askQuestionsFromPending, pendingRowIsOwnedByThisSession } from './parkOwnership.js';
|
|
4
|
+
import { askQuestionsFromPending, pendingRowIsOwnedByThisSession, pendingRowOwnershipOf } from './parkOwnership.js';
|
|
5
5
|
import { approvalQueueRowFamilyOf, checkpointQueueRowSortOf, QUEUE_ROW_FAMILY_UNREADABLE_GATE } from './approvalQueueRow.js';
|
|
6
6
|
import { checkpointRowBarOf, checkpointRowBarSentence } from '../checkpointRowVerdict.js';
|
|
7
7
|
import { msg, renderMessage } from '../i18n/translate.js';
|
|
@@ -161,8 +161,11 @@ export function countOwnedPendingRows(listed, deps) {
|
|
|
161
161
|
throw new Error('approvals.list answered with a pending row that is not an object — the owned pending count is unknown');
|
|
162
162
|
}
|
|
163
163
|
const family = approvalQueueRowFamilyOf(row);
|
|
164
|
-
if (family === 'unreadable')
|
|
164
|
+
if (family === 'unreadable') {
|
|
165
|
+
if (pendingRowOwnershipOf(row, deps) === 'foreign')
|
|
166
|
+
continue;
|
|
165
167
|
throw new Error('approvals.list answered with a pending row whose family (`kind`) cannot be read — the owned pending count is unknown');
|
|
168
|
+
}
|
|
166
169
|
if (family !== 'checkpoint')
|
|
167
170
|
continue;
|
|
168
171
|
if (pendingRowIsOwnedAndDecidable(row, deps))
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { type CoreModeArbitrationRow } from '../generated/engineFactTables.js';
|
|
2
2
|
import { CORE_ASK_FACES } from '../generated/engineAskFaceTables.js';
|
|
3
3
|
import type { UiLanguage } from '../env/uiLanguage.js';
|
|
4
|
+
import type { PermissionRuleValue } from '@sema-agent/agent-types';
|
|
4
5
|
export type AutomaticAnswerLane = 'mode_posture' | 'standing_rule' | 'permission_request_hook';
|
|
5
6
|
export type AutomaticAnswerAskFace = (typeof CORE_ASK_FACES)[number];
|
|
6
7
|
export interface AutomaticAnswerFacts {
|
|
7
8
|
readonly settingsAskRuleMatched?: boolean;
|
|
9
|
+
readonly allowRule?: PermissionRuleValue;
|
|
8
10
|
}
|
|
9
11
|
export type AutomaticAnswerRoad = 'origin' | 'requires_real_approval' | 'governance' | 'mandate_word' | 'mandated' | 'allow_rule_shadow' | 'ask_class' | 'settings_ask_rule';
|
|
10
|
-
export type AutomaticAnswerUnknownWhy = 'card_unreadable' | 'lane_not_recognised' | 'classes_malformed' | 'classes_absent' | 'class_not_in_table' | 'host_not_reported';
|
|
12
|
+
export type AutomaticAnswerUnknownWhy = 'card_unreadable' | 'lane_not_recognised' | 'classes_malformed' | 'classes_absent' | 'class_not_in_table' | 'host_not_reported' | 'answer_may_read_arguments';
|
|
11
13
|
export type AutomaticAnswerVerdict = {
|
|
12
14
|
readonly kind: 'must_ask';
|
|
13
15
|
readonly road: AutomaticAnswerRoad;
|
|
@@ -22,6 +24,7 @@ export type AutomaticAnswerVerdict = {
|
|
|
22
24
|
};
|
|
23
25
|
export declare const MODE_ARBITRATION: Readonly<Record<"hook" | "write_protection" | "mode" | "target_unresolved" | "content_question" | "ancestor" | "dangerous_delete" | "unverifiable_delete" | "unverifiable_shell_text" | "transcript_write" | "org_rule" | "rule_unreadable" | "ask_rule" | "denial_limit_fallback" | "classifier_no_ruling" | "requires_user_interaction" | "cross_boundary" | "operator_forced" | "shell_floor" | "probe" | "write_protection_on_disk" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary", CoreModeArbitrationRow>>;
|
|
24
26
|
export declare function foldModeArbitrationRow(classes: Iterable<string>, askFace?: AutomaticAnswerAskFace): CoreModeArbitrationRow;
|
|
27
|
+
export declare function askLevelVerdict(card: object | null | undefined, lane: AutomaticAnswerLane, facts?: AutomaticAnswerFacts | null): AutomaticAnswerVerdict;
|
|
25
28
|
export declare function automaticAnswerVerdict(card: object | null | undefined, lane: AutomaticAnswerLane, facts?: AutomaticAnswerFacts | null): AutomaticAnswerVerdict;
|
|
26
29
|
export declare function mandatedApprovalDetailOf(card: object | null | undefined, lang?: UiLanguage): string;
|
|
27
30
|
export interface CrossBoundaryTaintReading {
|
|
@@ -29,5 +32,5 @@ export interface CrossBoundaryTaintReading {
|
|
|
29
32
|
}
|
|
30
33
|
export declare function crossBoundaryTaintOf(carrier: object | null | undefined): CrossBoundaryTaintReading | undefined;
|
|
31
34
|
export declare function crossBoundaryTaintWayOutOf(carrier: object | null | undefined, lang?: UiLanguage): string | undefined;
|
|
32
|
-
export type PermissionRequestHookScope = '
|
|
35
|
+
export type PermissionRequestHookScope = 'deny_only' | 'skip';
|
|
33
36
|
export declare function permissionRequestHookScope(verdict: AutomaticAnswerVerdict | null | undefined): PermissionRequestHookScope;
|
|
@@ -3,6 +3,7 @@ import { CORE_RELEASABLE_ASK_CLASSES_BY_FACE, CORE_SHELL_FACE_TOOL_NAMES } from
|
|
|
3
3
|
import { mandatedApprovalDetail } from '../gateVocabulary.js';
|
|
4
4
|
import { msg, renderMessage } from '../i18n/translate.js';
|
|
5
5
|
import { guardedRead, readAskOrigin, readOwnDataValue, readOwnNonEmptyString } from '../ownKey.js';
|
|
6
|
+
import { allowRuleScopeOf } from './permissionRuleScope.js';
|
|
6
7
|
import { readAskClassPairState } from './askClassPair.js';
|
|
7
8
|
import { readRequiresRealApproval } from './approvalCardReading.js';
|
|
8
9
|
import { approvalAllowRuleShadowed, retiredAllowRuleShadowKeyPresent } from './allowRuleShadow.js';
|
|
@@ -60,13 +61,13 @@ export function foldModeArbitrationRow(classes, askFace) {
|
|
|
60
61
|
return ORDINARY_ROW;
|
|
61
62
|
return Object.freeze({ bypassImmune, classifierEligible, sandboxAdmission, ruleMayClear, hookAskFloor });
|
|
62
63
|
}
|
|
63
|
-
const
|
|
64
|
+
const HOOK_BLOCKING_CLASSES = new Set([...CORE_REAL_APPROVAL_ASK_CLASSES, ORIGIN_IMPLIES_CLASS.content_question]);
|
|
64
65
|
function classBlocks(lane, c, face) {
|
|
65
66
|
if (lane === 'mode_posture')
|
|
66
67
|
return bypassImmuneOn(c, face);
|
|
67
68
|
if (lane === 'standing_rule')
|
|
68
69
|
return !TABLE[c].ruleMayClear;
|
|
69
|
-
return
|
|
70
|
+
return HOOK_BLOCKING_CLASSES.has(c);
|
|
70
71
|
}
|
|
71
72
|
function mustAsk(road, extra) {
|
|
72
73
|
return Object.freeze({ kind: 'must_ask', road, ...(extra?.askClass !== undefined ? { askClass: extra.askClass } : {}), ...(extra?.origin !== undefined ? { origin: extra.origin } : {}) });
|
|
@@ -78,6 +79,7 @@ const UNKNOWN = Object.freeze({
|
|
|
78
79
|
classes_absent: Object.freeze({ kind: 'unknown', why: 'classes_absent' }),
|
|
79
80
|
class_not_in_table: Object.freeze({ kind: 'unknown', why: 'class_not_in_table' }),
|
|
80
81
|
host_not_reported: Object.freeze({ kind: 'unknown', why: 'host_not_reported' }),
|
|
82
|
+
answer_may_read_arguments: Object.freeze({ kind: 'unknown', why: 'answer_may_read_arguments' }),
|
|
81
83
|
});
|
|
82
84
|
const MAY_ANSWER = Object.freeze({ kind: 'may_answer' });
|
|
83
85
|
function evidenceView(card, ...keys) {
|
|
@@ -142,7 +144,7 @@ function readHostAskRuleMatched(facts) {
|
|
|
142
144
|
const v = guardedRead(() => readOwnDataValue(facts, 'settingsAskRuleMatched'));
|
|
143
145
|
return typeof v === 'boolean' ? v : undefined;
|
|
144
146
|
}
|
|
145
|
-
export function
|
|
147
|
+
export function askLevelVerdict(card, lane, facts) {
|
|
146
148
|
if (lane !== 'mode_posture' && lane !== 'standing_rule' && lane !== 'permission_request_hook')
|
|
147
149
|
return UNKNOWN.lane_not_recognised;
|
|
148
150
|
try {
|
|
@@ -214,6 +216,18 @@ export function automaticAnswerVerdict(card, lane, facts) {
|
|
|
214
216
|
return UNKNOWN.card_unreadable;
|
|
215
217
|
}
|
|
216
218
|
}
|
|
219
|
+
function reportedWholeToolAllowRule(facts) {
|
|
220
|
+
if (typeof facts !== 'object' || facts === null)
|
|
221
|
+
return false;
|
|
222
|
+
const raw = guardedRead(() => readOwnDataValue(facts, 'allowRule'));
|
|
223
|
+
return allowRuleScopeOf(typeof raw === 'object' ? raw : undefined) === 'whole_tool';
|
|
224
|
+
}
|
|
225
|
+
export function automaticAnswerVerdict(card, lane, facts) {
|
|
226
|
+
const asked = askLevelVerdict(card, lane, facts);
|
|
227
|
+
if (asked.kind !== 'may_answer' || lane === 'mode_posture')
|
|
228
|
+
return asked;
|
|
229
|
+
return lane === 'standing_rule' && reportedWholeToolAllowRule(facts) ? asked : UNKNOWN.answer_may_read_arguments;
|
|
230
|
+
}
|
|
217
231
|
export function mandatedApprovalDetailOf(card, lang) {
|
|
218
232
|
try {
|
|
219
233
|
if (typeof card !== 'object' || card === null)
|
|
@@ -276,7 +290,7 @@ export function crossBoundaryTaintWayOutOf(carrier, lang) {
|
|
|
276
290
|
export function permissionRequestHookScope(verdict) {
|
|
277
291
|
try {
|
|
278
292
|
const kind = typeof verdict === 'object' && verdict !== null ? verdict.kind : undefined;
|
|
279
|
-
return kind === '
|
|
293
|
+
return kind === 'must_ask' ? 'skip' : 'deny_only';
|
|
280
294
|
}
|
|
281
295
|
catch {
|
|
282
296
|
return 'deny_only';
|
|
@@ -3,5 +3,6 @@ import type { CapturedCode } from '../engineWireFor.js';
|
|
|
3
3
|
import { type ProtocolErrorNameReading } from '../wireFailureShape.js';
|
|
4
4
|
export type DecisionRefusalConflict = 'binding_mismatch' | 'row_integrity' | 'format_version' | 'answer_invalid' | 'grant_changed';
|
|
5
5
|
export declare function decisionConflictOf(err: unknown, captured?: CapturedCode, protocolNameRead?: ProtocolErrorNameReading): DecisionRefusalConflict | undefined;
|
|
6
|
-
export declare
|
|
6
|
+
export declare function decisionAnswerInvalidContent(lang?: UiLanguage): string;
|
|
7
|
+
export declare const DECISION_ANSWER_INVALID_CONTENT: string;
|
|
7
8
|
export declare function decisionGrantChangedContent(lang?: UiLanguage): string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { APPROVAL_BINDING_MISMATCH, CHECKPOINT_UNSUPPORTED_VERSION, RESUME_OUTCOME_INVALID } from '../engineErrorCodes.js';
|
|
1
|
+
import { APPROVAL_BINDING_MISMATCH, CHECKPOINT_INVALID_OUTCOME, CHECKPOINT_UNSUPPORTED_VERSION, RESUME_OUTCOME_INVALID } from '../engineErrorCodes.js';
|
|
2
2
|
import { msg, renderMessage } from '../i18n/translate.js';
|
|
3
3
|
import { ownDataField } from '../ownKey.js';
|
|
4
4
|
import { SDK_DECIDE_BINDING_KEYS } from '../generated/sdkFactTables.js';
|
|
@@ -28,16 +28,19 @@ export function decisionConflictOf(err, captured, protocolNameRead) {
|
|
|
28
28
|
return undefined;
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
|
-
const protocolName = namedProtocolOf(protocolNameRead ?? protocolErrorNameReading(err
|
|
31
|
+
const protocolName = namedProtocolOf(protocolNameRead ?? protocolErrorNameReading(err));
|
|
32
32
|
if (code === CHECKPOINT_UNSUPPORTED_VERSION)
|
|
33
33
|
return 'format_version';
|
|
34
34
|
const bindingFamily = code === APPROVAL_BINDING_MISMATCH || (code === undefined && protocolName === PROTOCOL_ERROR_NAME.ApprovalBindingMismatchError);
|
|
35
|
-
|
|
35
|
+
const rowOwnFamily = code === CHECKPOINT_INVALID_OUTCOME || (code === undefined && protocolName === PROTOCOL_ERROR_NAME.CheckpointInvalidOutcomeError);
|
|
36
|
+
if (!bindingFamily && !rowOwnFamily && code !== RESUME_OUTCOME_INVALID)
|
|
36
37
|
return undefined;
|
|
37
38
|
const slots = readRefusalSlots(err, REFUSAL_WORD_KEYS, extra.bag);
|
|
38
39
|
const field = slots.field.word;
|
|
39
40
|
if (code === RESUME_OUTCOME_INVALID)
|
|
40
41
|
return field === ANSWER_FIELD ? 'answer_invalid' : field === GRANT_DIGEST_FIELD ? 'grant_changed' : undefined;
|
|
42
|
+
if (rowOwnFamily)
|
|
43
|
+
return field === undefined && !slots.field.present && slots.reason.word !== undefined ? 'row_integrity' : undefined;
|
|
41
44
|
if (field === undefined) {
|
|
42
45
|
if (slots.field.present)
|
|
43
46
|
return undefined;
|
|
@@ -45,7 +48,10 @@ export function decisionConflictOf(err, captured, protocolNameRead) {
|
|
|
45
48
|
}
|
|
46
49
|
return BINDING_SEAT_FIELDS.has(field) ? 'binding_mismatch' : undefined;
|
|
47
50
|
}
|
|
48
|
-
export
|
|
51
|
+
export function decisionAnswerInvalidContent(lang) {
|
|
52
|
+
return renderMessage(msg('approval.decision.answerInvalid'), lang);
|
|
53
|
+
}
|
|
54
|
+
export const DECISION_ANSWER_INVALID_CONTENT = decisionAnswerInvalidContent();
|
|
49
55
|
export function decisionGrantChangedContent(lang) {
|
|
50
56
|
return renderMessage(msg('approval.decision.grantChanged'), lang);
|
|
51
57
|
}
|
|
@@ -226,6 +226,7 @@ export function mintDecisionRefusalReading(err, context, attributionCarried, del
|
|
|
226
226
|
const acceptableForm = errorCode === RESUME_CONSTRAINT_REJECTED && obj !== undefined ? isolated(() => readErrorPresent(obj, 'acceptableForm')) : undefined;
|
|
227
227
|
const transient = inRange &&
|
|
228
228
|
conflict !== 'grant_changed' &&
|
|
229
|
+
conflict !== 'row_integrity' &&
|
|
229
230
|
!unrecoverable &&
|
|
230
231
|
(TRANSIENT_STATUSES.has(status) || retriable || (status === 404 && obj !== undefined && isolated(() => notPendingCauseReading(obj)) === 'other_replica'));
|
|
231
232
|
return Object.freeze({
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { AgentClient, ElicitResponse } from '@sema-agent/sdk';
|
|
2
2
|
import type { UiLanguage } from '../env/uiLanguage.js';
|
|
3
|
+
import type { ToolPermissionSettledElsewhere } from './approvalResolution.js';
|
|
3
4
|
import { type AskGoneDetail } from '../decideReceipt.js';
|
|
4
5
|
import type { ApprovalDecidedByReading } from '../approvalDecidedByCapability.js';
|
|
5
6
|
import { type DecisionNoteAudit } from './approvalDecisionNoteAudit.js';
|
|
@@ -64,6 +65,7 @@ interface HitlDecisionOutcomeBase {
|
|
|
64
65
|
readonly attempts: number;
|
|
65
66
|
readonly fallback?: 'approval';
|
|
66
67
|
readonly noteDropped?: true;
|
|
68
|
+
readonly allowNoteDropped?: true;
|
|
67
69
|
readonly rememberDropped?: true;
|
|
68
70
|
readonly allowSessionCarried?: true;
|
|
69
71
|
readonly attributionDropped?: true;
|
|
@@ -115,5 +117,6 @@ export interface HitlDecisionSendTiming {
|
|
|
115
117
|
export declare function __setHitlDecisionSendTimingForTests(t?: HitlDecisionSendTiming): void;
|
|
116
118
|
export declare function hitlAskIdempotencyKey(askId: string, verdict: 'approve' | 'deny'): string;
|
|
117
119
|
export declare function sendHitlDecision(request: HitlDecisionSendRequest, deps: HitlDecisionSendDeps): Promise<HitlDecisionSendOutcome>;
|
|
120
|
+
export declare function toolPermissionSettledLine(fact: ToolPermissionSettledElsewhere | null | undefined, lang?: UiLanguage): string | undefined;
|
|
118
121
|
export declare function hitlDecisionOutcomeContent(outcome: HitlDecisionSendOutcome, lang?: UiLanguage): string | undefined;
|
|
119
122
|
export {};
|
|
@@ -14,7 +14,7 @@ import { ASK_DECIDED_CODE, classifyDeliveredDecisionRefusal, decisionRefusalClos
|
|
|
14
14
|
import { sessionAllowEligible } from './sessionAllowRoute.js';
|
|
15
15
|
import { addDecisionOpKeys, closeDecisionOp, decisionLedgerKeysOf, decisionOpsWithKey, openDecisionOp } from './decisionLedger.js';
|
|
16
16
|
import { hostHoldIsActive, takeHostHoldLedgerOp, tryHoldApprovalNow } from './approvalHolds.js';
|
|
17
|
-
import { answerPayloadFor, decisionAttributionKeyOf,
|
|
17
|
+
import { allowNoteReadingOf, answerPayloadFor, decisionAttributionKeyOf, readApprovalDenySettledBy, readToolApprovalRespondAck, readToolApprovalRespondParking, replayedFirstDecisionOf, settlementAckOf, } from './toolApprovalWire.js';
|
|
18
18
|
export const HITL_DECISION_FAMILIES = Object.freeze(['approval', 'ask', 'elicitation']);
|
|
19
19
|
export const HITL_DECISION_NOT_APPLIED_CAUSES = Object.freeze(['gone', 'parked', 'parking', 'lane_disabled', 'refused', 'idempotency_crossed']);
|
|
20
20
|
export const HITL_DECISION_UNCONFIRMED_CAUSES = Object.freeze(['transport', 'server_error', 'local_error', 'aborted', 'gone_after_retry']);
|
|
@@ -163,9 +163,10 @@ async function sendApprovalFamily(respond, approvalId, answer, ctx) {
|
|
|
163
163
|
const hint = view !== undefined ? ownReadingSlot(view, 'retryAfterMs') : undefined;
|
|
164
164
|
return { ...base, kind: 'not_applied', cause: 'parking', ...(view !== undefined ? { parking: view, ...(hint !== undefined ? { retryAfterMs: hint } : {}) } : {}) };
|
|
165
165
|
}
|
|
166
|
-
const parsed = readToolApprovalRespondAck(raw);
|
|
167
|
-
|
|
168
|
-
|
|
166
|
+
const parsed = settlementAckOf(readToolApprovalRespondAck(raw));
|
|
167
|
+
const replayWord = replayedFirstDecisionOf(parsed);
|
|
168
|
+
if (parsed !== undefined && replayWord !== undefined) {
|
|
169
|
+
const first = parsed.approvalId === approvalId ? verdictOf(replayWord) : undefined;
|
|
169
170
|
return {
|
|
170
171
|
...base,
|
|
171
172
|
kind: 'settled_elsewhere',
|
|
@@ -183,6 +184,7 @@ function bodyFacts(answer, payload, rememberUnsupported) {
|
|
|
183
184
|
return {
|
|
184
185
|
...(reason !== undefined && reason.trim() !== '' && payload.note === undefined ? { noteDropped: true } : {}),
|
|
185
186
|
...(rememberUnsupported && answer.kind === 'allow' && answer.allowSession === true ? { rememberDropped: true } : {}),
|
|
187
|
+
...(answer.kind === 'allow' && allowNoteReadingOf(answer).kind === 'text' ? { allowNoteDropped: true } : {}),
|
|
186
188
|
};
|
|
187
189
|
}
|
|
188
190
|
function answerGateCannotTake(out) {
|
|
@@ -361,8 +363,10 @@ function snapshotAnswer(raw) {
|
|
|
361
363
|
if (kind === 'allow') {
|
|
362
364
|
const allowSession = guardedRead(() => readOwnDataValue(raw, 'allowSession')) === true;
|
|
363
365
|
const edited = guardedRead(() => readOwnDataValue(raw, 'updatedInput'));
|
|
366
|
+
const noteRaw = guardedRead(() => readOwnDataValue(raw, 'note'));
|
|
367
|
+
const note = typeof noteRaw === 'string' && noteRaw.trim() !== '' ? noteRaw : undefined;
|
|
364
368
|
if (edited === undefined)
|
|
365
|
-
return Object.freeze({ kind: 'allow', allowSession });
|
|
369
|
+
return Object.freeze({ kind: 'allow', allowSession, ...(note !== undefined ? { note } : {}) });
|
|
366
370
|
let copy;
|
|
367
371
|
try {
|
|
368
372
|
const text = JSON.stringify(edited);
|
|
@@ -373,7 +377,7 @@ function snapshotAnswer(raw) {
|
|
|
373
377
|
catch {
|
|
374
378
|
return undefined;
|
|
375
379
|
}
|
|
376
|
-
return Object.freeze({ kind: 'allow', allowSession, updatedInput: copy });
|
|
380
|
+
return Object.freeze({ kind: 'allow', allowSession, ...(note !== undefined ? { note } : {}), updatedInput: copy });
|
|
377
381
|
}
|
|
378
382
|
if (kind === 'deny') {
|
|
379
383
|
const reason = guardedRead(() => readOwnDataValue(raw, 'reason'));
|
|
@@ -560,6 +564,24 @@ export async function sendHitlDecision(request, deps) {
|
|
|
560
564
|
ownHold.release(out.kind === 'applied' || out.kind === 'settled_elsewhere' ? 'answered' : undefined);
|
|
561
565
|
return Object.freeze(out);
|
|
562
566
|
}
|
|
567
|
+
function settledElsewhereContraryContent(first, lang) {
|
|
568
|
+
return first === 'deny'
|
|
569
|
+
? renderMessage(msg('approval.decision.settledElsewhereContrary.deniedFirst'), lang)
|
|
570
|
+
: renderMessage(msg('approval.decision.settledElsewhereContrary.approvedFirst'), lang);
|
|
571
|
+
}
|
|
572
|
+
export function toolPermissionSettledLine(fact, lang) {
|
|
573
|
+
try {
|
|
574
|
+
if (typeof fact !== 'object' || fact === null)
|
|
575
|
+
return undefined;
|
|
576
|
+
if (readOwnDataValue(fact, 'contrary') !== true)
|
|
577
|
+
return undefined;
|
|
578
|
+
const first = readOwnDataValue(fact, 'firstDecision');
|
|
579
|
+
return first === 'allow' || first === 'deny' ? settledElsewhereContraryContent(first, lang) : undefined;
|
|
580
|
+
}
|
|
581
|
+
catch {
|
|
582
|
+
return undefined;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
563
585
|
export function hitlDecisionOutcomeContent(outcome, lang) {
|
|
564
586
|
try {
|
|
565
587
|
if (typeof outcome !== 'object' || outcome === null)
|
|
@@ -569,11 +591,7 @@ export function hitlDecisionOutcomeContent(outcome, lang) {
|
|
|
569
591
|
if (readOwnDataValue(outcome, 'contrary') !== true)
|
|
570
592
|
return undefined;
|
|
571
593
|
const first = readOwnDataValue(outcome, 'firstDecision');
|
|
572
|
-
|
|
573
|
-
return renderMessage(msg('approval.decision.settledElsewhereContrary.deniedFirst'), lang);
|
|
574
|
-
if (first === 'approve')
|
|
575
|
-
return renderMessage(msg('approval.decision.settledElsewhereContrary.approvedFirst'), lang);
|
|
576
|
-
return undefined;
|
|
594
|
+
return first === 'deny' || first === 'approve' ? settledElsewhereContraryContent(first, lang) : undefined;
|
|
577
595
|
}
|
|
578
596
|
if (kind === 'unconfirmed' && readOwnDataValue(outcome, 'cause') === 'gone_after_retry')
|
|
579
597
|
return renderMessage(msg('approval.decision.unconfirmedAfterRetry'), lang);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { UiLanguage } from '../env/uiLanguage.js';
|
|
2
|
+
export declare const EDITED_APPROVAL_STATES: readonly ["accepts", "refuses", "unknown"];
|
|
3
|
+
export type EditedApprovalState = (typeof EDITED_APPROVAL_STATES)[number];
|
|
4
|
+
export declare const EDITED_APPROVAL_BASES: Readonly<{
|
|
5
|
+
accepts: readonly ["args_available"];
|
|
6
|
+
refuses: readonly ["args_unavailable"];
|
|
7
|
+
unknown: readonly ["card_unreadable", "slot_unreadable", "slot_malformed"];
|
|
8
|
+
}>;
|
|
9
|
+
interface EditedApprovalAccepts {
|
|
10
|
+
readonly state: 'accepts';
|
|
11
|
+
readonly basis: (typeof EDITED_APPROVAL_BASES.accepts)[number];
|
|
12
|
+
}
|
|
13
|
+
interface EditedApprovalRefuses {
|
|
14
|
+
readonly state: 'refuses';
|
|
15
|
+
readonly basis: (typeof EDITED_APPROVAL_BASES.refuses)[number];
|
|
16
|
+
readonly askStaysPending: true;
|
|
17
|
+
}
|
|
18
|
+
interface EditedApprovalUnknown {
|
|
19
|
+
readonly state: 'unknown';
|
|
20
|
+
readonly basis: (typeof EDITED_APPROVAL_BASES.unknown)[number];
|
|
21
|
+
}
|
|
22
|
+
export type EditedApprovalAcceptance = EditedApprovalAccepts | EditedApprovalRefuses | EditedApprovalUnknown;
|
|
23
|
+
export declare function editedApprovalAcceptanceOf(card: {} | null | undefined): EditedApprovalAcceptance;
|
|
24
|
+
export declare function editedApprovalRefusedLine(lang?: UiLanguage): string;
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { msg, renderMessage } from '../i18n/translate.js';
|
|
2
|
+
import { slotReadOf } from '../wireFailureShape.js';
|
|
3
|
+
export const EDITED_APPROVAL_STATES = Object.freeze(['accepts', 'refuses', 'unknown']);
|
|
4
|
+
export const EDITED_APPROVAL_BASES = Object.freeze({
|
|
5
|
+
accepts: Object.freeze(['args_available']),
|
|
6
|
+
refuses: Object.freeze(['args_unavailable']),
|
|
7
|
+
unknown: Object.freeze(['card_unreadable', 'slot_unreadable', 'slot_malformed']),
|
|
8
|
+
});
|
|
9
|
+
const ACCEPTS = Object.freeze({ state: 'accepts', basis: 'args_available' });
|
|
10
|
+
const REFUSES = Object.freeze({ state: 'refuses', basis: 'args_unavailable', askStaysPending: true });
|
|
11
|
+
const UNKNOWN_CARD = Object.freeze({ state: 'unknown', basis: 'card_unreadable' });
|
|
12
|
+
const UNKNOWN_SLOT = Object.freeze({ state: 'unknown', basis: 'slot_unreadable' });
|
|
13
|
+
const UNKNOWN_MALFORMED = Object.freeze({ state: 'unknown', basis: 'slot_malformed' });
|
|
14
|
+
export function editedApprovalAcceptanceOf(card) {
|
|
15
|
+
if (typeof card !== 'object' || card === null)
|
|
16
|
+
return UNKNOWN_CARD;
|
|
17
|
+
const read = slotReadOf(card, 'argsUnavailable');
|
|
18
|
+
if (read.presence === 'unreadable')
|
|
19
|
+
return UNKNOWN_SLOT;
|
|
20
|
+
if (read.presence === 'absent' || read.value === undefined)
|
|
21
|
+
return ACCEPTS;
|
|
22
|
+
return read.value === true ? REFUSES : UNKNOWN_MALFORMED;
|
|
23
|
+
}
|
|
24
|
+
export function editedApprovalRefusedLine(lang) {
|
|
25
|
+
return renderMessage(msg('approval.editRefusal.line'), lang);
|
|
26
|
+
}
|