@sema-agent/client-core 0.108.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 +121 -0
- package/README.md +37 -24
- 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.js +1 -1
- 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 +1 -1
- package/dist/checkpointRowVerdict.js +4 -2
- package/dist/compensations.js +1 -1
- package/dist/engineAgentAbsence.d.ts +2 -0
- package/dist/engineAgentAbsence.js +28 -0
- package/dist/engineErrorCodes.d.ts +4 -0
- package/dist/engineErrorCodes.js +4 -0
- package/dist/engineHealthFacts.d.ts +17 -0
- package/dist/engineHealthFacts.js +42 -3
- package/dist/engineNoticeCodes.d.ts +128 -0
- package/dist/engineNoticeCodes.js +630 -55
- package/dist/errorSupplementRoles.js +4 -1
- package/dist/fleetTaskDesc.js +3 -3
- package/dist/generated/engineFactTables.d.ts +1 -0
- package/dist/generated/engineFactTables.js +6 -0
- package/dist/generated/engineNoticeTables.js +3 -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/approvalsFeed.js +1 -1
- package/dist/hitl/askParkRowRouting.js +5 -2
- 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/frameRouter.js +9 -1
- package/dist/hitl/hitlBridge.d.ts +4 -0
- package/dist/hitl/hitlBridge.js +9 -5
- 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 +7 -7
- 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 +11 -10
- package/dist/hitl/sessionAllowRoute.js +5 -4
- package/dist/hitl/standingRows.d.ts +1 -5
- package/dist/hitl/standingRows.js +15 -14
- package/dist/hitl/toolApprovalWire.d.ts +8 -2
- package/dist/hitl/toolApprovalWire.js +35 -14
- package/dist/hooksWireCaps.js +4 -3
- package/dist/hostSettingsSource.js +2 -0
- package/dist/i18n/messages.en.d.ts +168 -0
- package/dist/i18n/messages.en.js +169 -1
- package/dist/i18n/messages.zh.js +169 -1
- package/dist/index.d.ts +29 -7
- package/dist/index.js +16 -4
- 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/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/ruleReadings.js +1 -1
- package/dist/seam.d.ts +13 -2
- package/dist/seam.js +8 -1
- package/dist/seatContract.d.ts +42 -4
- package/dist/seatContract.js +180 -3
- package/dist/sessionBackground.js +2 -0
- package/dist/subagentContentStore.d.ts +12 -0
- package/dist/subagentContentStore.js +72 -11
- package/dist/toolResult.js +18 -5
- package/dist/wireFailureShape.d.ts +20 -0
- package/dist/wireFailureShape.js +37 -6
- package/dist/wireRefusalCopy.d.ts +21 -1
- package/dist/wireRefusalCopy.js +91 -2
- package/docs/INTEGRATION-CLIENTS.md +1152 -10
- package/package.json +3 -3
|
@@ -5,7 +5,7 @@ import { resumeReopenContent } from './hitl/suspendedReopen.js';
|
|
|
5
5
|
import { idempotencyPayloadMismatchContent } from './engineErrorCodes.js';
|
|
6
6
|
import { inheritEnvRefusalContent } from './inheritEnvWire.js';
|
|
7
7
|
import { projectSeedRefusalContent } from './projectSeed.js';
|
|
8
|
-
import { usageWindowExhaustedContent, fleetLeaseUnavailableContent, settingsPermissionBucketRefusalContent, fieldLimitRefusalContent, autonomyLaneRefusalContent, sessionArchiveStampedContent, unsupportedRuleRefusalContent, admissionWallRefusalContent, hostPostureRefusalContent, toolDeclarationRefusalContent, } from './wireRefusalCopy.js';
|
|
8
|
+
import { usageWindowExhaustedContent, fleetLeaseUnavailableContent, settingsPermissionBucketRefusalContent, fieldLimitRefusalContent, autonomyLaneRefusalContent, sessionArchiveStampedContent, unsupportedRuleRefusalContent, admissionWallRefusalContent, hostPostureRefusalContent, toolDeclarationRefusalContent, envCredentialRefusalContent, sessionIdRetiredContent, runConcurrencyCapContent, } from './wireRefusalCopy.js';
|
|
9
9
|
import { catalogDefaultRefusalContent } from './model/catalogDefault.js';
|
|
10
10
|
const ROLE_BY_READER = new Map([
|
|
11
11
|
[corruptSessionContent, 'replacement'],
|
|
@@ -25,6 +25,9 @@ const ROLE_BY_READER = new Map([
|
|
|
25
25
|
[unsupportedRuleRefusalContent, 'replacement'],
|
|
26
26
|
[projectSeedRefusalContent, 'replacement'],
|
|
27
27
|
[catalogDefaultRefusalContent, 'replacement'],
|
|
28
|
+
[envCredentialRefusalContent, 'replacement'],
|
|
29
|
+
[sessionIdRetiredContent, 'replacement'],
|
|
30
|
+
[runConcurrencyCapContent, 'replacement'],
|
|
28
31
|
[admissionWallRefusalContent, 'supplement'],
|
|
29
32
|
[hostPostureRefusalContent, 'supplement'],
|
|
30
33
|
[toolDeclarationRefusalContent, 'supplement'],
|
package/dist/fleetTaskDesc.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { applyDisplayFace,
|
|
1
|
+
import { applyDisplayFace, displayUntrusted, ESCAPE_FACE } from './displayUntrusted.js';
|
|
2
2
|
export function escapeDisplayControlChars(s) {
|
|
3
3
|
return applyDisplayFace(s, ESCAPE_FACE);
|
|
4
4
|
}
|
|
5
5
|
export function capForDisplay(raw, max) {
|
|
6
|
-
return
|
|
6
|
+
return displayUntrusted(raw, { foldLines: false, escapeBackslashes: 'auto', max: typeof max === 'number' && max > 0 ? max : 0 });
|
|
7
7
|
}
|
|
8
8
|
export function collapseLabel(s) {
|
|
9
|
-
return
|
|
9
|
+
return displayUntrusted(s, { escapeBackslashes: 'auto' });
|
|
10
10
|
}
|
|
11
11
|
export function taskDescFromName(name, agentType, agentName) {
|
|
12
12
|
if (!name || !agentType)
|
|
@@ -74,3 +74,4 @@ export declare const CORE_USER_ATTACHMENT_LABEL_MAX: number;
|
|
|
74
74
|
export declare const CORE_PRESENT_PLAN_TOOL_NAME: "ExitPlanMode";
|
|
75
75
|
export declare const CORE_WORKFLOW_AGENT_PARKED_ERROR_CODE: "workflow.agent_parked";
|
|
76
76
|
export declare const CORE_REFUSAL_ECHO_KINDS: readonly ["path", "command", "pattern"];
|
|
77
|
+
export declare const CORE_DISCARDED_DELIVERY_PATHS: readonly ["live", "box", "drain", "notice"];
|
|
@@ -37,6 +37,7 @@ export const CORE_ENGINE_NOTICE_CODES = Object.freeze([
|
|
|
37
37
|
"permission.rule_store_unavailable",
|
|
38
38
|
"permission.rule_row_dropped",
|
|
39
39
|
"config.session_rules_earlier_grammar",
|
|
40
|
+
"config.legacy_tool_name",
|
|
40
41
|
"permission.allowed_tool_not_granted",
|
|
41
42
|
"mods.registration_refused",
|
|
42
43
|
"peer.inbound_disposition",
|
|
@@ -157,6 +158,7 @@ export const CORE_NOTICE_AUDIENCE = Object.freeze({
|
|
|
157
158
|
"permission.rule_store_unavailable": "user",
|
|
158
159
|
"permission.rule_row_dropped": "user",
|
|
159
160
|
"config.session_rules_earlier_grammar": "user",
|
|
161
|
+
"config.legacy_tool_name": "user",
|
|
160
162
|
"permission.allowed_tool_not_granted": "user",
|
|
161
163
|
"mods.registration_refused": "user",
|
|
162
164
|
"peer.inbound_disposition": "user",
|
|
@@ -283,6 +285,7 @@ export const CORE_NOTICE_MINTER = Object.freeze({
|
|
|
283
285
|
"permission.rule_store_unavailable": "engine",
|
|
284
286
|
"permission.rule_row_dropped": "engine",
|
|
285
287
|
"config.session_rules_earlier_grammar": "engine",
|
|
288
|
+
"config.legacy_tool_name": "engine",
|
|
286
289
|
"permission.allowed_tool_not_granted": "engine",
|
|
287
290
|
"mods.registration_refused": "engine",
|
|
288
291
|
"peer.inbound_disposition": "engine",
|
|
@@ -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 { approvalUnreadableWhyWordOf } 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 (typeof why === 'string' ? approvalUnreadableWhyWordOf(why) : undefined) {
|
|
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,7 @@ export function approvalCardReasons(card, opts, lang) {
|
|
|
64
82
|
catch {
|
|
65
83
|
denialLimitReadable = false;
|
|
66
84
|
}
|
|
67
|
-
add('payload_unreadable', () => (ownData(card, 'cardPayloadUnreadable') === true ? payloadUnreadableDetail(lang) : undefined));
|
|
85
|
+
add('payload_unreadable', () => (ownData(card, 'cardPayloadUnreadable') === true ? payloadUnreadableDetail(ownData(card, 'cardPayloadUnreadableWhy'), lang) : undefined));
|
|
68
86
|
add('prior_cards', () => approvalPriorCardsDetail(card, lang));
|
|
69
87
|
add('message', () => {
|
|
70
88
|
const engineMessage = ownData(card, 'message');
|
|
@@ -73,7 +91,7 @@ export function approvalCardReasons(card, opts, lang) {
|
|
|
73
91
|
const tool = ownData(card, 'toolName');
|
|
74
92
|
if (typeof tool === 'string' && engineMessage.trim() === `approval required for "${tool}"`)
|
|
75
93
|
return undefined;
|
|
76
|
-
return
|
|
94
|
+
return engineMessageLine(engineMessage);
|
|
77
95
|
});
|
|
78
96
|
add('mandated', () => (approvalIsMandated(card) ? mandatedApprovalDetailOf(card, lang) : undefined));
|
|
79
97
|
add('mandate', () => {
|
|
@@ -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
|
+
}
|
|
@@ -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('');
|
|
@@ -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';
|
|
@@ -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
|
}
|
package/dist/hitl/frameRouter.js
CHANGED
|
@@ -32,7 +32,11 @@ export function policyDenyReason(facts) {
|
|
|
32
32
|
const one = typeof facts.toolName === 'string' && SENTENCE_TOOL_NAME.test(facts.toolName) ? `this one "${facts.toolName}" call` : 'this one call';
|
|
33
33
|
const flag = typeof facts.allowRuleFlag === 'string' && SENTENCE_TOOL_NAME.test(facts.allowRuleFlag.replace(/^--?/, '')) ? ` (or ${facts.allowRuleFlag})` : '';
|
|
34
34
|
const budgetKnob = typeof facts.budgetSetting === 'string' && SENTENCE_TOOL_NAME.test(facts.budgetSetting) ? facts.budgetSetting : undefined;
|
|
35
|
-
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';
|
|
36
40
|
if (facts.lane === 'dont_ask') {
|
|
37
41
|
const mode = 'denied by the dontAsk permission mode';
|
|
38
42
|
switch (cause) {
|
|
@@ -44,6 +48,8 @@ export function policyDenyReason(facts) {
|
|
|
44
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`;
|
|
45
49
|
case 'budget':
|
|
46
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`;
|
|
47
53
|
default:
|
|
48
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`;
|
|
49
55
|
}
|
|
@@ -59,6 +65,8 @@ export function policyDenyReason(facts) {
|
|
|
59
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`;
|
|
60
66
|
case 'budget':
|
|
61
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`;
|
|
62
70
|
default:
|
|
63
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`;
|
|
64
72
|
}
|
|
@@ -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
|
@@ -270,11 +270,8 @@ export async function findPendingForTask(client, taskId, matches, opts, callId,
|
|
|
270
270
|
return { ok: false, reason: `approvals.list failed: ${t.reason}` };
|
|
271
271
|
}
|
|
272
272
|
const readings = rows.flatMap((r) => {
|
|
273
|
-
const
|
|
274
|
-
|
|
275
|
-
return [];
|
|
276
|
-
const cp = r;
|
|
277
|
-
return [{ r: cp, foreign: sort === 'unreadable' ? QUEUE_ROW_FAMILY_UNREADABLE_GATE : askParkForeignGateKind(cp) }];
|
|
273
|
+
const x = checkpointQueueReadingOf(r);
|
|
274
|
+
return x === undefined ? [] : [x];
|
|
278
275
|
});
|
|
279
276
|
const decidable = readings.filter((x) => x.foreign === null).map((x) => x.r);
|
|
280
277
|
const identityRow = callId !== undefined
|
|
@@ -313,6 +310,13 @@ export async function findPendingForTask(client, taskId, matches, opts, callId,
|
|
|
313
310
|
return { ok: false, reason: checkpointRowBarSentence(bar), code: 'row_unresumable', rowVerdict: bar };
|
|
314
311
|
return { ok: true, pending, gatedCallId: pending.toolCallId ?? pending.boundCallId ?? undefined };
|
|
315
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
|
+
}
|
|
316
320
|
export class HitlBridge {
|
|
317
321
|
client;
|
|
318
322
|
taskId;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { isApprovalRequestFrameV1 } from '@sema-agent/sdk';
|
|
2
|
-
import { appendOwnElement } from '../ownKey.js';
|
|
2
|
+
import { appendOwnElement, readOwnDataNonEmptyString } from '../ownKey.js';
|
|
3
3
|
import { readRequiresRealApproval } from './approvalCardReading.js';
|
|
4
4
|
import { pendingRowIsOfSession } from './parkRowDelegation.js';
|
|
5
5
|
import { approvalLiveFaceOf, liveFaceCarried } from './approvalLiveFace.js';
|
|
6
6
|
import { THROWN_SLOT_UNREADABLE, readThrownSlot } from '../wireFailureShape.js';
|
|
7
|
-
import { isToolApprovalFrame,
|
|
7
|
+
import { isToolApprovalFrame, surfaceApprovalFrameWithId, } from './toolApprovalWire.js';
|
|
8
8
|
function nonEmptyString(v) {
|
|
9
9
|
return typeof v === 'string' && v !== '';
|
|
10
10
|
}
|
|
@@ -24,7 +24,9 @@ function snapshotMembers(raw) {
|
|
|
24
24
|
}
|
|
25
25
|
return raw.length === length ? out : undefined;
|
|
26
26
|
}
|
|
27
|
-
function openingFrameOf(f) {
|
|
27
|
+
function openingFrameOf(f, approvalId) {
|
|
28
|
+
if (typeof f !== 'object' || f === null || readOwnDataNonEmptyString(f, 'approvalId') !== approvalId)
|
|
29
|
+
return undefined;
|
|
28
30
|
if (isToolApprovalFrame(f))
|
|
29
31
|
return f.type === 'tool_approval' ? f : undefined;
|
|
30
32
|
return isApprovalRequestFrameV1(f) ? f : undefined;
|
|
@@ -54,19 +56,19 @@ export function readLivePendingRows(body) {
|
|
|
54
56
|
continue;
|
|
55
57
|
}
|
|
56
58
|
const o = item;
|
|
57
|
-
|
|
59
|
+
const approvalId = readOwnDataNonEmptyString(o, 'approvalId');
|
|
60
|
+
if (approvalId === undefined || !nonEmptyString(o.toolName) || !nonNegativeFinite(o.ts) || !nonNegativeFinite(o.expiresAtMs)) {
|
|
58
61
|
dropped++;
|
|
59
62
|
continue;
|
|
60
63
|
}
|
|
61
|
-
if (seen.has(
|
|
64
|
+
if (seen.has(approvalId)) {
|
|
62
65
|
dropped++;
|
|
63
66
|
continue;
|
|
64
67
|
}
|
|
65
|
-
seen.add(
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
approvalId: o.approvalId,
|
|
68
|
+
seen.add(approvalId);
|
|
69
|
+
const frame = openingFrameOf(o.frame, approvalId);
|
|
70
|
+
appendOwnElement(rows, {
|
|
71
|
+
approvalId,
|
|
70
72
|
toolName: o.toolName,
|
|
71
73
|
ts: o.ts,
|
|
72
74
|
expiresAtMs: o.expiresAtMs,
|
|
@@ -147,13 +149,12 @@ export function livePendingRowToApprovalFrame(row) {
|
|
|
147
149
|
};
|
|
148
150
|
}
|
|
149
151
|
export function surfaceSuspendedAskAndRespond(row, respond, signal, lane) {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
+
const frame = row.frame;
|
|
153
|
+
const approvalId = row.approvalId;
|
|
154
|
+
if (frame !== undefined) {
|
|
155
|
+
return surfaceApprovalFrameWithId(frame, approvalId, respond, undefined, signal, lane, undefined);
|
|
152
156
|
}
|
|
153
|
-
return
|
|
154
|
-
...lane,
|
|
155
|
-
argsUnavailable: true,
|
|
156
|
-
});
|
|
157
|
+
return surfaceApprovalFrameWithId(livePendingRowToApprovalFrame(row), approvalId, respond, undefined, signal, { ...lane, argsUnavailable: true }, undefined);
|
|
157
158
|
}
|
|
158
159
|
const TRACKER_UNSEEN_CLAIMS_MAX = 512;
|
|
159
160
|
export function createSuspendedAskTracker(filter) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { reasonOfThrownWithSink } from '../hostCallbackGuard.js';
|
|
2
|
+
import { isWholeToolRuleValue } from './permissionRuleScope.js';
|
|
2
3
|
const BASH_TOOL_NAME_FOR_RULES = 'Bash';
|
|
3
4
|
export function parseLocalAllowRule(rule, expectedToolName, deps) {
|
|
4
5
|
if (typeof rule !== 'string' || rule === '') {
|
|
@@ -14,7 +15,7 @@ export function parseLocalAllowRule(rule, expectedToolName, deps) {
|
|
|
14
15
|
if (typeof value.toolName !== 'string' || value.toolName === '') {
|
|
15
16
|
return { ok: false, error: 'rule text carries no tool name' };
|
|
16
17
|
}
|
|
17
|
-
if (value
|
|
18
|
+
if (isWholeToolRuleValue(value)) {
|
|
18
19
|
return {
|
|
19
20
|
ok: false,
|
|
20
21
|
error: 'candidate is a whole-tool allow rule (broader than this ask) — not offered locally',
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type NoAllowCause = 'no_allow_rule' | 'ask_rule' | 'engine_ask_rule' | 'budget' | 'other';
|
|
1
|
+
export type NoAllowCause = 'no_allow_rule' | 'ask_rule' | 'engine_ask_rule' | 'budget' | 'whole_tool_rule_only' | 'other';
|
|
2
2
|
export interface RuleLadderNoAllowFacts {
|
|
3
3
|
readonly allowed?: boolean;
|
|
4
4
|
readonly denied?: boolean;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { askLevelVerdict } from './automaticAnswerVerdict.js';
|
|
2
2
|
function ladderSays(ladder, key) {
|
|
3
3
|
if (typeof ladder !== 'object' || ladder === null)
|
|
4
4
|
return false;
|
|
@@ -17,11 +17,13 @@ export function noAllowCauseOf(card, ladder) {
|
|
|
17
17
|
return 'ask_rule';
|
|
18
18
|
if (ladderSays(ladder, 'budgetExhausted'))
|
|
19
19
|
return 'budget';
|
|
20
|
-
const standing =
|
|
20
|
+
const standing = askLevelVerdict(card, 'standing_rule');
|
|
21
21
|
if (standing.kind === 'must_ask' && (standing.askClass === 'ask_rule' || standing.origin === 'ask_rule')) {
|
|
22
22
|
return ladderSays(ladder, 'noAskRuleMatched') || ladderSays(ladder, 'noRuleMatched') ? 'engine_ask_rule' : 'ask_rule';
|
|
23
23
|
}
|
|
24
24
|
if (ladderSays(ladder, 'noRuleMatched') && standing.kind === 'may_answer')
|
|
25
25
|
return 'no_allow_rule';
|
|
26
|
+
if (standing.kind === 'may_answer')
|
|
27
|
+
return 'whole_tool_rule_only';
|
|
26
28
|
return 'other';
|
|
27
29
|
}
|
|
@@ -1,11 +1,36 @@
|
|
|
1
|
+
import { isApprovalCompleteFrameV1 } from '@sema-agent/sdk';
|
|
1
2
|
import { APPROVAL_EXPIRED } from '../engineErrorCodes.js';
|
|
2
3
|
import { approvalCompleteParked } from './approvalCompleteParked.js';
|
|
3
4
|
export function classifyApprovalCompleteFrame(frame) {
|
|
4
5
|
if (typeof frame !== 'object' || frame === null)
|
|
5
6
|
return null;
|
|
6
7
|
const f = frame;
|
|
7
|
-
|
|
8
|
+
const type = f.type;
|
|
9
|
+
if (type === 'tool_approval_complete')
|
|
10
|
+
return dispositionOf(frame, f);
|
|
11
|
+
if (type === 'approval_complete')
|
|
12
|
+
return presentedFamilyDisposition(frame);
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
function presentedFamilyDisposition(frame) {
|
|
16
|
+
try {
|
|
17
|
+
const snapshot = ownDataSnapshot(frame);
|
|
18
|
+
return isApprovalCompleteFrameV1(snapshot) ? dispositionOf(snapshot, snapshot) : null;
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
8
21
|
return null;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function ownDataSnapshot(frame) {
|
|
25
|
+
const snapshot = Object.create(null);
|
|
26
|
+
for (const key of Object.getOwnPropertyNames(frame)) {
|
|
27
|
+
const d = Object.getOwnPropertyDescriptor(frame, key);
|
|
28
|
+
if (d !== undefined && Object.hasOwn(d, 'value'))
|
|
29
|
+
snapshot[key] = d.value;
|
|
30
|
+
}
|
|
31
|
+
return snapshot;
|
|
32
|
+
}
|
|
33
|
+
function dispositionOf(frame, f) {
|
|
9
34
|
const outcome = f.outcome;
|
|
10
35
|
if (outcome === 'allowed' || outcome === 'denied')
|
|
11
36
|
return 'settled';
|
|
@@ -6,5 +6,7 @@ export interface ParkOwnershipDeps {
|
|
|
6
6
|
isOwnRun?: (taskIdTail: string) => boolean;
|
|
7
7
|
}
|
|
8
8
|
export declare function pendingRowIsOwnedByThisSession(row: PendingCheckpoint, deps?: ParkOwnershipDeps): boolean;
|
|
9
|
+
export declare function pendingRowOwnershipOf(row: object, deps?: ParkOwnershipDeps): 'owned' | 'foreign' | 'unknown';
|
|
10
|
+
export declare function usableAskQuestions(value: unknown): AskQuestion[] | null;
|
|
9
11
|
export declare function askQuestionsFromPending(pending: PendingCheckpoint): AskQuestion[] | null;
|
|
10
12
|
export declare function isHitlSafetyErrorLike(e: unknown): boolean;
|