@sema-agent/client-core 0.107.0 → 0.109.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 +239 -0
- package/README.md +54 -36
- package/dist/adapt/arms.js +23 -8
- package/dist/adapt/textStream.d.ts +2 -0
- package/dist/adapt/textStream.js +37 -16
- package/dist/adapter/activeRunSelfHeal.d.ts +2 -0
- package/dist/adapter/activeRunSelfHeal.js +21 -4
- package/dist/adapter/downstream/eventToSdkMessage.js +2 -1
- 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 +6 -1
- package/dist/checkpointRowVerdict.js +30 -2
- package/dist/cloudConfigWireCaps.d.ts +10 -0
- package/dist/cloudConfigWireCaps.js +33 -0
- package/dist/compensations.js +1 -1
- package/dist/coreValuePorts.d.ts +17 -1
- package/dist/coreValuePorts.js +5 -0
- package/dist/decideReceipt.js +2 -1
- package/dist/engineAgentAbsence.d.ts +2 -0
- package/dist/engineAgentAbsence.js +28 -0
- package/dist/engineErrorCodes.d.ts +9 -0
- package/dist/engineErrorCodes.js +9 -0
- package/dist/engineHealthFacts.d.ts +17 -0
- package/dist/engineHealthFacts.js +42 -3
- package/dist/engineNoticeCodes.d.ts +147 -1
- package/dist/engineNoticeCodes.js +694 -57
- package/dist/engineTargetSeat.js +1 -0
- package/dist/errorSupplementRoles.js +6 -1
- package/dist/eventLeg.js +1 -1
- package/dist/executionLaneWords.js +2 -1
- package/dist/fleetTaskDesc.js +3 -3
- package/dist/gateOutcome.d.ts +10 -1
- package/dist/gateOutcome.js +48 -1
- package/dist/generated/engineFactTables.d.ts +2 -0
- package/dist/generated/engineFactTables.js +11 -0
- package/dist/generated/engineNoticeTables.js +6 -0
- package/dist/generated/settingsSchemaFns.d.ts +4 -2
- package/dist/generated/settingsSchemaFns.js +9 -3
- package/dist/generated/settingsSchemaMcpRequestEntry.d.ts +1 -1
- package/dist/generated/settingsSchemaMcpRequestEntry.js +9 -18
- package/dist/generated/settingsSchemaReservedMemberName.d.ts +1 -0
- package/dist/generated/settingsSchemaReservedMemberName.js +7 -0
- package/dist/generated/settingsSchemaTables.d.ts +2 -0
- package/dist/generated/settingsSchemaTables.js +10 -0
- package/dist/generated/settingsSchemaWireName.d.ts +1 -0
- package/dist/generated/settingsSchemaWireName.js +8 -0
- package/dist/headlessReconnectWire.js +12 -7
- package/dist/hitl/approvalAskers.d.ts +13 -0
- package/dist/hitl/approvalAskers.js +79 -0
- package/dist/hitl/approvalCardReasons.js +22 -4
- package/dist/hitl/approvalRequestFrameReading.d.ts +14 -0
- package/dist/hitl/approvalRequestFrameReading.js +79 -0
- package/dist/hitl/approvalResolution.d.ts +3 -0
- package/dist/hitl/approvalResolution.js +22 -4
- package/dist/hitl/approvalsFeed.js +4 -13
- package/dist/hitl/askParkRowRouting.js +10 -3
- package/dist/hitl/automaticAnswerVerdict.d.ts +5 -2
- package/dist/hitl/automaticAnswerVerdict.js +16 -2
- package/dist/hitl/decisionConflict.d.ts +2 -1
- package/dist/hitl/decisionConflict.js +4 -1
- package/dist/hitl/decisionRefusal.d.ts +1 -0
- package/dist/hitl/decisionRefusal.js +5 -2
- package/dist/hitl/decisionSend.js +2 -6
- package/dist/hitl/frameRouter.d.ts +3 -2
- package/dist/hitl/frameRouter.js +37 -7
- package/dist/hitl/gateLedger.d.ts +2 -0
- package/dist/hitl/gateLedger.js +3 -1
- package/dist/hitl/hitlBridge.d.ts +4 -0
- package/dist/hitl/hitlBridge.js +11 -8
- 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 +39 -30
- package/dist/hitl/parkRowBirthWait.d.ts +2 -0
- package/dist/hitl/parkRowBirthWait.js +8 -1
- 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 +7 -1
- package/dist/hitl/persistedRulesWire.js +25 -8
- package/dist/hitl/planReviewWire.js +12 -16
- package/dist/hitl/policyDenyCause.d.ts +3 -0
- package/dist/hitl/policyDenyCause.js +16 -0
- package/dist/hitl/sessionAllowRoute.js +5 -4
- package/dist/hitl/sessionPolicyDeliverable.js +1 -1
- package/dist/hitl/standingRows.d.ts +1 -5
- package/dist/hitl/standingRows.js +15 -14
- package/dist/hitl/toolApprovalWire.d.ts +16 -4
- package/dist/hitl/toolApprovalWire.js +57 -17
- package/dist/hooksReaderGenerations.d.ts +1 -0
- package/dist/hooksReaderGenerations.js +12 -0
- package/dist/hooksWireCaps.js +12 -7
- package/dist/hostSettingsSource.js +2 -0
- package/dist/i18n/messages.en.d.ts +206 -1
- package/dist/i18n/messages.en.js +209 -4
- package/dist/i18n/messages.zh.js +214 -4
- package/dist/index.d.ts +35 -8
- package/dist/index.js +20 -5
- package/dist/liveModelCatalog.d.ts +4 -2
- package/dist/liveModelCatalog.js +164 -26
- 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/mcpReconnect.js +12 -5
- package/dist/mcpWireCaps.js +2 -2
- package/dist/memoryEntriesWire.d.ts +1 -1
- package/dist/memoryEntriesWire.js +5 -0
- package/dist/model/catalogDefault.d.ts +25 -0
- package/dist/model/catalogDefault.js +44 -0
- package/dist/noticePresentation.d.ts +2 -0
- package/dist/noticePresentation.js +79 -1
- package/dist/ownKey.d.ts +10 -0
- package/dist/ownKey.js +15 -1
- package/dist/permissionWireCaps.d.ts +1 -0
- package/dist/permissionWireCaps.js +11 -0
- package/dist/pluginHooksWire.d.ts +5 -3
- package/dist/pluginHooksWire.js +116 -7
- package/dist/queuedDelivery.d.ts +1 -0
- package/dist/queuedDelivery.js +12 -0
- package/dist/resultFrameKeys.js +4 -2
- package/dist/resumeRefusalCopy.js +15 -8
- package/dist/ruleReadings.js +1 -1
- package/dist/runPermissionModeSwitch.d.ts +2 -1
- package/dist/runPermissionModeSwitch.js +16 -6
- package/dist/seam.d.ts +13 -2
- package/dist/seam.js +8 -1
- package/dist/seatContract.d.ts +103 -12
- package/dist/seatContract.js +344 -14
- package/dist/sessionBackground.js +2 -0
- package/dist/sessionEngine.d.ts +2 -1
- package/dist/sessionEngine.js +5 -0
- package/dist/settingsHooksSalvage.d.ts +5 -0
- package/dist/settingsHooksSalvage.js +54 -0
- package/dist/subagentContentStore.d.ts +12 -0
- package/dist/subagentContentStore.js +73 -12
- package/dist/supportFloor.js +2 -0
- package/dist/taskNotificationAdmission.d.ts +19 -0
- package/dist/taskNotificationAdmission.js +84 -0
- package/dist/toolResult.js +20 -6
- package/dist/webSearchWireCaps.js +9 -4
- package/dist/wireFailureShape.d.ts +20 -0
- package/dist/wireFailureShape.js +37 -6
- package/dist/wireRefusalCopy.d.ts +23 -2
- package/dist/wireRefusalCopy.js +93 -4
- package/docs/INTEGRATION-CLIENTS.md +1959 -15
- package/package.json +4 -4
|
@@ -0,0 +1,14 @@
|
|
|
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 declare function approvalFrameUnreadableWhyOf(reading: ApprovalRequestFrameReading | null | undefined): ApprovalRequestFrameUnreadableWhy | undefined;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { isApprovalRequestFrameV1 } from '@sema-agent/sdk';
|
|
2
|
+
import { displayUntrusted } from '../displayUntrusted.js';
|
|
3
|
+
export const APPROVAL_REQUEST_FRAME_UNREADABLE_WHYS = Object.freeze(['version_unknown', 'kind_unknown', 'unreadable_fields']);
|
|
4
|
+
const KNOWN_FRAME_TYPE = 'approval_request';
|
|
5
|
+
const KNOWN_SCHEMA_VERSION = 1;
|
|
6
|
+
const KNOWN_KIND = 'permission';
|
|
7
|
+
const FRAME_READING_VALUE_MAX = 24;
|
|
8
|
+
const FRAME_READING_VALUE_PREFIX = 128;
|
|
9
|
+
const V1_READING = Object.freeze({ v1: true });
|
|
10
|
+
const UNREADABLE_READING = Object.freeze({ v1: false, why: 'unreadable_fields' });
|
|
11
|
+
function displayableScalar(v) {
|
|
12
|
+
let raw;
|
|
13
|
+
if (typeof v === 'string')
|
|
14
|
+
raw = v.length > FRAME_READING_VALUE_PREFIX ? v.slice(0, FRAME_READING_VALUE_PREFIX) : v;
|
|
15
|
+
else if (typeof v === 'number' && Number.isFinite(v))
|
|
16
|
+
raw = String(v);
|
|
17
|
+
else
|
|
18
|
+
return undefined;
|
|
19
|
+
const shown = displayUntrusted(raw, { max: FRAME_READING_VALUE_MAX });
|
|
20
|
+
return shown === '' ? undefined : shown;
|
|
21
|
+
}
|
|
22
|
+
export function approvalRequestFrameReadingThrowing(frame) {
|
|
23
|
+
if (typeof frame !== 'object' || frame === null)
|
|
24
|
+
return UNREADABLE_READING;
|
|
25
|
+
const x = frame;
|
|
26
|
+
const type = x.type;
|
|
27
|
+
const schemaVersion = x.schemaVersion;
|
|
28
|
+
const kind = x.kind;
|
|
29
|
+
const pinned = Object.create(frame, {
|
|
30
|
+
type: { value: type, enumerable: true },
|
|
31
|
+
schemaVersion: { value: schemaVersion, enumerable: true },
|
|
32
|
+
kind: { value: kind, enumerable: true },
|
|
33
|
+
});
|
|
34
|
+
if (isApprovalRequestFrameV1(pinned))
|
|
35
|
+
return V1_READING;
|
|
36
|
+
const why = type !== KNOWN_FRAME_TYPE
|
|
37
|
+
? 'unreadable_fields'
|
|
38
|
+
: schemaVersion !== KNOWN_SCHEMA_VERSION
|
|
39
|
+
? 'version_unknown'
|
|
40
|
+
: kind !== KNOWN_KIND
|
|
41
|
+
? 'kind_unknown'
|
|
42
|
+
: 'unreadable_fields';
|
|
43
|
+
const shownVersion = displayableScalar(schemaVersion);
|
|
44
|
+
const shownKind = displayableScalar(kind);
|
|
45
|
+
return Object.freeze({
|
|
46
|
+
v1: false,
|
|
47
|
+
why,
|
|
48
|
+
...(shownVersion !== undefined ? { schemaVersion: shownVersion } : {}),
|
|
49
|
+
...(shownKind !== undefined ? { kind: shownKind } : {}),
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
export function approvalRequestFrameReadingOf(frame) {
|
|
53
|
+
try {
|
|
54
|
+
return approvalRequestFrameReadingThrowing(frame);
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return UNREADABLE_READING;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
export function approvalUnreadableWhyWordOf(v) {
|
|
61
|
+
return APPROVAL_REQUEST_FRAME_UNREADABLE_WHYS.find((w) => w === v);
|
|
62
|
+
}
|
|
63
|
+
export function approvalFrameUnreadableWhyOf(reading) {
|
|
64
|
+
try {
|
|
65
|
+
if (typeof reading !== 'object' || reading === null)
|
|
66
|
+
return undefined;
|
|
67
|
+
const v1 = Object.getOwnPropertyDescriptor(reading, 'v1');
|
|
68
|
+
const why = Object.getOwnPropertyDescriptor(reading, 'why');
|
|
69
|
+
if (v1 === undefined || !Object.hasOwn(v1, 'value') || v1.value !== false)
|
|
70
|
+
return undefined;
|
|
71
|
+
if (why === undefined || !Object.hasOwn(why, 'value'))
|
|
72
|
+
return undefined;
|
|
73
|
+
const word = why.value;
|
|
74
|
+
return typeof word === 'string' ? approvalUnreadableWhyWordOf(word) : undefined;
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { DecideReceiptView } from '../decideReceipt.js';
|
|
2
2
|
import { type HitlSafetyCode } from './hitlBridge.js';
|
|
3
3
|
import type { AskAnsweredOutput } from './gateLedger.js';
|
|
4
|
+
import type { PolicyDenyCause } from './policyDenyCause.js';
|
|
4
5
|
import type { ApprovalDenySettledBy, ToolApprovalRespondAckView, ToolApprovalRespondDecision, ToolApprovalRespondParkingView } from './toolApprovalWire.js';
|
|
5
6
|
import { type DecisionRefusalReading, type RefusalRouteContext } from './decisionRefusal.js';
|
|
6
7
|
import { type DeliveredReading, type LadderSafetyStop } from './attributionLadder.js';
|
|
@@ -14,6 +15,7 @@ export type ApprovalUnsettledCause = (typeof APPROVAL_UNSETTLED_CAUSES)[number];
|
|
|
14
15
|
export interface ApprovalDenyFacts {
|
|
15
16
|
readonly settledBy?: ApprovalDenySettledBy;
|
|
16
17
|
readonly reason?: string;
|
|
18
|
+
readonly policyCause?: PolicyDenyCause;
|
|
17
19
|
readonly attributionKey?: 'dropped' | 'renamed';
|
|
18
20
|
}
|
|
19
21
|
interface ApprovalResolutionBase {
|
|
@@ -53,6 +55,7 @@ export declare function approvalUnsettledCause(r: ApprovalResolution): ApprovalU
|
|
|
53
55
|
export declare const APPROVAL_NOTE_RETRACTED_DETAIL = "the card was retracted (this host no longer has a decision port for it)";
|
|
54
56
|
export declare const APPROVAL_NOTE_EDIT_REFUSED_DETAIL = "edits are not accepted on this card";
|
|
55
57
|
export declare function approvalResolutionDetail(r: ApprovalResolution): string | undefined;
|
|
58
|
+
export declare function approvalResolutionStatusTag(r: ApprovalResolution): string;
|
|
56
59
|
export declare function unsettledCauseOfReading(reading: DecisionRefusalReading): 'engine_refused' | 'engine_error' | 'no_answer';
|
|
57
60
|
export interface DecisionFailureMint {
|
|
58
61
|
readonly lane: ApprovalResolutionLane;
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { DecideTransportRetryExhaustedError, refusalCarrierOf, safetyStopHeadOf, safetyStopNamed } from './hitlBridge.js';
|
|
2
|
-
import { mintDecisionRefusalReading } from './decisionRefusal.js';
|
|
2
|
+
import { decisionStatusTag, mintDecisionRefusalReading } from './decisionRefusal.js';
|
|
3
3
|
import { isSlotCarrier, thrownIsInstanceOf } from '../wireFailureShape.js';
|
|
4
4
|
import { carrierReadOf, isLocalSafetyStop, localCodeReadOf, topCauseReadOf } from './attributionLadder.js';
|
|
5
5
|
import { directFailureReadingOf, transportReadingOf } from './approvalDelivery.js';
|
|
6
6
|
import { ownReadingSlot } from '../engineWireFor.js';
|
|
7
|
-
import { CHECKPOINT_ROW_BAR_SENTENCE } from '../checkpointRowVerdict.js';
|
|
8
|
-
import { msg, renderMessage } from '../i18n/translate.js';
|
|
7
|
+
import { CHECKPOINT_ROW_BAR_SENTENCE, unboundWayOutContent } from '../checkpointRowVerdict.js';
|
|
9
8
|
export const APPROVAL_RESOLUTION_LANES = Object.freeze(['respond', 'decide', 'ask']);
|
|
10
9
|
export const APPROVAL_NOT_SENT_CAUSES = Object.freeze([
|
|
11
10
|
'retracted',
|
|
@@ -95,7 +94,7 @@ export function approvalResolutionDetail(r) {
|
|
|
95
94
|
const code = cause === 'safety_stop' ? ownStr(r, 'safetyCode') : undefined;
|
|
96
95
|
if (code === undefined)
|
|
97
96
|
return sentence;
|
|
98
|
-
return code === 'binding_missing' ? `${sentence} (${code}) · ${
|
|
97
|
+
return code === 'binding_missing' ? `${sentence} (${code}) · ${unboundWayOutContent('unknown')}` : `${sentence} (${code})`;
|
|
99
98
|
}
|
|
100
99
|
if (kind !== 'unsettled')
|
|
101
100
|
return undefined;
|
|
@@ -110,6 +109,25 @@ export function approvalResolutionDetail(r) {
|
|
|
110
109
|
const parts = [ownStr(refusal, 'errorCode'), ownStr(r, 'detail') ?? ownStr(refusal, 'message')].filter((x) => x !== undefined);
|
|
111
110
|
return parts.length > 0 ? parts.join(' · ') : undefined;
|
|
112
111
|
}
|
|
112
|
+
export function approvalResolutionStatusTag(r) {
|
|
113
|
+
try {
|
|
114
|
+
if (typeof r !== 'object' || r === null)
|
|
115
|
+
return '';
|
|
116
|
+
const kd = Object.getOwnPropertyDescriptor(r, 'kind');
|
|
117
|
+
if (kd === undefined || !Object.hasOwn(kd, 'value') || kd.value !== 'unsettled')
|
|
118
|
+
return '';
|
|
119
|
+
const rd = Object.getOwnPropertyDescriptor(r, 'refusal');
|
|
120
|
+
const refusal = rd !== undefined && Object.hasOwn(rd, 'value') ? rd.value : undefined;
|
|
121
|
+
if (typeof refusal !== 'object' || refusal === null)
|
|
122
|
+
return '';
|
|
123
|
+
const sd = Object.getOwnPropertyDescriptor(refusal, 'status');
|
|
124
|
+
const status = sd !== undefined && Object.hasOwn(sd, 'value') ? sd.value : undefined;
|
|
125
|
+
return typeof status === 'number' && Number.isInteger(status) && status >= 400 && status <= 599 ? decisionStatusTag(status) : '';
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
return '';
|
|
129
|
+
}
|
|
130
|
+
}
|
|
113
131
|
export function unsettledCauseOfReading(reading) {
|
|
114
132
|
const standing = ownReadingSlot(reading, 'standing');
|
|
115
133
|
if (standing === 'ambiguous')
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { hostLog } from '../host.js';
|
|
2
|
+
import { invokeHostCallbackIsolated } from '../hostCallbackGuard.js';
|
|
2
3
|
import { unrefTimer } from '../unrefTimer.js';
|
|
3
4
|
import { readLivePendingRows } from './livePendingAsk.js';
|
|
4
5
|
import { createStreamDrainingLegs } from '../streamDrainingLegs.js';
|
|
@@ -50,7 +51,7 @@ function readDurablePendingRows(raw) {
|
|
|
50
51
|
}
|
|
51
52
|
function durableDigestOf(rows) {
|
|
52
53
|
return rows
|
|
53
|
-
.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)]
|
|
54
55
|
.join(''))
|
|
55
56
|
.sort()
|
|
56
57
|
.join('');
|
|
@@ -176,12 +177,7 @@ export function startApprovalsFeed(client, onSnapshot, opts) {
|
|
|
176
177
|
const at = Date.now();
|
|
177
178
|
blind = { why, at };
|
|
178
179
|
stats.unknowns++;
|
|
179
|
-
|
|
180
|
-
onSnapshot({ kind: 'unknown', why, at, mode: via });
|
|
181
|
-
}
|
|
182
|
-
catch (e) {
|
|
183
|
-
hostLog('debug', `approvalsFeed: subscriber threw on the unknown arm (swallowed): ${String(e)}`);
|
|
184
|
-
}
|
|
180
|
+
invokeHostCallbackIsolated('approvalsFeed: subscriber (unknown arm)', () => onSnapshot({ kind: 'unknown', why, at, mode: via }));
|
|
185
181
|
}
|
|
186
182
|
async function take(via, leg) {
|
|
187
183
|
if (stopped)
|
|
@@ -293,12 +289,7 @@ export function startApprovalsFeed(client, onSnapshot, opts) {
|
|
|
293
289
|
};
|
|
294
290
|
last = snap;
|
|
295
291
|
stats.snapshots++;
|
|
296
|
-
|
|
297
|
-
onSnapshot(snap);
|
|
298
|
-
}
|
|
299
|
-
catch (e) {
|
|
300
|
-
hostLog('debug', `approvalsFeed: subscriber threw (swallowed): ${String(e)}`);
|
|
301
|
-
}
|
|
292
|
+
invokeHostCallbackIsolated('approvalsFeed: subscriber', () => onSnapshot(snap));
|
|
302
293
|
}
|
|
303
294
|
function schedulePoll() {
|
|
304
295
|
if (stopped || ac.signal.aborted)
|
|
@@ -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';
|
|
@@ -37,6 +37,7 @@ export function classifyAskParkRows(queueRows, taskId, deps) {
|
|
|
37
37
|
kind: 'settled',
|
|
38
38
|
reason: renderMessage(msg('approval.rowUnresumable.askNotSurfaced', { taskId: String(pending.taskId), sentence: checkpointRowBarSentence(bar) })),
|
|
39
39
|
rowVerdict: bar,
|
|
40
|
+
rowTaskId: askParkRowTaskIdOf(taskId, pending),
|
|
40
41
|
};
|
|
41
42
|
}
|
|
42
43
|
if (foreignKind !== null) {
|
|
@@ -50,8 +51,11 @@ export function classifyAskParkRows(queueRows, taskId, deps) {
|
|
|
50
51
|
function askParkRowGateKind(row) {
|
|
51
52
|
return typeof row.gateKind === 'string' && row.gateKind.length > 0 ? row.gateKind : null;
|
|
52
53
|
}
|
|
54
|
+
function askParkRowTaskIdOf(taskId, row) {
|
|
55
|
+
return typeof row.taskId === 'string' && row.taskId.length > 0 ? row.taskId : taskId;
|
|
56
|
+
}
|
|
53
57
|
export function askParkRowIdentity(taskId, row) {
|
|
54
|
-
const rowTaskId =
|
|
58
|
+
const rowTaskId = askParkRowTaskIdOf(taskId, row);
|
|
55
59
|
const gatedCallId = row.toolCallId ?? row.boundCallId ?? undefined;
|
|
56
60
|
return { rowTaskId, gatedCallId, armedKey: approvalCallKey(gatedCallId, rowTaskId) };
|
|
57
61
|
}
|
|
@@ -157,8 +161,11 @@ export function countOwnedPendingRows(listed, deps) {
|
|
|
157
161
|
throw new Error('approvals.list answered with a pending row that is not an object — the owned pending count is unknown');
|
|
158
162
|
}
|
|
159
163
|
const family = approvalQueueRowFamilyOf(row);
|
|
160
|
-
if (family === 'unreadable')
|
|
164
|
+
if (family === 'unreadable') {
|
|
165
|
+
if (pendingRowOwnershipOf(row, deps) === 'foreign')
|
|
166
|
+
continue;
|
|
161
167
|
throw new Error('approvals.list answered with a pending row whose family (`kind`) cannot be read — the owned pending count is unknown');
|
|
168
|
+
}
|
|
162
169
|
if (family !== 'checkpoint')
|
|
163
170
|
continue;
|
|
164
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';
|
|
@@ -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;
|
|
@@ -45,7 +45,10 @@ export function decisionConflictOf(err, captured, protocolNameRead) {
|
|
|
45
45
|
}
|
|
46
46
|
return BINDING_SEAT_FIELDS.has(field) ? 'binding_mismatch' : undefined;
|
|
47
47
|
}
|
|
48
|
-
export
|
|
48
|
+
export function decisionAnswerInvalidContent(lang) {
|
|
49
|
+
return renderMessage(msg('approval.decision.answerInvalid'), lang);
|
|
50
|
+
}
|
|
51
|
+
export const DECISION_ANSWER_INVALID_CONTENT = decisionAnswerInvalidContent();
|
|
49
52
|
export function decisionGrantChangedContent(lang) {
|
|
50
53
|
return renderMessage(msg('approval.decision.grantChanged'), lang);
|
|
51
54
|
}
|
|
@@ -78,5 +78,6 @@ export interface UndeliverableDecisionFacts {
|
|
|
78
78
|
readonly end: UndeliverableDecisionEnd;
|
|
79
79
|
readonly runId?: string;
|
|
80
80
|
}
|
|
81
|
+
export declare function decisionStatusTag(status: number, errorCode?: string): string;
|
|
81
82
|
export declare function undeliverableDecisionContent(facts: UndeliverableDecisionFacts): string;
|
|
82
83
|
export declare function decideRowUnrevivableNotice(lang?: UiLanguage | (string & {})): string;
|
|
@@ -314,9 +314,12 @@ export function decisionRefusalClosesOut(refusal, pending) {
|
|
|
314
314
|
return false;
|
|
315
315
|
return standing === 'ambiguous' || standing === 'refused-pending';
|
|
316
316
|
}
|
|
317
|
+
export function decisionStatusTag(status, errorCode) {
|
|
318
|
+
const code = typeof errorCode === 'string' && isDisplayableWireCode(errorCode) ? ` ${errorCode}` : '';
|
|
319
|
+
return `(HTTP ${String(status)}${code})`;
|
|
320
|
+
}
|
|
317
321
|
export function undeliverableDecisionContent(facts) {
|
|
318
|
-
const
|
|
319
|
-
const head = `The engine refused the approval decision this client sent (HTTP ${String(facts.status)}${code}), so the call it asked about could not be answered from here and did not run`;
|
|
322
|
+
const head = `The engine refused the approval decision this client sent ${decisionStatusTag(facts.status, facts.errorCode)}, so the call it asked about could not be answered from here and did not run`;
|
|
320
323
|
const runId = typeof facts.runId === 'string' && isDisplayableWireCode(facts.runId) ? ` ${facts.runId}` : '';
|
|
321
324
|
switch (facts.end) {
|
|
322
325
|
case 'run-stopped':
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { settleWithinDeadline } from '../abortableSleep.js';
|
|
2
2
|
import { hostLog } from '../host.js';
|
|
3
|
+
import { invokeHostCallbackIsolated } from '../hostCallbackGuard.js';
|
|
3
4
|
import { msg, renderMessage } from '../i18n/translate.js';
|
|
4
5
|
import { askGoneFromError } from '../decideReceipt.js';
|
|
5
6
|
import { appendOwnElement, guardedRead, readOwnDataNonEmptyString, readOwnDataValue } from '../ownKey.js';
|
|
@@ -343,12 +344,7 @@ function holdFits(handle, req) {
|
|
|
343
344
|
}
|
|
344
345
|
}
|
|
345
346
|
function callHold(call) {
|
|
346
|
-
|
|
347
|
-
call();
|
|
348
|
-
}
|
|
349
|
-
catch (e) {
|
|
350
|
-
hostLog('debug', `decisionSend.callHold: ${String(e).slice(0, 120)}`);
|
|
351
|
-
}
|
|
347
|
+
invokeHostCallbackIsolated('decisionSend: hold verb', call);
|
|
352
348
|
}
|
|
353
349
|
function hostField(holder, key) {
|
|
354
350
|
if (typeof holder !== 'object' || holder === null)
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { AgentEvent } from '@sema-agent/sdk';
|
|
2
2
|
import type { DecideOperationObserver, HitlClientLike } from './hitlBridge.js';
|
|
3
3
|
import { type RespondToolApprovalFn, type ToolApprovalFrame, type ToolApprovalFrameLaneOpts } from './toolApprovalWire.js';
|
|
4
|
-
import type { ApprovalResolution } from './approvalResolution.js';
|
|
5
|
-
import type { GateLedger } from './gateLedger.js';
|
|
4
|
+
import type { ApprovalDenyFacts, ApprovalResolution } from './approvalResolution.js';
|
|
5
|
+
import type { GateLedger, GateDenyAttribution } from './gateLedger.js';
|
|
6
6
|
import type { NoAllowCause } from './noAllowCause.js';
|
|
7
7
|
import { type ReplayedApprovalDisposition } from './replayedApproval.js';
|
|
8
8
|
import type { ReattachDrainingEvent } from '../runReattachPolicy.js';
|
|
@@ -17,6 +17,7 @@ export interface PolicyDenyReasonFacts {
|
|
|
17
17
|
readonly budgetSetting?: string;
|
|
18
18
|
}
|
|
19
19
|
export declare function policyDenyReason(facts: PolicyDenyReasonFacts): string;
|
|
20
|
+
export declare function denyAttributionOf(deny: ApprovalDenyFacts | undefined): GateDenyAttribution;
|
|
20
21
|
export declare const HITL_INTERRUPT_MESSAGE_FOR_TOOL_USE = "[Request interrupted by user for tool use]";
|
|
21
22
|
export declare const ENGINE_ABORT_TOOL_RESULT = "Operation aborted";
|
|
22
23
|
export interface ParkReattachNotice {
|
package/dist/hitl/frameRouter.js
CHANGED
|
@@ -13,6 +13,8 @@ import { surfaceForCurrentSession, surfaceReplayedApprovalListUnreadable } from
|
|
|
13
13
|
import { liveCardHoldOf, noteEngineClosedApproval, settleEngineClosedApproval } from './approvalHolds.js';
|
|
14
14
|
import { approvalCompleteParked } from './approvalCompleteParked.js';
|
|
15
15
|
import { liveFrameCallKey } from './gateIdentity.js';
|
|
16
|
+
import { readPolicyDenyCause } from './policyDenyCause.js';
|
|
17
|
+
import { msg, renderMessage } from '../i18n/translate.js';
|
|
16
18
|
import { SEMA_DENIAL_KIND_KEY, hasLedgerPositionKey } from './gateLedger.js';
|
|
17
19
|
import { replayedApprovalClosesCardFrame, replayedApprovalDisposition, settledApprovalDisposition } from './replayedApproval.js';
|
|
18
20
|
import { settleWithinDeadline } from '../abortableSleep.js';
|
|
@@ -30,7 +32,11 @@ export function policyDenyReason(facts) {
|
|
|
30
32
|
const one = typeof facts.toolName === 'string' && SENTENCE_TOOL_NAME.test(facts.toolName) ? `this one "${facts.toolName}" call` : 'this one call';
|
|
31
33
|
const flag = typeof facts.allowRuleFlag === 'string' && SENTENCE_TOOL_NAME.test(facts.allowRuleFlag.replace(/^--?/, '')) ? ` (or ${facts.allowRuleFlag})` : '';
|
|
32
34
|
const budgetKnob = typeof facts.budgetSetting === 'string' && SENTENCE_TOOL_NAME.test(facts.budgetSetting) ? facts.budgetSetting : undefined;
|
|
33
|
-
const cause = facts.cause === 'no_allow_rule' || facts.cause === 'ask_rule' || facts.cause === 'engine_ask_rule' || facts.cause === 'budget'
|
|
35
|
+
const cause = facts.cause === 'no_allow_rule' || facts.cause === 'ask_rule' || facts.cause === 'engine_ask_rule' || facts.cause === 'budget' || facts.cause === 'whole_tool_rule_only'
|
|
36
|
+
? facts.cause
|
|
37
|
+
: 'other';
|
|
38
|
+
const wholeToolOnly = 'this client does not approve calls from the arguments shown to it, so here only an allow rule for the whole tool can approve calls like this ahead of time — ' +
|
|
39
|
+
'a rule that names paths, commands or other arguments applies only where the engine checks it against the real arguments';
|
|
34
40
|
if (facts.lane === 'dont_ask') {
|
|
35
41
|
const mode = 'denied by the dontAsk permission mode';
|
|
36
42
|
switch (cause) {
|
|
@@ -42,6 +48,8 @@ export function policyDenyReason(facts) {
|
|
|
42
48
|
return `${mode}: a rule on the engine side, not one of the user's permission rules, asks about ${one}, and this mode refuses anything that would ask — the user's settings cannot approve it; use another permission mode to answer it`;
|
|
43
49
|
case 'budget':
|
|
44
50
|
return `${mode}: ${one} needed approval, and this session's automatic-approval budget is used up, so saved rules no longer approve calls${budgetKnob !== undefined ? ` — raise ${budgetKnob} before launch to change the cap` : ''}`;
|
|
51
|
+
case 'whole_tool_rule_only':
|
|
52
|
+
return `${mode}: ${one} needed approval; ${wholeToolOnly} — and this mode refuses anything that would ask; use another permission mode to answer it`;
|
|
45
53
|
default:
|
|
46
54
|
return `${mode}: ${one} needed a person's approval that saved permission rules cannot approve here (the engine or your deployment requires a person for it, or it could not be checked against your rules), and this mode refuses anything that would ask — use another permission mode to answer it`;
|
|
47
55
|
}
|
|
@@ -57,6 +65,8 @@ export function policyDenyReason(facts) {
|
|
|
57
65
|
return `${lane}: a rule on the engine side, not one of the user's permission rules, asks about ${one}, so it needed a person's answer, and ${tail}; the user's settings cannot approve it - run the task interactively to answer it`;
|
|
58
66
|
case 'budget':
|
|
59
67
|
return `${lane}: ${one} needed a person's approval, and this session's automatic-approval budget is used up, so saved rules no longer approve calls; ${tail}${budgetKnob !== undefined ? `; raise ${budgetKnob} before launch to change the cap` : ''}`;
|
|
68
|
+
case 'whole_tool_rule_only':
|
|
69
|
+
return `${lane}: ${one} needed a person's approval; ${wholeToolOnly}; ${tail}; run the task interactively to answer it`;
|
|
60
70
|
default:
|
|
61
71
|
return `${lane}: ${one} needed a person's approval, and saved permission rules cannot approve it here (the engine or your deployment requires a person for it, or it could not be checked against your rules); ${tail}; run the task interactively to answer it`;
|
|
62
72
|
}
|
|
@@ -64,10 +74,33 @@ export function policyDenyReason(facts) {
|
|
|
64
74
|
function denyOutputForRender(attribution) {
|
|
65
75
|
if (attribution?.settledBy !== 'policy')
|
|
66
76
|
return HITL_REJECT_MESSAGE;
|
|
77
|
+
const head = policyDenyHeadFor(readPolicyDenyCause(attribution));
|
|
67
78
|
const reason = attribution.reason;
|
|
68
79
|
return reason !== undefined && reason.trim() !== ''
|
|
69
|
-
? `${
|
|
70
|
-
:
|
|
80
|
+
? `${head}\n${reason}`
|
|
81
|
+
: head;
|
|
82
|
+
}
|
|
83
|
+
function policyDenyHeadFor(cause) {
|
|
84
|
+
const tail = msg('approval.policyDeny.tail');
|
|
85
|
+
switch (cause) {
|
|
86
|
+
case 'dont_ask':
|
|
87
|
+
return renderMessage(msg('approval.policyDeny.dontAsk', { tail }));
|
|
88
|
+
case 'deny_rule':
|
|
89
|
+
return renderMessage(msg('approval.policyDeny.denyRule', { tail }));
|
|
90
|
+
case 'engine_floor':
|
|
91
|
+
return renderMessage(msg('approval.policyDeny.engineFloor', { tail }));
|
|
92
|
+
case 'no_approval_ui':
|
|
93
|
+
case undefined:
|
|
94
|
+
return HITL_POLICY_DENY_MESSAGE;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
export function denyAttributionOf(deny) {
|
|
98
|
+
const policyCause = readPolicyDenyCause(deny);
|
|
99
|
+
return {
|
|
100
|
+
...(deny?.settledBy !== undefined ? { settledBy: deny.settledBy } : {}),
|
|
101
|
+
...(deny?.reason !== undefined ? { reason: deny.reason } : {}),
|
|
102
|
+
...(policyCause !== undefined ? { policyCause } : {}),
|
|
103
|
+
};
|
|
71
104
|
}
|
|
72
105
|
function denialKindForTranscript(attribution) {
|
|
73
106
|
return ccToolDenialKindForSettledBy(attribution?.settledBy);
|
|
@@ -354,10 +387,7 @@ function settleLiveCardOutcome(ev, outcome, ctx, fromSubagent, gatedCallId) {
|
|
|
354
387
|
invokeHostCallbackIsolated('liveHitlAskWire: onToolApprovalOutcome', () => deps.onToolApprovalOutcome?.(ev, outcome));
|
|
355
388
|
}
|
|
356
389
|
if (outcome.kind === 'decided' && outcome.decision === 'deny' && !fromSubagent) {
|
|
357
|
-
const attribution =
|
|
358
|
-
...(outcome.deny?.settledBy !== undefined ? { settledBy: outcome.deny.settledBy } : {}),
|
|
359
|
-
...(outcome.deny?.reason !== undefined ? { reason: outcome.deny.reason } : {}),
|
|
360
|
-
};
|
|
390
|
+
const attribution = denyAttributionOf(outcome.deny);
|
|
361
391
|
if (gatedCallId !== undefined)
|
|
362
392
|
led.markDenied(gatedCallId, attribution);
|
|
363
393
|
else
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { AgentEvent } from '@sema-agent/sdk';
|
|
2
|
+
import { type PolicyDenyCause } from './policyDenyCause.js';
|
|
2
3
|
export declare const SEMA_COLLATERAL_ABORT_KEY = "_sema_collateral_abort";
|
|
3
4
|
export declare const SEMA_DENIAL_KIND_KEY = "_sema_denial_kind";
|
|
4
5
|
export interface GateDenyAttribution {
|
|
5
6
|
settledBy?: 'human' | 'policy';
|
|
6
7
|
reason?: string;
|
|
8
|
+
policyCause?: PolicyDenyCause;
|
|
7
9
|
}
|
|
8
10
|
export interface AskAnsweredOutput {
|
|
9
11
|
type: 'ask-user-question';
|
package/dist/hitl/gateLedger.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { parkedToolEndRoleOf } from '../engineRowRef.js';
|
|
2
2
|
import { inheritFrameBinding } from '../frameBinding.js';
|
|
3
|
+
import { readPolicyDenyCause } from './policyDenyCause.js';
|
|
3
4
|
export const SEMA_COLLATERAL_ABORT_KEY = '_sema_collateral_abort';
|
|
4
5
|
export const SEMA_DENIAL_KIND_KEY = '_sema_denial_kind';
|
|
5
6
|
export function durableSeqOf(ev) {
|
|
@@ -27,9 +28,10 @@ function normalizeDenyAttribution(a) {
|
|
|
27
28
|
return undefined;
|
|
28
29
|
const settledBy = a.settledBy === 'human' || a.settledBy === 'policy' ? a.settledBy : undefined;
|
|
29
30
|
const reason = typeof a.reason === 'string' && a.reason.trim() !== '' ? a.reason : undefined;
|
|
31
|
+
const policyCause = settledBy === 'policy' ? readPolicyDenyCause(a) : undefined;
|
|
30
32
|
if (settledBy === undefined && reason === undefined)
|
|
31
33
|
return undefined;
|
|
32
|
-
return { ...(settledBy !== undefined ? { settledBy } : {}), ...(reason !== undefined ? { reason } : {}) };
|
|
34
|
+
return { ...(settledBy !== undefined ? { settledBy } : {}), ...(reason !== undefined ? { reason } : {}), ...(policyCause !== undefined ? { policyCause } : {}) };
|
|
33
35
|
}
|
|
34
36
|
export function createGateLedger() {
|
|
35
37
|
const startedCalls = new Set();
|
|
@@ -141,6 +141,10 @@ export type FindPendingOutcome = {
|
|
|
141
141
|
export declare function findPendingForTask(client: HitlClientLike, taskId: string, matches: (toolName: string | undefined) => boolean, opts?: {
|
|
142
142
|
signal?: AbortSignal;
|
|
143
143
|
}, callId?: string, identityAccepts?: (row: PendingCheckpoint) => boolean): Promise<FindPendingOutcome>;
|
|
144
|
+
export declare function checkpointQueueReadingOf(row: object): {
|
|
145
|
+
readonly r: PendingCheckpoint;
|
|
146
|
+
readonly foreign: string | null;
|
|
147
|
+
} | undefined;
|
|
144
148
|
export declare class HitlBridge {
|
|
145
149
|
private readonly client;
|
|
146
150
|
private readonly taskId;
|
package/dist/hitl/hitlBridge.js
CHANGED
|
@@ -11,8 +11,7 @@ import { suspendedReopenOf } from './suspendedReopen.js';
|
|
|
11
11
|
import { closeDecisionOp, decisionLedgerKeysOf, openDecisionOp } from './decisionLedger.js';
|
|
12
12
|
import { askParkBlockGeneration, noteAskParkDecideSettled } from './askParkAutoReopenBlock.js';
|
|
13
13
|
import { checkpointQueueRowSortOf, QUEUE_ROW_FAMILY_UNREADABLE_GATE } from './approvalQueueRow.js';
|
|
14
|
-
import { checkpointRowBarOf, checkpointRowBarSentence } from '../checkpointRowVerdict.js';
|
|
15
|
-
import { msg, renderMessage } from '../i18n/translate.js';
|
|
14
|
+
import { checkpointDeadlineStateOf, checkpointRowBarOf, checkpointRowBarSentence, unboundWayOutContent } from '../checkpointRowVerdict.js';
|
|
16
15
|
export const DEFAULT_DENY_REASON = 'The user rejected this tool use';
|
|
17
16
|
export const MAX_DENY_REASON_CHARS = 4096;
|
|
18
17
|
export function denyReasonForWire(reason, tag) {
|
|
@@ -271,11 +270,8 @@ export async function findPendingForTask(client, taskId, matches, opts, callId,
|
|
|
271
270
|
return { ok: false, reason: `approvals.list failed: ${t.reason}` };
|
|
272
271
|
}
|
|
273
272
|
const readings = rows.flatMap((r) => {
|
|
274
|
-
const
|
|
275
|
-
|
|
276
|
-
return [];
|
|
277
|
-
const cp = r;
|
|
278
|
-
return [{ r: cp, foreign: sort === 'unreadable' ? QUEUE_ROW_FAMILY_UNREADABLE_GATE : askParkForeignGateKind(cp) }];
|
|
273
|
+
const x = checkpointQueueReadingOf(r);
|
|
274
|
+
return x === undefined ? [] : [x];
|
|
279
275
|
});
|
|
280
276
|
const decidable = readings.filter((x) => x.foreign === null).map((x) => x.r);
|
|
281
277
|
const identityRow = callId !== undefined
|
|
@@ -314,6 +310,13 @@ export async function findPendingForTask(client, taskId, matches, opts, callId,
|
|
|
314
310
|
return { ok: false, reason: checkpointRowBarSentence(bar), code: 'row_unresumable', rowVerdict: bar };
|
|
315
311
|
return { ok: true, pending, gatedCallId: pending.toolCallId ?? pending.boundCallId ?? undefined };
|
|
316
312
|
}
|
|
313
|
+
export function checkpointQueueReadingOf(row) {
|
|
314
|
+
const sort = checkpointQueueRowSortOf(row);
|
|
315
|
+
if (sort === 'excluded')
|
|
316
|
+
return undefined;
|
|
317
|
+
const cp = row;
|
|
318
|
+
return { r: cp, foreign: sort === 'unreadable' ? QUEUE_ROW_FAMILY_UNREADABLE_GATE : askParkForeignGateKind(cp) };
|
|
319
|
+
}
|
|
317
320
|
export class HitlBridge {
|
|
318
321
|
client;
|
|
319
322
|
taskId;
|
|
@@ -365,7 +368,7 @@ export class HitlBridge {
|
|
|
365
368
|
if (typeof boundCallId !== 'string' || boundCallId.length === 0 || typeof boundInputHash !== 'string' || boundInputHash.length === 0) {
|
|
366
369
|
throw new HitlSafetyError(`pending checkpoint ${p.id ?? '<no-id>'} is missing D-1 binding fields ` +
|
|
367
370
|
`(boundCallId=${String(boundCallId)}, boundInputHash=${String(boundInputHash)}) — ` +
|
|
368
|
-
`the row itself carries no binding to echo, so ${
|
|
371
|
+
`the row itself carries no binding to echo, so ${unboundWayOutContent(checkpointDeadlineStateOf(p))}`, 'binding_missing');
|
|
369
372
|
}
|
|
370
373
|
return { boundCallId, boundInputHash };
|
|
371
374
|
}
|