@sema-agent/client-core 0.105.0 → 0.107.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 +301 -0
- package/README.md +40 -21
- package/dist/adapt/arms.js +10 -1
- package/dist/adapter/activeRunSelfHeal.d.ts +21 -2
- package/dist/adapter/activeRunSelfHeal.js +129 -28
- package/dist/adapter/downstream/eventToSdkMessage.d.ts +0 -5
- package/dist/adapter/downstream/eventToSdkMessage.js +20 -19
- package/dist/adapter/downstream/terminalToSdkResult.js +2 -3
- package/dist/adapter/downstream/wiringManifestView.d.ts +1 -3
- package/dist/adapter/downstream/wiringManifestView.js +0 -1
- package/dist/adapter/runStream.js +3 -4
- package/dist/approvalReachWire.d.ts +1 -0
- package/dist/approvalReachWire.js +4 -1
- package/dist/approvalSeat.d.ts +21 -0
- package/dist/approvalSeat.js +73 -0
- package/dist/assistantInbox.d.ts +2 -0
- package/dist/assistantInbox.js +3 -0
- package/dist/checkpointRowVerdict.d.ts +29 -0
- package/dist/checkpointRowVerdict.js +98 -0
- package/dist/coreValuePorts.d.ts +12 -1
- package/dist/coreValuePorts.js +10 -0
- package/dist/decideFailureNote.js +3 -1
- package/dist/decideReceipt.d.ts +9 -0
- package/dist/decideReceipt.js +29 -1
- package/dist/declared/supportFloorDeclared.js +2 -2
- package/dist/deviceRebind.d.ts +7 -0
- package/dist/deviceRebind.js +39 -5
- package/dist/displayUntrusted.d.ts +5 -3
- package/dist/displayUntrusted.js +50 -41
- package/dist/engineAddress.d.ts +3 -0
- package/dist/engineAddress.js +25 -0
- package/dist/engineDirectory.js +9 -17
- package/dist/engineErrorCodes.d.ts +8 -0
- package/dist/engineErrorCodes.js +8 -0
- package/dist/engineNoticeCodes.d.ts +38 -3
- package/dist/engineNoticeCodes.js +167 -11
- package/dist/engineRowRef.js +1 -1
- package/dist/errorSupplementRoles.js +4 -1
- package/dist/eventLeg.d.ts +2 -2
- package/dist/eventLeg.js +2 -1
- package/dist/executionLaneCapability.js +3 -2
- package/dist/executionLaneWords.d.ts +1 -0
- package/dist/executionLaneWords.js +3 -0
- package/dist/fleet/fleetProjection.js +26 -5
- package/dist/generated/engineFactTables.d.ts +2 -1
- package/dist/generated/engineFactTables.js +3 -1
- package/dist/generated/engineNoticeTables.js +28 -7
- package/dist/generated/sdkFactTables.d.ts +3 -0
- package/dist/generated/sdkFactTables.js +15 -0
- package/dist/generated/settingsSchemaFns.d.ts +11 -0
- package/dist/generated/settingsSchemaFns.js +2 -1
- package/dist/generated/settingsSchemaSafetyMergeSpec.js +1 -1
- package/dist/generated/settingsSchemaSettingsSources.d.ts +1 -1
- package/dist/generated/settingsSchemaSettingsSources.js +22 -2
- package/dist/hitl/approvalLiveFace.d.ts +17 -0
- package/dist/hitl/approvalLiveFace.js +35 -0
- package/dist/hitl/approvalQueueRow.d.ts +21 -0
- package/dist/hitl/approvalQueueRow.js +69 -0
- package/dist/hitl/approvalResolution.d.ts +5 -1
- package/dist/hitl/approvalResolution.js +18 -1
- package/dist/hitl/approvalsFeed.d.ts +5 -4
- package/dist/hitl/approvalsFeed.js +39 -6
- package/dist/hitl/askParkRowRouting.d.ts +4 -3
- package/dist/hitl/askParkRowRouting.js +27 -3
- package/dist/hitl/automaticAnswerVerdict.js +13 -10
- package/dist/hitl/crashConverged.d.ts +5 -1
- package/dist/hitl/decisionConflict.js +2 -1
- package/dist/hitl/decisionRefusal.js +1 -1
- package/dist/hitl/decisionSend.d.ts +3 -0
- package/dist/hitl/decisionSend.js +32 -6
- package/dist/hitl/frameRouter.js +4 -5
- package/dist/hitl/hitlBridge.d.ts +6 -2
- package/dist/hitl/hitlBridge.js +53 -7
- package/dist/hitl/livePendingAsk.d.ts +5 -0
- package/dist/hitl/livePendingAsk.js +10 -3
- package/dist/hitl/parkOwnership.js +4 -5
- package/dist/hitl/parkResolver.js +9 -5
- package/dist/hitl/parkRowBirthWait.d.ts +7 -0
- package/dist/hitl/parkRowBirthWait.js +1 -1
- package/dist/hitl/parkRowDelegation.d.ts +6 -0
- package/dist/hitl/parkRowDelegation.js +33 -0
- package/dist/hitl/persistedRulesWire.d.ts +15 -3
- package/dist/hitl/persistedRulesWire.js +102 -20
- package/dist/hitl/planReviewCard.d.ts +2 -0
- package/dist/hitl/planReviewCard.js +21 -0
- package/dist/hitl/planReviewWire.d.ts +2 -2
- package/dist/hitl/planReviewWire.js +105 -38
- package/dist/hitl/sessionAllowRoute.d.ts +7 -0
- package/dist/hitl/sessionAllowRoute.js +49 -0
- package/dist/hitl/sessionPolicyWire.d.ts +1 -7
- package/dist/hitl/sessionPolicyWire.js +3 -43
- package/dist/hitl/standingRows.js +10 -10
- package/dist/hitl/subagentSource.d.ts +1 -0
- package/dist/hitl/subagentSource.js +13 -0
- package/dist/hitl/toolApprovalWire.d.ts +3 -2
- package/dist/hitl/toolApprovalWire.js +100 -44
- package/dist/hostSettingsSource.d.ts +4 -1
- package/dist/hostSettingsSource.js +11 -6
- package/dist/hostTurnSettings.d.ts +4 -5
- package/dist/hostTurnSettings.js +80 -19
- package/dist/i18n/messages.en.d.ts +41 -12
- package/dist/i18n/messages.en.js +42 -13
- package/dist/i18n/messages.zh.js +45 -13
- package/dist/index.d.ts +22 -2
- package/dist/index.js +12 -2
- package/dist/injectionLaneNotice.js +2 -1
- package/dist/liveInitToolFace.js +0 -1
- package/dist/liveModelCatalog.d.ts +15 -0
- package/dist/liveModelCatalog.js +40 -0
- package/dist/mcpWireCaps.js +1 -1
- package/dist/modelCapabilityProbe.js +66 -33
- package/dist/noticePresentation.js +2 -0
- package/dist/ownKey.d.ts +0 -1
- package/dist/ownKey.js +0 -2
- package/dist/permissionsDeclaration.d.ts +2 -2
- package/dist/permissionsDeclaration.js +12 -14
- package/dist/projectSeed.d.ts +39 -0
- package/dist/projectSeed.js +80 -0
- package/dist/promptDelivery.js +1 -1
- package/dist/replayBody.d.ts +7 -6
- package/dist/replayBody.js +62 -7
- package/dist/request/taskRequest.js +3 -4
- package/dist/ruleCompileVerdict.d.ts +0 -2
- package/dist/ruleCompileVerdict.js +0 -31
- package/dist/ruleRefusalSentence.js +0 -3
- package/dist/runReattachPolicy.d.ts +3 -0
- package/dist/runReattachPolicy.js +15 -2
- package/dist/runTerminal.js +30 -8
- package/dist/sandboxWire.d.ts +0 -3
- package/dist/sandboxWire.js +0 -9
- package/dist/sdkWireTransit.d.ts +1 -1
- package/dist/seam.d.ts +14 -7
- package/dist/seam.js +12 -0
- package/dist/seatContract.d.ts +58 -7
- package/dist/seatContract.js +135 -4
- package/dist/serverSupportRange.d.ts +18 -0
- package/dist/serverSupportRange.js +25 -0
- package/dist/sessionEngine.d.ts +156 -0
- package/dist/sessionEngine.js +464 -0
- package/dist/sessionMap.d.ts +11 -1
- package/dist/sessionMap.js +35 -9
- package/dist/sessionMemorySync.d.ts +31 -0
- package/dist/sessionMemorySync.js +95 -0
- package/dist/sessionRowTag.d.ts +4 -0
- package/dist/sessionRowTag.js +18 -0
- package/dist/settingsLayerAdmission.d.ts +1 -0
- package/dist/settingsLayerAdmission.js +4 -1
- package/dist/toolResult.js +1 -1
- package/dist/wireRefusalCopy.d.ts +6 -1
- package/dist/wireRefusalCopy.js +9 -7
- package/docs/INTEGRATION-CLIENTS.md +1393 -18
- package/package.json +5 -5
|
@@ -53,7 +53,7 @@ export const SETTINGS_SAFETY_MERGE_CLOSURE = (MIN_TRUST_WORDS) => {
|
|
|
53
53
|
model: { mergeShape: "replace", minTrust: "session", tighten: { rule: "none" }, enforcement: "client", fail: "open", seam: "RoleSpec / TaskSpec.{model,thinking}" },
|
|
54
54
|
env: { mergeShape: "concat", minTrust: "project", tighten: { rule: "none" }, enforcement: "resolver", fail: "open", seam: "NodeExecutionEnv.shellEnv (later layer overrides same name)" },
|
|
55
55
|
envSecret: { mergeShape: "replace", minTrust: "global", tighten: { rule: "none" }, enforcement: "resolver", fail: "closed", seam: "§7 secret-ref resolution" },
|
|
56
|
-
memoryScopes: { mergeShape: "concat", minTrust: "global", tighten: { rule: "none" }, enforcement: "client", fail: "open", seam: "
|
|
56
|
+
memoryScopes: { mergeShape: "concat", minTrust: "global", tighten: { rule: "none" }, enforcement: "client", fail: "open", seam: "MemoryEngine" },
|
|
57
57
|
autoCompaction: { mergeShape: "replace", minTrust: "session", tighten: { rule: "none" }, enforcement: "client", fail: "open", seam: "compaction config" },
|
|
58
58
|
ui: { mergeShape: "replace", minTrust: "local", tighten: { rule: "none" }, enforcement: "client", fail: "open", seam: "shell-only (theme/keybindings/statusLine) — never touches the engine" },
|
|
59
59
|
org: { mergeShape: "replace", minTrust: "managed", tighten: { rule: "none" }, enforcement: "server", fail: "closed", seam: "web-admin → governanceBaseline (SSO/SCIM/audit/budget, TOB-only)" },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const SETTINGS_LAYER_SOURCES_CLOSURE: (SAFETY_MERGE_SPEC: object, isAtLeast: (layer: string, minTrust: string) => boolean, memberAdmission: (category: string, member: string) => object) => any;
|
|
1
|
+
export declare const SETTINGS_LAYER_SOURCES_CLOSURE: (SAFETY_MERGE_SPEC: object, isAtLeast: (layer: string, minTrust: string) => boolean, memberAdmission: (category: string, member: string) => object, echoCallerText: (text: string) => string, stripControlAndBidi: (text: string) => string) => any;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const SETTINGS_LAYER_SOURCES_CLOSURE = (SAFETY_MERGE_SPEC, isAtLeast, memberAdmission) => {
|
|
1
|
+
export const SETTINGS_LAYER_SOURCES_CLOSURE = (SAFETY_MERGE_SPEC, isAtLeast, memberAdmission, echoCallerText, stripControlAndBidi) => {
|
|
2
2
|
const SETTINGS_SOURCES = ["userSettings", "projectSettings", "localSettings", "flagSettings", "policySettings", "foreignProjectSettings"];
|
|
3
3
|
const SETTINGS_SOURCE_CONTRACT = {
|
|
4
4
|
userSettings: { trust: "global", repoControllable: false },
|
|
@@ -41,6 +41,26 @@ export const SETTINGS_LAYER_SOURCES_CLOSURE = (SAFETY_MERGE_SPEC, isAtLeast, mem
|
|
|
41
41
|
const accepted = workspaceAccepted(workspace);
|
|
42
42
|
return layer.tightenOnly === true || (layer.repoControllable && !accepted);
|
|
43
43
|
}
|
|
44
|
+
const LAYER_PARTS_UNREAD_CODE = "settings.layer_parts_unread";
|
|
45
|
+
const NOTICE_PARTS_SHOWN = 16;
|
|
46
|
+
function buildLayerPartsUnreadNotice(input) {
|
|
47
|
+
const layer = settingsSourceContract(input.source);
|
|
48
|
+
if (!readsTightenOnly(layer, input.workspace)) {
|
|
49
|
+
throw new RangeError(`buildLayerPartsUnreadNotice: source '${input.source}' is not read in the tighten direction only under workspace reading '${input.workspace}' — there is nothing "read for restrictions only" to disclose`);
|
|
50
|
+
}
|
|
51
|
+
if (input.parts.length === 0)
|
|
52
|
+
return undefined;
|
|
53
|
+
const cause = layer.tightenOnly === true ? "it is written for another tool" : "this workspace is not trusted";
|
|
54
|
+
const shown = input.parts.slice(0, NOTICE_PARTS_SHOWN).map(echoCallerText);
|
|
55
|
+
const rest = input.parts.length - shown.length;
|
|
56
|
+
const named = rest > 0 ? `${shown.join(", ")}, +${rest} more` : shown.join(", ");
|
|
57
|
+
return {
|
|
58
|
+
code: LAYER_PARTS_UNREAD_CODE,
|
|
59
|
+
source: input.source,
|
|
60
|
+
parts: [...input.parts],
|
|
61
|
+
line: `${stripControlAndBidi(input.file)}: read for restrictions only (${cause}) — not read: ${named}`,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
44
64
|
function workspaceAccepted(workspace) {
|
|
45
65
|
switch (workspace) {
|
|
46
66
|
case "accepted":
|
|
@@ -54,5 +74,5 @@ export const SETTINGS_LAYER_SOURCES_CLOSURE = (SAFETY_MERGE_SPEC, isAtLeast, mem
|
|
|
54
74
|
}
|
|
55
75
|
}
|
|
56
76
|
}
|
|
57
|
-
return { layerAdmission };
|
|
77
|
+
return { layerAdmission, buildLayerPartsUnreadNotice };
|
|
58
78
|
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ApprovalMandateWord } from '../gateVocabulary.js';
|
|
2
|
+
export declare const APPROVAL_LIVE_FACE_KEYS: readonly ["mandate", "mandated", "origin"];
|
|
3
|
+
export declare function hasOwnStrictTrue(v: object, key: string): boolean;
|
|
4
|
+
export interface ApprovalLiveFaceFacts {
|
|
5
|
+
mandated?: true;
|
|
6
|
+
mandate?: ApprovalMandateWord;
|
|
7
|
+
origin?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface ApprovalLiveFace {
|
|
10
|
+
readonly facts: Readonly<ApprovalLiveFaceFacts>;
|
|
11
|
+
readonly layerUnknown?: 'marked' | 'absent';
|
|
12
|
+
}
|
|
13
|
+
export declare function approvalLiveFaceOf(live: object): ApprovalLiveFace;
|
|
14
|
+
export type ApprovalLiveFaceCarried = ApprovalLiveFaceFacts & {
|
|
15
|
+
readonly liveFactsUnknown?: true;
|
|
16
|
+
};
|
|
17
|
+
export declare function liveFaceCarried(face: ApprovalLiveFace): ApprovalLiveFaceCarried;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { readAskOrigin } from '../ownKey.js';
|
|
2
|
+
import { slotPresenceOf, slotReadOf } from '../wireFailureShape.js';
|
|
3
|
+
import { readApprovalMandate } from './toolApprovalWire.js';
|
|
4
|
+
export const APPROVAL_LIVE_FACE_KEYS = Object.freeze(['mandate', 'mandated', 'origin']);
|
|
5
|
+
export function hasOwnStrictTrue(v, key) {
|
|
6
|
+
return Object.hasOwn(v, key) && v[key] === true;
|
|
7
|
+
}
|
|
8
|
+
const APPROVAL_LIVE_FACTS_UNKNOWN_KEY = 'liveFactsUnknown';
|
|
9
|
+
function guarded(read) {
|
|
10
|
+
try {
|
|
11
|
+
return read();
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export function approvalLiveFaceOf(live) {
|
|
18
|
+
const marker = slotReadOf(live, APPROVAL_LIVE_FACTS_UNKNOWN_KEY);
|
|
19
|
+
const marked = marker.presence === 'unreadable' || (marker.presence === 'present' && marker.value === true);
|
|
20
|
+
const layerAbsent = !marked && APPROVAL_LIVE_FACE_KEYS.every((k) => slotPresenceOf(live, k) === 'absent');
|
|
21
|
+
const facts = {};
|
|
22
|
+
if (guarded(() => hasOwnStrictTrue(live, 'mandated')) === true)
|
|
23
|
+
facts.mandated = true;
|
|
24
|
+
const mandate = guarded(() => readApprovalMandate(live));
|
|
25
|
+
if (mandate !== undefined)
|
|
26
|
+
facts.mandate = mandate;
|
|
27
|
+
const origin = guarded(() => readAskOrigin(live));
|
|
28
|
+
if (origin !== undefined)
|
|
29
|
+
facts.origin = origin;
|
|
30
|
+
const layerUnknown = marked ? 'marked' : layerAbsent ? 'absent' : undefined;
|
|
31
|
+
return Object.freeze({ facts: Object.freeze(facts), ...(layerUnknown !== undefined ? { layerUnknown } : {}) });
|
|
32
|
+
}
|
|
33
|
+
export function liveFaceCarried(face) {
|
|
34
|
+
return face.layerUnknown === 'marked' ? { ...face.facts, [APPROVAL_LIVE_FACTS_UNKNOWN_KEY]: true } : { ...face.facts };
|
|
35
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { SDK_APPROVAL_QUEUE_KINDS } from '../generated/sdkFactTables.js';
|
|
2
|
+
export type ApprovalQueueKind = (typeof SDK_APPROVAL_QUEUE_KINDS)[number];
|
|
3
|
+
export type ApprovalQueueRowFamily = ApprovalQueueKind | 'unknown' | 'unreadable';
|
|
4
|
+
export declare function approvalQueueRowFamilyOf(row: object): ApprovalQueueRowFamily;
|
|
5
|
+
export type CheckpointQueueRowSort = 'checkpoint' | 'excluded' | 'unreadable';
|
|
6
|
+
export declare function checkpointQueueRowSortOf(row: object | null | undefined): CheckpointQueueRowSort;
|
|
7
|
+
export declare const QUEUE_ROW_FAMILY_UNREADABLE_GATE = "(unreadable)";
|
|
8
|
+
export interface ApprovalQueuePeerInboundRow {
|
|
9
|
+
readonly id: string;
|
|
10
|
+
readonly recipientSessionId: string;
|
|
11
|
+
readonly lane?: string;
|
|
12
|
+
readonly cause?: string;
|
|
13
|
+
readonly content?: string;
|
|
14
|
+
readonly sentAt?: number;
|
|
15
|
+
readonly heldAt?: number;
|
|
16
|
+
readonly deadline?: number;
|
|
17
|
+
readonly fromSession?: string;
|
|
18
|
+
readonly fromName?: string;
|
|
19
|
+
readonly fromScope?: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function peerInboundQueueRowOf(row: object): ApprovalQueuePeerInboundRow | undefined;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { slotReadOf } from '../wireFailureShape.js';
|
|
2
|
+
import { SDK_APPROVAL_QUEUE_KINDS } from '../generated/sdkFactTables.js';
|
|
3
|
+
const _queueKindsPin = true;
|
|
4
|
+
void _queueKindsPin;
|
|
5
|
+
const isApprovalQueueKind = (v) => SDK_APPROVAL_QUEUE_KINDS.includes(v);
|
|
6
|
+
export function approvalQueueRowFamilyOf(row) {
|
|
7
|
+
const kind = slotReadOf(row, 'kind');
|
|
8
|
+
if (kind.presence === 'absent')
|
|
9
|
+
return 'checkpoint';
|
|
10
|
+
if (kind.presence !== 'present' || typeof kind.value !== 'string')
|
|
11
|
+
return 'unreadable';
|
|
12
|
+
return isApprovalQueueKind(kind.value) ? kind.value : 'unknown';
|
|
13
|
+
}
|
|
14
|
+
export function checkpointQueueRowSortOf(row) {
|
|
15
|
+
try {
|
|
16
|
+
if (typeof row !== 'object' || row === null || Array.isArray(row))
|
|
17
|
+
return 'excluded';
|
|
18
|
+
const family = approvalQueueRowFamilyOf(row);
|
|
19
|
+
return family === 'checkpoint' ? 'checkpoint' : family === 'unreadable' ? 'unreadable' : 'excluded';
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return 'unreadable';
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export const QUEUE_ROW_FAMILY_UNREADABLE_GATE = '(unreadable)';
|
|
26
|
+
const ownString = (row, key, nonEmpty) => {
|
|
27
|
+
const r = slotReadOf(row, key);
|
|
28
|
+
return r.presence === 'present' && typeof r.value === 'string' && (!nonEmpty || r.value !== '') ? r.value : undefined;
|
|
29
|
+
};
|
|
30
|
+
const ownTime = (row, key) => {
|
|
31
|
+
const r = slotReadOf(row, key);
|
|
32
|
+
return r.presence === 'present' && typeof r.value === 'number' && Number.isFinite(r.value) && r.value >= 0 ? r.value : undefined;
|
|
33
|
+
};
|
|
34
|
+
export function peerInboundQueueRowOf(row) {
|
|
35
|
+
try {
|
|
36
|
+
const id = ownString(row, 'id', true);
|
|
37
|
+
const recipientSessionId = ownString(row, 'recipientSessionId', true);
|
|
38
|
+
if (id === undefined || recipientSessionId === undefined)
|
|
39
|
+
return undefined;
|
|
40
|
+
const out = { id, recipientSessionId };
|
|
41
|
+
const lane = ownString(row, 'lane', true);
|
|
42
|
+
if (lane !== undefined)
|
|
43
|
+
out.lane = lane;
|
|
44
|
+
const cause = ownString(row, 'cause', true);
|
|
45
|
+
if (cause !== undefined)
|
|
46
|
+
out.cause = cause;
|
|
47
|
+
const content = ownString(row, 'content', false);
|
|
48
|
+
if (content !== undefined)
|
|
49
|
+
out.content = content;
|
|
50
|
+
const sentAt = ownTime(row, 'sentAt');
|
|
51
|
+
if (sentAt !== undefined)
|
|
52
|
+
out.sentAt = sentAt;
|
|
53
|
+
const heldAt = ownTime(row, 'heldAt');
|
|
54
|
+
if (heldAt !== undefined)
|
|
55
|
+
out.heldAt = heldAt;
|
|
56
|
+
const deadline = ownTime(row, 'deadline');
|
|
57
|
+
if (deadline !== undefined)
|
|
58
|
+
out.deadline = deadline;
|
|
59
|
+
for (const k of ['fromSession', 'fromName', 'fromScope']) {
|
|
60
|
+
const v = ownString(row, k, true);
|
|
61
|
+
if (v !== undefined)
|
|
62
|
+
out[k] = v;
|
|
63
|
+
}
|
|
64
|
+
return Object.freeze(out);
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -4,9 +4,10 @@ import type { AskAnsweredOutput } from './gateLedger.js';
|
|
|
4
4
|
import type { ApprovalDenySettledBy, ToolApprovalRespondAckView, ToolApprovalRespondDecision, ToolApprovalRespondParkingView } from './toolApprovalWire.js';
|
|
5
5
|
import { type DecisionRefusalReading, type RefusalRouteContext } from './decisionRefusal.js';
|
|
6
6
|
import { type DeliveredReading, type LadderSafetyStop } from './attributionLadder.js';
|
|
7
|
+
import { type CheckpointRowVerdictReading } from '../checkpointRowVerdict.js';
|
|
7
8
|
export declare const APPROVAL_RESOLUTION_LANES: readonly ["respond", "decide", "ask"];
|
|
8
9
|
export type ApprovalResolutionLane = (typeof APPROVAL_RESOLUTION_LANES)[number];
|
|
9
|
-
export declare const APPROVAL_NOT_SENT_CAUSES: readonly ["retracted", "edit_refused", "no_pending", "wrong_gate", "fetch_failed", "no_input", "card_unavailable", "safety_stop"];
|
|
10
|
+
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"];
|
|
10
11
|
export type ApprovalNotSentCause = (typeof APPROVAL_NOT_SENT_CAUSES)[number];
|
|
11
12
|
export declare const APPROVAL_UNSETTLED_CAUSES: readonly ["engine_refused", "engine_error", "no_answer", "transport_exhausted", "parking_in_progress", "interrupted", "orchestration", "unreadable"];
|
|
12
13
|
export type ApprovalUnsettledCause = (typeof APPROVAL_UNSETTLED_CAUSES)[number];
|
|
@@ -32,6 +33,9 @@ export interface ApprovalResolutionNotSent extends ApprovalResolutionBase {
|
|
|
32
33
|
readonly kind: 'not_sent';
|
|
33
34
|
readonly cause: ApprovalNotSentCause;
|
|
34
35
|
readonly safetyCode?: Exclude<HitlSafetyCode, 'binding_mismatch' | 'no_pending' | 'wrong_gate'>;
|
|
36
|
+
readonly rowVerdict?: Exclude<CheckpointRowVerdictReading, {
|
|
37
|
+
readonly kind: 'ok';
|
|
38
|
+
}>;
|
|
35
39
|
readonly detail?: string;
|
|
36
40
|
}
|
|
37
41
|
export interface ApprovalResolutionUnsettled extends ApprovalResolutionBase {
|
|
@@ -4,6 +4,8 @@ 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
9
|
export const APPROVAL_RESOLUTION_LANES = Object.freeze(['respond', 'decide', 'ask']);
|
|
8
10
|
export const APPROVAL_NOT_SENT_CAUSES = Object.freeze([
|
|
9
11
|
'retracted',
|
|
@@ -14,6 +16,7 @@ export const APPROVAL_NOT_SENT_CAUSES = Object.freeze([
|
|
|
14
16
|
'no_input',
|
|
15
17
|
'card_unavailable',
|
|
16
18
|
'safety_stop',
|
|
19
|
+
'row_unresumable',
|
|
17
20
|
]);
|
|
18
21
|
export const APPROVAL_UNSETTLED_CAUSES = Object.freeze([
|
|
19
22
|
'engine_refused',
|
|
@@ -49,6 +52,7 @@ const NOT_SENT_SENTENCES = Object.freeze({
|
|
|
49
52
|
no_input: 'the approval has no tool input or question to show, so no card was shown; nothing was sent',
|
|
50
53
|
card_unavailable: 'no approval card could be shown on this host; nothing was sent',
|
|
51
54
|
safety_stop: 'the decision was stopped by a local safety check before it was sent; nothing was sent',
|
|
55
|
+
row_unresumable: CHECKPOINT_ROW_BAR_SENTENCE,
|
|
52
56
|
});
|
|
53
57
|
function nonEmpty(v) {
|
|
54
58
|
return typeof v === 'string' && v.length > 0 ? v : undefined;
|
|
@@ -77,8 +81,21 @@ export function approvalResolutionDetail(r) {
|
|
|
77
81
|
if (cause === undefined || !Object.hasOwn(NOT_SENT_SENTENCES, cause))
|
|
78
82
|
return undefined;
|
|
79
83
|
const sentence = NOT_SENT_SENTENCES[cause];
|
|
84
|
+
if (cause === 'row_unresumable') {
|
|
85
|
+
let verdict;
|
|
86
|
+
try {
|
|
87
|
+
const d = Object.getOwnPropertyDescriptor(r, 'rowVerdict');
|
|
88
|
+
verdict = d !== undefined && Object.hasOwn(d, 'value') ? d.value : undefined;
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
verdict = undefined;
|
|
92
|
+
}
|
|
93
|
+
return ownStr(verdict, 'kind') !== 'unreadable' ? (ownStr(verdict, 'sentence') ?? sentence) : sentence;
|
|
94
|
+
}
|
|
80
95
|
const code = cause === 'safety_stop' ? ownStr(r, 'safetyCode') : undefined;
|
|
81
|
-
|
|
96
|
+
if (code === undefined)
|
|
97
|
+
return sentence;
|
|
98
|
+
return code === 'binding_missing' ? `${sentence} (${code}) · ${renderMessage(msg('approval.decide.unboundWayOut'))}` : `${sentence} (${code})`;
|
|
82
99
|
}
|
|
83
100
|
if (kind !== 'unsettled')
|
|
84
101
|
return undefined;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import type { PendingCheckpoint } from '@sema-agent/sdk';
|
|
2
2
|
import { type LivePendingAskView } from './livePendingAsk.js';
|
|
3
|
+
import { type ApprovalQueuePeerInboundRow } from './approvalQueueRow.js';
|
|
4
|
+
import type { ApprovalsListEnvelope } from './crashConverged.js';
|
|
5
|
+
export type { ApprovalQueuePeerInboundRow } from './approvalQueueRow.js';
|
|
3
6
|
export interface ApprovalsFeedClientLike {
|
|
4
7
|
approvals: {
|
|
5
8
|
list(opts?: {
|
|
6
9
|
signal?: AbortSignal;
|
|
7
|
-
}): Promise<
|
|
8
|
-
pending: PendingCheckpoint[];
|
|
9
|
-
livePending?: unknown[];
|
|
10
|
-
}>;
|
|
10
|
+
}): Promise<ApprovalsListEnvelope>;
|
|
11
11
|
stream?(opts?: {
|
|
12
12
|
signal?: AbortSignal;
|
|
13
13
|
}): AsyncGenerator<{
|
|
@@ -20,6 +20,7 @@ export type ApprovalsFeedMode = 'push' | 'poll' | 'idle';
|
|
|
20
20
|
export interface ApprovalsFeedSnapshot {
|
|
21
21
|
kind: 'snapshot';
|
|
22
22
|
pending: PendingCheckpoint[];
|
|
23
|
+
peerInbound?: ApprovalQueuePeerInboundRow[];
|
|
23
24
|
livePending?: LivePendingAskView[];
|
|
24
25
|
livePendingDropped?: number;
|
|
25
26
|
pendingDropped?: number;
|
|
@@ -2,17 +2,41 @@ import { hostLog } from '../host.js';
|
|
|
2
2
|
import { unrefTimer } from '../unrefTimer.js';
|
|
3
3
|
import { readLivePendingRows } from './livePendingAsk.js';
|
|
4
4
|
import { createStreamDrainingLegs } from '../streamDrainingLegs.js';
|
|
5
|
+
import { approvalQueueRowFamilyOf, peerInboundQueueRowOf } from './approvalQueueRow.js';
|
|
6
|
+
import { parkRowDelegationLinksOf } from './parkRowDelegation.js';
|
|
7
|
+
import { checkpointRowVerdictOf } from '../checkpointRowVerdict.js';
|
|
8
|
+
const _realClientFitsFeedSlice = true;
|
|
9
|
+
void _realClientFitsFeedSlice;
|
|
5
10
|
const MAX_CONSECUTIVE_POLL_ESCAPES = 5;
|
|
6
11
|
function readDurablePendingRows(raw) {
|
|
7
12
|
if (!Array.isArray(raw))
|
|
8
13
|
return { kind: 'malformed' };
|
|
9
14
|
const rows = [];
|
|
15
|
+
const peer = [];
|
|
10
16
|
let dropped = 0;
|
|
17
|
+
let skipped = 0;
|
|
11
18
|
for (const item of raw) {
|
|
12
19
|
if (item === null || typeof item !== 'object' || Array.isArray(item)) {
|
|
13
20
|
dropped++;
|
|
14
21
|
continue;
|
|
15
22
|
}
|
|
23
|
+
const family = approvalQueueRowFamilyOf(item);
|
|
24
|
+
if (family === 'unknown') {
|
|
25
|
+
skipped++;
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
if (family === 'peer_inbound') {
|
|
29
|
+
const view = peerInboundQueueRowOf(item);
|
|
30
|
+
if (view === undefined)
|
|
31
|
+
dropped++;
|
|
32
|
+
else
|
|
33
|
+
peer.push(view);
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (family === 'unreadable') {
|
|
37
|
+
dropped++;
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
16
40
|
const sid = item.sessionId;
|
|
17
41
|
if (typeof sid !== 'string' || sid === '') {
|
|
18
42
|
dropped++;
|
|
@@ -20,13 +44,13 @@ function readDurablePendingRows(raw) {
|
|
|
20
44
|
}
|
|
21
45
|
rows.push(item);
|
|
22
46
|
}
|
|
23
|
-
if (raw.length > 0 && rows.length === 0)
|
|
47
|
+
if (raw.length > 0 && rows.length + peer.length + skipped === 0)
|
|
24
48
|
return { kind: 'malformed' };
|
|
25
|
-
return { kind: 'present', rows, dropped };
|
|
49
|
+
return { kind: 'present', rows, peer, dropped };
|
|
26
50
|
}
|
|
27
51
|
function durableDigestOf(rows) {
|
|
28
52
|
return rows
|
|
29
|
-
.map(r => [r.sessionId ?? '', r.taskId ?? '', r.toolCallId ?? '', r.boundCallId ?? '', r.boundInputHash ?? '', r.toolName ?? '']
|
|
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)]
|
|
30
54
|
.join(''))
|
|
31
55
|
.sort()
|
|
32
56
|
.join('');
|
|
@@ -34,14 +58,20 @@ function durableDigestOf(rows) {
|
|
|
34
58
|
const LIVE_FIELD_SEP = String.fromCharCode(1);
|
|
35
59
|
const LIVE_ROW_SEP = String.fromCharCode(2);
|
|
36
60
|
const LIVE_SECTION_SEP = String.fromCharCode(3);
|
|
37
|
-
function
|
|
61
|
+
function peerDigestOf(peer) {
|
|
62
|
+
return peer
|
|
63
|
+
.map(r => JSON.stringify(r))
|
|
64
|
+
.sort()
|
|
65
|
+
.join(LIVE_ROW_SEP);
|
|
66
|
+
}
|
|
67
|
+
function digestOf(rows, live, dropped = 0, droppedDurable = 0, peer = []) {
|
|
38
68
|
const liveDigest = live === undefined
|
|
39
69
|
? 'absent'
|
|
40
70
|
: live
|
|
41
71
|
.map(r => [r.approvalId, r.toolName, String(r.expiresAtMs), r.sessionId ?? '', r.originTaskId ?? '', r.frame !== undefined ? 'f' : ''].join(LIVE_FIELD_SEP))
|
|
42
72
|
.sort()
|
|
43
73
|
.join(LIVE_ROW_SEP);
|
|
44
|
-
return `${durableDigestOf(rows)}${LIVE_SECTION_SEP}${liveDigest}${LIVE_SECTION_SEP}${dropped}${LIVE_SECTION_SEP}${droppedDurable}`;
|
|
74
|
+
return `${durableDigestOf(rows)}${LIVE_SECTION_SEP}${liveDigest}${LIVE_SECTION_SEP}${dropped}${LIVE_SECTION_SEP}${droppedDurable}${LIVE_SECTION_SEP}${peerDigestOf(peer)}`;
|
|
45
75
|
}
|
|
46
76
|
export function startApprovalsFeed(client, onSnapshot, opts) {
|
|
47
77
|
const pollIntervalMs = opts?.pollIntervalMs ?? 5000;
|
|
@@ -158,6 +188,7 @@ export function startApprovalsFeed(client, onSnapshot, opts) {
|
|
|
158
188
|
return;
|
|
159
189
|
const seq = ++takeSeq;
|
|
160
190
|
let rows;
|
|
191
|
+
let peer;
|
|
161
192
|
let live;
|
|
162
193
|
let dropped = 0;
|
|
163
194
|
let droppedDurable = 0;
|
|
@@ -212,6 +243,7 @@ export function startApprovalsFeed(client, onSnapshot, opts) {
|
|
|
212
243
|
throw new TypeError('approvalsFeed: unreadable pending section');
|
|
213
244
|
}
|
|
214
245
|
rows = durableRead.rows;
|
|
246
|
+
peer = durableRead.peer;
|
|
215
247
|
droppedDurable = durableRead.dropped;
|
|
216
248
|
if (durableRead.dropped > 0)
|
|
217
249
|
hostLog('debug', `approvalsFeed: dropped ${durableRead.dropped} malformed pending row(s) — snapshot carries pendingDropped`);
|
|
@@ -220,7 +252,7 @@ export function startApprovalsFeed(client, onSnapshot, opts) {
|
|
|
220
252
|
return;
|
|
221
253
|
let d;
|
|
222
254
|
try {
|
|
223
|
-
d = digestOf(rows, live, dropped, droppedDurable);
|
|
255
|
+
d = digestOf(rows, live, dropped, droppedDurable, peer);
|
|
224
256
|
}
|
|
225
257
|
catch (e) {
|
|
226
258
|
noteTakeMissed(via, seq);
|
|
@@ -252,6 +284,7 @@ export function startApprovalsFeed(client, onSnapshot, opts) {
|
|
|
252
284
|
const snap = {
|
|
253
285
|
kind: 'snapshot',
|
|
254
286
|
pending: rows,
|
|
287
|
+
...(peer.length > 0 ? { peerInbound: peer } : {}),
|
|
255
288
|
...(live !== undefined ? { livePending: live } : {}),
|
|
256
289
|
...(dropped > 0 ? { livePendingDropped: dropped } : {}),
|
|
257
290
|
...(droppedDurable > 0 ? { pendingDropped: droppedDurable } : {}),
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { PendingCheckpoint } from '@sema-agent/sdk';
|
|
2
|
+
import type { ApprovalQueueRow } from './crashConverged.js';
|
|
2
3
|
import type { ParkRowProbe } from './parkRowBirthWait.js';
|
|
3
4
|
import { type ParkOwnershipDeps } from './parkOwnership.js';
|
|
4
5
|
export declare const ASK_PARK_ROW_WAIT_MS = 15000;
|
|
@@ -7,7 +8,7 @@ export interface AskParkRowScanDeps {
|
|
|
7
8
|
isOwned?: (row: PendingCheckpoint) => boolean;
|
|
8
9
|
ownership?: ParkOwnershipDeps;
|
|
9
10
|
}
|
|
10
|
-
export declare function classifyAskParkRows(
|
|
11
|
+
export declare function classifyAskParkRows(queueRows: readonly ApprovalQueueRow[], taskId: string, deps?: AskParkRowScanDeps): ParkRowProbe<PendingCheckpoint>;
|
|
11
12
|
export interface AskParkRowIdentity {
|
|
12
13
|
rowTaskId: string;
|
|
13
14
|
gatedCallId: string | undefined;
|
|
@@ -15,7 +16,7 @@ export interface AskParkRowIdentity {
|
|
|
15
16
|
}
|
|
16
17
|
export declare function askParkRowIdentity(taskId: string, row: PendingCheckpoint): AskParkRowIdentity;
|
|
17
18
|
export declare function askParkRowArm(row: PendingCheckpoint): 'question' | 'tool-gate';
|
|
18
|
-
export declare function askParkRowStillPending(rows: readonly
|
|
19
|
+
export declare function askParkRowStillPending(rows: readonly ApprovalQueueRow[], identity: AskParkRowIdentity): boolean;
|
|
19
20
|
export type AskParkChainFailureDisposition = 'retry' | 'row-gone-after-card' | 'row-unborn';
|
|
20
21
|
export declare function classifyAskParkChainFailure(i: {
|
|
21
22
|
rowStillPending: boolean;
|
|
@@ -29,6 +30,6 @@ export interface RowArmSingleFlight<T> {
|
|
|
29
30
|
export declare function createRowArmSingleFlight<T>(): RowArmSingleFlight<T>;
|
|
30
31
|
export declare function pendingRowIsOwnedAndDecidable(row: PendingCheckpoint, deps?: ParkOwnershipDeps): boolean;
|
|
31
32
|
export interface OwnedPendingListView {
|
|
32
|
-
readonly pending?: readonly
|
|
33
|
+
readonly pending?: readonly ApprovalQueueRow[] | null;
|
|
33
34
|
}
|
|
34
35
|
export declare function countOwnedPendingRows(listed: OwnedPendingListView | null | undefined, deps?: ParkOwnershipDeps): number;
|
|
@@ -2,10 +2,19 @@ import { askParkForeignGateKind, durableDecideLegOf } from '../adapter/activeRun
|
|
|
2
2
|
import { isAskTool, questionCardVerdict } from './frameRouter.js';
|
|
3
3
|
import { approvalCallKey } from './gateIdentity.js';
|
|
4
4
|
import { askQuestionsFromPending, pendingRowIsOwnedByThisSession } from './parkOwnership.js';
|
|
5
|
+
import { approvalQueueRowFamilyOf, checkpointQueueRowSortOf, QUEUE_ROW_FAMILY_UNREADABLE_GATE } from './approvalQueueRow.js';
|
|
6
|
+
import { checkpointRowBarOf, checkpointRowBarSentence } from '../checkpointRowVerdict.js';
|
|
7
|
+
import { msg, renderMessage } from '../i18n/translate.js';
|
|
5
8
|
export const ASK_PARK_ROW_WAIT_MS = 15000;
|
|
6
9
|
export const ASK_PARK_ROW_POLL_MS = 500;
|
|
7
|
-
export function classifyAskParkRows(
|
|
10
|
+
export function classifyAskParkRows(queueRows, taskId, deps) {
|
|
8
11
|
const isOwned = deps?.isOwned ?? ((row) => pendingRowIsOwnedByThisSession(row, deps?.ownership));
|
|
12
|
+
const sorted = queueRows.flatMap((r) => {
|
|
13
|
+
const sort = checkpointQueueRowSortOf(r);
|
|
14
|
+
return sort === 'excluded' ? [] : [{ r: r, unreadable: sort === 'unreadable' }];
|
|
15
|
+
});
|
|
16
|
+
const rows = sorted.map((x) => x.r);
|
|
17
|
+
const familyUnreadable = new Set(sorted.filter((x) => x.unreadable).map((x) => x.r));
|
|
9
18
|
const own = rows.find(r => r.taskId === taskId);
|
|
10
19
|
const sole = rows.length === 1 ? rows[0] : undefined;
|
|
11
20
|
const soleUnowned = sole !== undefined && !isOwned(sole);
|
|
@@ -21,7 +30,15 @@ export function classifyAskParkRows(rows, taskId, deps) {
|
|
|
21
30
|
: `${String(rows.length)} pending rows but none for task ${taskId} — ambiguous queue, refusing to surface an unrelated row`,
|
|
22
31
|
};
|
|
23
32
|
}
|
|
24
|
-
const foreignKind = askParkForeignGateKind(pending);
|
|
33
|
+
const foreignKind = familyUnreadable.has(pending) ? QUEUE_ROW_FAMILY_UNREADABLE_GATE : askParkForeignGateKind(pending);
|
|
34
|
+
const bar = foreignKind === null || foreignKind === QUEUE_ROW_FAMILY_UNREADABLE_GATE ? checkpointRowBarOf(pending) : undefined;
|
|
35
|
+
if (bar !== undefined) {
|
|
36
|
+
return {
|
|
37
|
+
kind: 'settled',
|
|
38
|
+
reason: renderMessage(msg('approval.rowUnresumable.askNotSurfaced', { taskId: String(pending.taskId), sentence: checkpointRowBarSentence(bar) })),
|
|
39
|
+
rowVerdict: bar,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
25
42
|
if (foreignKind !== null) {
|
|
26
43
|
return {
|
|
27
44
|
kind: 'unborn',
|
|
@@ -120,7 +137,9 @@ export function pendingRowIsOwnedAndDecidable(row, deps) {
|
|
|
120
137
|
const leg = durableDecideLegOf(row);
|
|
121
138
|
if (leg === 'plan_review')
|
|
122
139
|
return true;
|
|
123
|
-
if (leg !== 'approval'
|
|
140
|
+
if (leg !== 'approval')
|
|
141
|
+
return false;
|
|
142
|
+
if (checkpointRowBarOf(row) !== undefined)
|
|
124
143
|
return false;
|
|
125
144
|
return askParkRowArm(row) === 'question' ? askQuestionsFromPending(row) !== null : true;
|
|
126
145
|
}
|
|
@@ -137,6 +156,11 @@ export function countOwnedPendingRows(listed, deps) {
|
|
|
137
156
|
if (typeof row !== 'object' || row === null) {
|
|
138
157
|
throw new Error('approvals.list answered with a pending row that is not an object — the owned pending count is unknown');
|
|
139
158
|
}
|
|
159
|
+
const family = approvalQueueRowFamilyOf(row);
|
|
160
|
+
if (family === 'unreadable')
|
|
161
|
+
throw new Error('approvals.list answered with a pending row whose family (`kind`) cannot be read — the owned pending count is unknown');
|
|
162
|
+
if (family !== 'checkpoint')
|
|
163
|
+
continue;
|
|
140
164
|
if (pendingRowIsOwnedAndDecidable(row, deps))
|
|
141
165
|
n++;
|
|
142
166
|
}
|
|
@@ -125,6 +125,17 @@ function evidenceUnreadable(card) {
|
|
|
125
125
|
const nested = evidenceSlotOf(risk.value, 'requiresRealApproval');
|
|
126
126
|
return nested.kind !== 'data' || typeof nested.value !== 'boolean';
|
|
127
127
|
}
|
|
128
|
+
function registryUnreadable(card) {
|
|
129
|
+
const slot = evidenceSlotOf(card, 'unreadableEvidence');
|
|
130
|
+
if (slot.kind === 'absent' || (slot.kind === 'data' && slot.value === undefined))
|
|
131
|
+
return false;
|
|
132
|
+
if (slot.kind === 'unreadable')
|
|
133
|
+
return true;
|
|
134
|
+
const list = slot.value;
|
|
135
|
+
if (!Array.isArray(list) || list.some((k) => typeof k !== 'string'))
|
|
136
|
+
return true;
|
|
137
|
+
return list.some((k) => k !== 'rememberRefused' && k !== 'ruleOffers');
|
|
138
|
+
}
|
|
128
139
|
function readHostAskRuleMatched(facts) {
|
|
129
140
|
if (typeof facts !== 'object' || facts === null)
|
|
130
141
|
return undefined;
|
|
@@ -137,17 +148,9 @@ export function automaticAnswerVerdict(card, lane, facts) {
|
|
|
137
148
|
try {
|
|
138
149
|
if (typeof card !== 'object' || card === null)
|
|
139
150
|
return UNKNOWN.card_unreadable;
|
|
151
|
+
const unreadableAtEntry = registryUnreadable(card) || evidenceUnreadable(card) || (retiredAllowRuleShadowKeyPresent(card, 'frame') && !approvalAllowRuleShadowed(card));
|
|
140
152
|
if (card.cardPayloadUnreadable === true)
|
|
141
153
|
return UNKNOWN.card_unreadable;
|
|
142
|
-
const unreadable = card.unreadableEvidence;
|
|
143
|
-
if (unreadable !== undefined) {
|
|
144
|
-
if (!Array.isArray(unreadable) || unreadable.some((k) => typeof k !== 'string'))
|
|
145
|
-
return UNKNOWN.card_unreadable;
|
|
146
|
-
if (unreadable.some((k) => k !== 'rememberRefused' && k !== 'ruleOffers'))
|
|
147
|
-
return UNKNOWN.card_unreadable;
|
|
148
|
-
}
|
|
149
|
-
if (!approvalAllowRuleShadowed(card) && retiredAllowRuleShadowKeyPresent(card, 'frame'))
|
|
150
|
-
return UNKNOWN.card_unreadable;
|
|
151
154
|
const face = lane === 'mode_posture' ? askFaceOfCard(card) : undefined;
|
|
152
155
|
const origin = readAskOrigin(evidenceView(card, 'origin'));
|
|
153
156
|
if (origin !== undefined && Object.hasOwn(ORIGIN_IMPLIES_CLASS, origin)) {
|
|
@@ -175,7 +178,7 @@ export function automaticAnswerVerdict(card, lane, facts) {
|
|
|
175
178
|
return mustAsk('allow_rule_shadow');
|
|
176
179
|
}
|
|
177
180
|
}
|
|
178
|
-
if (
|
|
181
|
+
if (unreadableAtEntry)
|
|
179
182
|
return UNKNOWN.card_unreadable;
|
|
180
183
|
const pair = readAskClassPairState(card);
|
|
181
184
|
if (pair.state === 'malformed')
|
|
@@ -4,8 +4,12 @@ export interface CrashConvergedRowReading extends Readonly<CrashConvergedRow> {
|
|
|
4
4
|
readonly needsHumanReason?: 'approved_then_interrupted' | 'pending_unsafe' | 'unstable_row' | 'contradictory';
|
|
5
5
|
}
|
|
6
6
|
export declare const isCrashConvergedCause: (v: unknown) => v is CrashConvergedRowReading["cause"];
|
|
7
|
+
export interface ApprovalQueueKindedRow {
|
|
8
|
+
readonly kind: string;
|
|
9
|
+
}
|
|
10
|
+
export type ApprovalQueueRow = PendingCheckpoint | ApprovalQueueKindedRow;
|
|
7
11
|
export interface ApprovalsListEnvelope {
|
|
8
|
-
pending:
|
|
12
|
+
pending: ApprovalQueueRow[];
|
|
9
13
|
livePending?: unknown[];
|
|
10
14
|
crashConverged?: CrashConvergedRowReading[];
|
|
11
15
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { APPROVAL_BINDING_MISMATCH, 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
|
+
import { SDK_DECIDE_BINDING_KEYS } from '../generated/sdkFactTables.js';
|
|
4
5
|
import { isSlotCarrier, PROTOCOL_ERROR_NAME, protocolErrorNameReading, readRefusalSlots, readThrownExtraSnapshot } from '../wireFailureShape.js';
|
|
5
|
-
const BINDING_SEAT_FIELDS = new Set(
|
|
6
|
+
const BINDING_SEAT_FIELDS = new Set(SDK_DECIDE_BINDING_KEYS);
|
|
6
7
|
const ANSWER_FIELD = 'answer';
|
|
7
8
|
const REFUSAL_WORD_KEYS = Object.freeze(['field', 'reason']);
|
|
8
9
|
const GRANT_DIGEST_FIELD = 'boundGrantDigest';
|
|
@@ -146,7 +146,7 @@ export function readDecisionRefusalAsk(failure, answer, read) {
|
|
|
146
146
|
if (name === 'HitlSafetyError')
|
|
147
147
|
return facts('not_settled');
|
|
148
148
|
const code = typeof errorCode === 'string' && errorCode.length > 0 ? errorCode : undefined;
|
|
149
|
-
if (code === RESUME_PREFLIGHT_REJECTED &&
|
|
149
|
+
if (code === RESUME_PREFLIGHT_REJECTED && preflightSettledBitsPresent(carrier))
|
|
150
150
|
return facts('not_settled', true);
|
|
151
151
|
if (isCodeClassifiedGateFailure(code, retriable))
|
|
152
152
|
return facts('not_settled');
|
|
@@ -20,6 +20,7 @@ export interface HitlApprovalDecisionRequest {
|
|
|
20
20
|
readonly taskId?: string;
|
|
21
21
|
readonly toolCallId?: string;
|
|
22
22
|
readonly answer: ApprovalCardDecision;
|
|
23
|
+
readonly card?: object;
|
|
23
24
|
}
|
|
24
25
|
export interface HitlAskDecisionRequest {
|
|
25
26
|
readonly family: 'ask';
|
|
@@ -28,6 +29,7 @@ export interface HitlAskDecisionRequest {
|
|
|
28
29
|
readonly approvalId?: string;
|
|
29
30
|
readonly toolCallId?: string;
|
|
30
31
|
readonly answer: ApprovalCardDecision;
|
|
32
|
+
readonly card?: object;
|
|
31
33
|
}
|
|
32
34
|
export interface HitlElicitationDecisionRequest {
|
|
33
35
|
readonly family: 'elicitation';
|
|
@@ -63,6 +65,7 @@ interface HitlDecisionOutcomeBase {
|
|
|
63
65
|
readonly fallback?: 'approval';
|
|
64
66
|
readonly noteDropped?: true;
|
|
65
67
|
readonly rememberDropped?: true;
|
|
68
|
+
readonly allowSessionCarried?: true;
|
|
66
69
|
readonly attributionDropped?: true;
|
|
67
70
|
readonly attributionRenamed?: true;
|
|
68
71
|
readonly pending?: LiveAskPendingReading;
|