@sema-agent/client-core 0.106.0 → 0.108.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.
Files changed (114) hide show
  1. package/CHANGELOG.md +199 -0
  2. package/README.md +35 -26
  3. package/dist/adapter/activeRunSelfHeal.d.ts +10 -0
  4. package/dist/adapter/activeRunSelfHeal.js +68 -23
  5. package/dist/checkpointRowVerdict.d.ts +11 -0
  6. package/dist/checkpointRowVerdict.js +35 -0
  7. package/dist/cloudConfigWireCaps.d.ts +10 -0
  8. package/dist/cloudConfigWireCaps.js +33 -0
  9. package/dist/coreValuePorts.d.ts +17 -1
  10. package/dist/coreValuePorts.js +5 -0
  11. package/dist/decideReceipt.js +2 -1
  12. package/dist/displayUntrusted.d.ts +5 -3
  13. package/dist/displayUntrusted.js +50 -41
  14. package/dist/engineErrorCodes.d.ts +5 -0
  15. package/dist/engineErrorCodes.js +5 -0
  16. package/dist/engineNoticeCodes.d.ts +31 -1
  17. package/dist/engineNoticeCodes.js +182 -9
  18. package/dist/engineTargetSeat.js +1 -0
  19. package/dist/errorSupplementRoles.js +4 -1
  20. package/dist/eventLeg.js +1 -1
  21. package/dist/executionLaneCapability.js +3 -2
  22. package/dist/executionLaneWords.d.ts +1 -0
  23. package/dist/executionLaneWords.js +4 -0
  24. package/dist/gateOutcome.d.ts +10 -1
  25. package/dist/gateOutcome.js +48 -1
  26. package/dist/generated/engineFactTables.d.ts +1 -0
  27. package/dist/generated/engineFactTables.js +5 -0
  28. package/dist/generated/engineNoticeTables.js +12 -3
  29. package/dist/generated/settingsSchemaFns.d.ts +4 -2
  30. package/dist/generated/settingsSchemaFns.js +9 -3
  31. package/dist/generated/settingsSchemaMcpRequestEntry.d.ts +1 -1
  32. package/dist/generated/settingsSchemaMcpRequestEntry.js +9 -18
  33. package/dist/generated/settingsSchemaReservedMemberName.d.ts +1 -0
  34. package/dist/generated/settingsSchemaReservedMemberName.js +7 -0
  35. package/dist/generated/settingsSchemaTables.d.ts +2 -0
  36. package/dist/generated/settingsSchemaTables.js +10 -0
  37. package/dist/generated/settingsSchemaWireName.d.ts +1 -0
  38. package/dist/generated/settingsSchemaWireName.js +8 -0
  39. package/dist/headlessReconnectWire.js +12 -7
  40. package/dist/hitl/approvalAskers.d.ts +13 -0
  41. package/dist/hitl/approvalAskers.js +79 -0
  42. package/dist/hitl/approvalResolution.d.ts +8 -1
  43. package/dist/hitl/approvalResolution.js +37 -2
  44. package/dist/hitl/approvalsFeed.js +5 -13
  45. package/dist/hitl/askParkRowRouting.js +17 -1
  46. package/dist/hitl/decisionRefusal.d.ts +1 -0
  47. package/dist/hitl/decisionRefusal.js +5 -2
  48. package/dist/hitl/decisionSend.d.ts +2 -0
  49. package/dist/hitl/decisionSend.js +22 -12
  50. package/dist/hitl/frameRouter.d.ts +3 -2
  51. package/dist/hitl/frameRouter.js +28 -6
  52. package/dist/hitl/gateLedger.d.ts +2 -0
  53. package/dist/hitl/gateLedger.js +3 -1
  54. package/dist/hitl/hitlBridge.d.ts +5 -1
  55. package/dist/hitl/hitlBridge.js +26 -2
  56. package/dist/hitl/livePendingAsk.js +4 -2
  57. package/dist/hitl/parkOwnership.js +4 -5
  58. package/dist/hitl/parkResolver.js +34 -21
  59. package/dist/hitl/parkRowBirthWait.d.ts +9 -0
  60. package/dist/hitl/parkRowBirthWait.js +8 -1
  61. package/dist/hitl/parkRowDelegation.d.ts +6 -0
  62. package/dist/hitl/parkRowDelegation.js +33 -0
  63. package/dist/hitl/persistedRulesWire.d.ts +19 -3
  64. package/dist/hitl/persistedRulesWire.js +118 -20
  65. package/dist/hitl/planReviewWire.js +16 -18
  66. package/dist/hitl/policyDenyCause.d.ts +3 -0
  67. package/dist/hitl/policyDenyCause.js +16 -0
  68. package/dist/hitl/sessionAllowRoute.d.ts +5 -0
  69. package/dist/hitl/sessionAllowRoute.js +42 -0
  70. package/dist/hitl/sessionPolicyDeliverable.js +1 -1
  71. package/dist/hitl/standingRows.js +10 -10
  72. package/dist/hitl/toolApprovalWire.d.ts +8 -2
  73. package/dist/hitl/toolApprovalWire.js +44 -11
  74. package/dist/hooksReaderGenerations.d.ts +1 -0
  75. package/dist/hooksReaderGenerations.js +12 -0
  76. package/dist/hooksWireCaps.js +8 -4
  77. package/dist/i18n/messages.en.d.ts +43 -0
  78. package/dist/i18n/messages.en.js +47 -4
  79. package/dist/i18n/messages.zh.js +53 -4
  80. package/dist/index.d.ts +7 -1
  81. package/dist/index.js +5 -1
  82. package/dist/injectionLaneNotice.js +2 -1
  83. package/dist/liveModelCatalog.d.ts +4 -2
  84. package/dist/liveModelCatalog.js +164 -26
  85. package/dist/model/catalogDefault.d.ts +25 -0
  86. package/dist/model/catalogDefault.js +44 -0
  87. package/dist/noticePresentation.js +2 -0
  88. package/dist/permissionWireCaps.d.ts +1 -0
  89. package/dist/permissionWireCaps.js +11 -0
  90. package/dist/pluginHooksWire.d.ts +5 -3
  91. package/dist/pluginHooksWire.js +116 -7
  92. package/dist/queuedDelivery.d.ts +1 -0
  93. package/dist/queuedDelivery.js +12 -0
  94. package/dist/resultFrameKeys.js +4 -2
  95. package/dist/resumeRefusalCopy.js +15 -8
  96. package/dist/runPermissionModeSwitch.d.ts +2 -1
  97. package/dist/runPermissionModeSwitch.js +16 -6
  98. package/dist/sdkWireTransit.d.ts +1 -1
  99. package/dist/seatContract.d.ts +64 -10
  100. package/dist/seatContract.js +167 -12
  101. package/dist/sessionEngine.d.ts +2 -1
  102. package/dist/sessionEngine.js +5 -0
  103. package/dist/settingsHooksSalvage.d.ts +5 -0
  104. package/dist/settingsHooksSalvage.js +54 -0
  105. package/dist/subagentContentStore.js +1 -1
  106. package/dist/supportFloor.js +2 -0
  107. package/dist/taskNotificationAdmission.d.ts +19 -0
  108. package/dist/taskNotificationAdmission.js +84 -0
  109. package/dist/toolResult.js +2 -1
  110. package/dist/webSearchWireCaps.js +9 -4
  111. package/dist/wireRefusalCopy.d.ts +7 -1
  112. package/dist/wireRefusalCopy.js +7 -1
  113. package/docs/INTEGRATION-CLIENTS.md +1189 -18
  114. package/package.json +5 -5
@@ -1 +1 @@
1
- export declare const SETTINGS_MCP_REQUEST_ENTRY_CLOSURE: (MCP_CONTENT_ORIGINS: readonly ["local", "execution", "external"], startsWithHttpScheme: (raw: string) => boolean, echoCallerText: (text: string) => string, UNINSPECTABLE: "an object that could not be inspected (a proxy trap threw)", captureStringArray: (v: unknown, classification: "strict" | "wide") => string[] | undefined, dataDescriptor: (value: unknown) => PropertyDescriptor, inspect: (read: () => unknown) => object, ownFieldsOf: (record: object, keys: readonly string[]) => object, ownValueOf: (record: object, key: string) => object, readKey: (record: object, key: PropertyKey) => object, isJsonArray: (v: unknown) => v is unknown[], jsonShapeOf: (v: unknown) => "plain" | "non_plain_object" | "array" | "null" | "primitive" | "uninspectable", isReservedMcpServerName: (name: string) => boolean, RESERVED_MCP_SERVER_NAME_REASON: "the \"remote-\" prefix is reserved for the remote MCP servers a device executor offers") => any;
1
+ export declare const SETTINGS_MCP_REQUEST_ENTRY_CLOSURE: (MCP_CONTENT_ORIGINS: readonly ["local", "execution", "external"], startsWithHttpScheme: (raw: string) => boolean, echoCallerText: (text: string) => string, UNINSPECTABLE: "an object that could not be inspected (a proxy trap threw)", captureStringArray: (v: unknown, classification: "strict" | "wide") => string[] | undefined, dataDescriptor: (value: unknown) => PropertyDescriptor, inspect: (read: () => unknown) => object, ownFieldsOf: (record: object, keys: readonly string[]) => object, ownValueOf: (record: object, key: string) => object, readKey: (record: object, key: PropertyKey) => object, isJsonArray: (v: unknown) => v is unknown[], jsonShapeOf: (v: unknown) => "plain" | "non_plain_object" | "array" | "null" | "primitive" | "uninspectable", isReservedMcpServerName: (name: string) => boolean, RESERVED_MCP_SERVER_NAME_REASON: "the \"remote-\" prefix is reserved for the remote MCP servers a device executor offers", TOOL_WIRE_NAME_MAX_CHARS: 128, hasEdgeWhitespace: (v: string) => boolean, isUsableWireName: (v: unknown) => v is string, isReservedMemberName: (name: string) => boolean) => any;
@@ -1,4 +1,4 @@
1
- export const SETTINGS_MCP_REQUEST_ENTRY_CLOSURE = (MCP_CONTENT_ORIGINS, startsWithHttpScheme, echoCallerText, UNINSPECTABLE, captureStringArray, dataDescriptor, inspect, ownFieldsOf, ownValueOf, readKey, isJsonArray, jsonShapeOf, isReservedMcpServerName, RESERVED_MCP_SERVER_NAME_REASON) => {
1
+ export const SETTINGS_MCP_REQUEST_ENTRY_CLOSURE = (MCP_CONTENT_ORIGINS, startsWithHttpScheme, echoCallerText, UNINSPECTABLE, captureStringArray, dataDescriptor, inspect, ownFieldsOf, ownValueOf, readKey, isJsonArray, jsonShapeOf, isReservedMcpServerName, RESERVED_MCP_SERVER_NAME_REASON, TOOL_WIRE_NAME_MAX_CHARS, hasEdgeWhitespace, isUsableWireName, isReservedMemberName) => {
2
2
  function describeKindWord(v) {
3
3
  const shape = jsonShapeOf(v);
4
4
  switch (shape) {
@@ -46,11 +46,6 @@ export const SETTINGS_MCP_REQUEST_ENTRY_CLOSURE = (MCP_CONTENT_ORIGINS, startsWi
46
46
  function quotedCallerText(text) {
47
47
  return `"${echoCallerText(text)}"`;
48
48
  }
49
- const TOOL_WIRE_NAME_MAX_CHARS = 128;
50
- const hasEdgeWhitespace = (v) => v.trim() !== v;
51
- function isUsableWireName(v) {
52
- return typeof v === "string" && v.length > 0 && v.length <= TOOL_WIRE_NAME_MAX_CHARS && !hasEdgeWhitespace(v);
53
- }
54
49
  function describeBadWireName(v) {
55
50
  if (typeof v !== "string")
56
51
  return describeKindWord(v);
@@ -202,8 +197,7 @@ export const SETTINGS_MCP_REQUEST_ENTRY_CLOSURE = (MCP_CONTENT_ORIGINS, startsWi
202
197
  }
203
198
  return { ok: true, value: { kind: "other", value: kind.value } };
204
199
  }
205
- const PLAIN_STRING_RECORD_RESERVED_MEMBER = "__proto__";
206
- const RESERVED_MEMBER_FAULT = `no member of a declaration may be named "${PLAIN_STRING_RECORD_RESERVED_MEMBER}"`;
200
+ const reservedMemberFault = (name) => `no member of a declaration may be named "${name}"`;
207
201
  function notPlainDetail(shape, v) {
208
202
  switch (shape) {
209
203
  case "null":
@@ -233,28 +227,25 @@ export const SETTINGS_MCP_REQUEST_ENTRY_CLOSURE = (MCP_CONTENT_ORIGINS, startsWi
233
227
  return { ok: false, fault: "not_plain_record", detail: `got ${namesRead.sentence}` };
234
228
  const names = namesRead.value;
235
229
  const members = Object.create(null);
236
- let reservedMember = false;
230
+ const reservedMembers = names.filter(isReservedMemberName);
237
231
  for (const name of names) {
238
232
  const read = readKey(v, name);
239
233
  const unreadable = read.presence === "unreadable";
240
234
  const value = read.presence === "own" ? read.value : undefined;
241
235
  if (unreadable || typeof value !== "string") {
242
236
  const valueFault = unreadable ? "could not be read (its getter threw)" : `must be a string — got ${describeValueShape(value)}`;
243
- const reserved = name === PLAIN_STRING_RECORD_RESERVED_MEMBER;
244
- const fault = reserved ? "member_name_reserved" : "member_not_string";
237
+ const fault = isReservedMemberName(name) ? "member_name_reserved" : "member_not_string";
245
238
  return {
246
239
  ok: false,
247
240
  fault,
248
241
  member: echoCallerText(name),
249
- detail: `its member "${echoCallerText(name)}" ${reserved ? `is not allowed (${RESERVED_MEMBER_FAULT}) and its value ${valueFault}` : valueFault}`,
242
+ detail: `its member "${echoCallerText(name)}" ${isReservedMemberName(name) ? `is not allowed (${reservedMemberFault(name)}) and its value ${valueFault}` : valueFault}`,
250
243
  };
251
244
  }
252
- if (name === PLAIN_STRING_RECORD_RESERVED_MEMBER)
253
- reservedMember = true;
254
- else
245
+ if (!isReservedMemberName(name))
255
246
  Object.defineProperty(members, name, dataDescriptor(value));
256
247
  }
257
- return { ok: true, record: { ...members }, reservedMember };
248
+ return { ok: true, record: { ...members }, reservedMembers };
258
249
  }
259
250
  const issuesOf = (...candidates) => candidates.filter((c) => c !== undefined);
260
251
  function readTransportRecord(path, raw) {
@@ -269,8 +260,8 @@ export const SETTINGS_MCP_REQUEST_ENTRY_CLOSURE = (MCP_CONTENT_ORIGINS, startsWi
269
260
  }
270
261
  return {
271
262
  record: read.record,
272
- issues: read.reservedMember ? [{ path: `${path}.${PLAIN_STRING_RECORD_RESERVED_MEMBER}`, reason: RESERVED_MEMBER_FAULT, member: PLAIN_STRING_RECORD_RESERVED_MEMBER, fault: "member_name_reserved" }] : [],
263
+ issues: read.reservedMembers.map((name) => ({ path: `${path}.${name}`, reason: reservedMemberFault(name), member: name, fault: "member_name_reserved" })),
273
264
  };
274
265
  }
275
- return { readRequestMcpTransport, readMcpIdentityHeaders, isUsableWireName, describeBadWireName, isUsableMcpServerName, describeBadMcpServerName, isContentOriginWord, describeBadContentOrigin, TOOL_WIRE_NAME_MAX_CHARS };
266
+ return { readRequestMcpTransport, readMcpIdentityHeaders, describeBadWireName, isUsableMcpServerName, describeBadMcpServerName, isContentOriginWord, describeBadContentOrigin };
276
267
  };
@@ -0,0 +1 @@
1
+ export declare const SETTINGS_RESERVED_MEMBER_NAME_CLOSURE: () => any;
@@ -0,0 +1,7 @@
1
+ export const SETTINGS_RESERVED_MEMBER_NAME_CLOSURE = () => {
2
+ const RESERVED_MEMBER_NAMES = ["__proto__", "constructor", "prototype"];
3
+ function isReservedMemberName(name) {
4
+ return RESERVED_MEMBER_NAMES.includes(name);
5
+ }
6
+ return { isReservedMemberName };
7
+ };
@@ -13,3 +13,5 @@ export declare const SETTINGS_UI_LANGUAGE_VALUES: readonly ["en", "zh"];
13
13
  export declare const SETTINGS_MCP_CONTENT_ORIGINS: readonly ["local", "execution", "external"];
14
14
  export declare const SETTINGS_MIN_TRUST_WORDS: readonly ["local", "session", "project", "global", "managed", "task"];
15
15
  export declare const SETTINGS_WORKSPACE_TRUST_STATES: readonly ["accepted", "declined", "no_trust_step"];
16
+ export declare const SETTINGS_MODEL_PLANE_REFUSAL_CODES: readonly ["config.default_model_missing", "config.model_refused_name_minted", "config.model_route_endpoint_missing", "config.gateway_fallback_without_primary", "config.catalog_replaces_env_models"];
17
+ export declare const SETTINGS_NO_EXECUTION_TARGET_LANES: readonly ["none"];
@@ -63,3 +63,13 @@ export const SETTINGS_WORKSPACE_TRUST_STATES = Object.freeze([
63
63
  "declined",
64
64
  "no_trust_step",
65
65
  ]);
66
+ export const SETTINGS_MODEL_PLANE_REFUSAL_CODES = Object.freeze([
67
+ "config.default_model_missing",
68
+ "config.model_refused_name_minted",
69
+ "config.model_route_endpoint_missing",
70
+ "config.gateway_fallback_without_primary",
71
+ "config.catalog_replaces_env_models",
72
+ ]);
73
+ export const SETTINGS_NO_EXECUTION_TARGET_LANES = Object.freeze([
74
+ "none",
75
+ ]);
@@ -0,0 +1 @@
1
+ export declare const SETTINGS_WIRE_NAME_CLOSURE: () => any;
@@ -0,0 +1,8 @@
1
+ export const SETTINGS_WIRE_NAME_CLOSURE = () => {
2
+ const TOOL_WIRE_NAME_MAX_CHARS = 128;
3
+ const hasEdgeWhitespace = (v) => v.trim() !== v;
4
+ function isUsableWireName(v) {
5
+ return typeof v === "string" && v.length > 0 && v.length <= TOOL_WIRE_NAME_MAX_CHARS && !hasEdgeWhitespace(v);
6
+ }
7
+ return { isUsableWireName, TOOL_WIRE_NAME_MAX_CHARS, hasEdgeWhitespace };
8
+ };
@@ -53,7 +53,7 @@ export async function* withHeadlessR1Reconnect(live, deps) {
53
53
  let attempts = 0;
54
54
  let lastSeenSeq;
55
55
  const probe = deps.probeAlive ?? probeEngineAlive;
56
- let isRecoverableTear;
56
+ let tearShape;
57
57
  const drains = createStreamDrainingLegs();
58
58
  let drainReopenAfterMs;
59
59
  let lastBreak;
@@ -62,6 +62,11 @@ export async function* withHeadlessR1Reconnect(live, deps) {
62
62
  registerRunNotFollowed(originalTearErr, fact);
63
63
  throw originalTearErr;
64
64
  };
65
+ const unboundHandle = (cause) => {
66
+ if (tearShape === 'transport')
67
+ throw originalTearErr;
68
+ return giveUp(mintRunNotFollowed(cause));
69
+ };
65
70
  const terminalFromRunRow = async (taskId) => {
66
71
  const row = await deps.getRun(taskId).catch(() => null);
67
72
  const terminal = terminalEventFromRunRow(row);
@@ -72,21 +77,21 @@ export async function* withHeadlessR1Reconnect(live, deps) {
72
77
  for (;;) {
73
78
  if (deps.signal?.aborted)
74
79
  throw originalTearErr;
75
- if (isRecoverableTear === undefined)
76
- isRecoverableTear = isSseIdleError(originalTearErr);
77
- if (!isRecoverableTear)
80
+ if (tearShape === undefined)
81
+ tearShape = isSseIdleError(originalTearErr) ? 'idle' : guardedTransport(originalTearErr) ? 'transport' : 'other';
82
+ if (tearShape === 'other')
78
83
  throw originalTearErr;
79
84
  let handle;
80
85
  try {
81
86
  handle = deps.getTaskId();
82
87
  }
83
88
  catch {
84
- return giveUp(mintRunNotFollowed('bad_input'));
89
+ return unboundHandle('bad_input');
85
90
  }
86
91
  if (handle === null || handle === undefined)
87
- return giveUp(mintRunNotFollowed('no_run_id'));
92
+ return unboundHandle('no_run_id');
88
93
  if (typeof handle !== 'string' || handle === '')
89
- return giveUp(mintRunNotFollowed('bad_input'));
94
+ return unboundHandle('bad_input');
90
95
  const taskId = handle;
91
96
  if (drainReopenAfterMs !== undefined) {
92
97
  const waitMs = drainReopenAfterMs;
@@ -0,0 +1,13 @@
1
+ export interface ApprovalAskReasonByHook {
2
+ readonly by: 'hook';
3
+ readonly cause: string;
4
+ readonly registration?: string;
5
+ readonly words?: string;
6
+ }
7
+ export interface ApprovalAskReasonByPolicy {
8
+ readonly by: string;
9
+ readonly words: string;
10
+ }
11
+ export type ApprovalAskReason = ApprovalAskReasonByHook | ApprovalAskReasonByPolicy;
12
+ export declare function approvalAskReasonsOf(carrier: object | null | undefined): readonly ApprovalAskReason[] | undefined;
13
+ export declare function approvalAgentIdOf(carrier: object | null | undefined): string | undefined;
@@ -0,0 +1,79 @@
1
+ import { appendOwnElement } from '../ownKey.js';
2
+ import { slotReadOf } from '../wireFailureShape.js';
3
+ function ownNonEmptyText(o, key) {
4
+ const r = slotReadOf(o, key);
5
+ return r.presence === 'present' && typeof r.value === 'string' && r.value !== '' ? r.value : undefined;
6
+ }
7
+ function optionalText(o, key) {
8
+ const r = slotReadOf(o, key);
9
+ if (r.presence === 'absent')
10
+ return { state: 'absent' };
11
+ if (r.presence === 'present' && typeof r.value === 'string')
12
+ return { state: 'text', value: r.value };
13
+ return { state: 'bad' };
14
+ }
15
+ function askReasonOf(item) {
16
+ if (typeof item !== 'object' || item === null)
17
+ return undefined;
18
+ const by = ownNonEmptyText(item, 'by');
19
+ if (by === undefined)
20
+ return undefined;
21
+ const words = optionalText(item, 'words');
22
+ if (words.state === 'bad')
23
+ return undefined;
24
+ if (by === 'hook') {
25
+ const cause = ownNonEmptyText(item, 'cause');
26
+ if (cause === undefined)
27
+ return undefined;
28
+ const registration = optionalText(item, 'registration');
29
+ if (registration.state === 'bad')
30
+ return undefined;
31
+ return Object.freeze({
32
+ by: 'hook',
33
+ cause,
34
+ ...(registration.state === 'text' ? { registration: registration.value } : {}),
35
+ ...(words.state === 'text' ? { words: words.value } : {}),
36
+ });
37
+ }
38
+ if (words.state !== 'text')
39
+ return undefined;
40
+ return Object.freeze({ by, words: words.value });
41
+ }
42
+ export function approvalAskReasonsOf(carrier) {
43
+ try {
44
+ if (typeof carrier !== 'object' || carrier === null)
45
+ return undefined;
46
+ const slot = slotReadOf(carrier, 'askReasons');
47
+ if (slot.presence !== 'present')
48
+ return undefined;
49
+ const raw = slot.value;
50
+ if (typeof raw !== 'object' || raw === null || !Array.isArray(raw))
51
+ return undefined;
52
+ const len = slotReadOf(raw, 'length');
53
+ if (len.presence !== 'present' || typeof len.value !== 'number' || !Number.isSafeInteger(len.value) || len.value < 0)
54
+ return undefined;
55
+ const out = [];
56
+ for (let i = 0; i < len.value; i++) {
57
+ const el = slotReadOf(raw, String(i));
58
+ if (el.presence !== 'present')
59
+ return undefined;
60
+ const reason = askReasonOf(el.value);
61
+ if (reason !== undefined)
62
+ appendOwnElement(out, reason);
63
+ }
64
+ return out.length === 0 ? undefined : Object.freeze(out);
65
+ }
66
+ catch {
67
+ return undefined;
68
+ }
69
+ }
70
+ export function approvalAgentIdOf(carrier) {
71
+ try {
72
+ if (typeof carrier !== 'object' || carrier === null)
73
+ return undefined;
74
+ return ownNonEmptyText(carrier, 'agentId');
75
+ }
76
+ catch {
77
+ return undefined;
78
+ }
79
+ }
@@ -1,18 +1,21 @@
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';
8
+ import { type CheckpointRowVerdictReading } from '../checkpointRowVerdict.js';
7
9
  export declare const APPROVAL_RESOLUTION_LANES: readonly ["respond", "decide", "ask"];
8
10
  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"];
11
+ export declare const APPROVAL_NOT_SENT_CAUSES: readonly ["retracted", "edit_refused", "no_pending", "wrong_gate", "fetch_failed", "no_input", "card_unavailable", "safety_stop", "row_unresumable"];
10
12
  export type ApprovalNotSentCause = (typeof APPROVAL_NOT_SENT_CAUSES)[number];
11
13
  export declare const APPROVAL_UNSETTLED_CAUSES: readonly ["engine_refused", "engine_error", "no_answer", "transport_exhausted", "parking_in_progress", "interrupted", "orchestration", "unreadable"];
12
14
  export type ApprovalUnsettledCause = (typeof APPROVAL_UNSETTLED_CAUSES)[number];
13
15
  export interface ApprovalDenyFacts {
14
16
  readonly settledBy?: ApprovalDenySettledBy;
15
17
  readonly reason?: string;
18
+ readonly policyCause?: PolicyDenyCause;
16
19
  readonly attributionKey?: 'dropped' | 'renamed';
17
20
  }
18
21
  interface ApprovalResolutionBase {
@@ -32,6 +35,9 @@ export interface ApprovalResolutionNotSent extends ApprovalResolutionBase {
32
35
  readonly kind: 'not_sent';
33
36
  readonly cause: ApprovalNotSentCause;
34
37
  readonly safetyCode?: Exclude<HitlSafetyCode, 'binding_mismatch' | 'no_pending' | 'wrong_gate'>;
38
+ readonly rowVerdict?: Exclude<CheckpointRowVerdictReading, {
39
+ readonly kind: 'ok';
40
+ }>;
35
41
  readonly detail?: string;
36
42
  }
37
43
  export interface ApprovalResolutionUnsettled extends ApprovalResolutionBase {
@@ -49,6 +55,7 @@ export declare function approvalUnsettledCause(r: ApprovalResolution): ApprovalU
49
55
  export declare const APPROVAL_NOTE_RETRACTED_DETAIL = "the card was retracted (this host no longer has a decision port for it)";
50
56
  export declare const APPROVAL_NOTE_EDIT_REFUSED_DETAIL = "edits are not accepted on this card";
51
57
  export declare function approvalResolutionDetail(r: ApprovalResolution): string | undefined;
58
+ export declare function approvalResolutionStatusTag(r: ApprovalResolution): string;
52
59
  export declare function unsettledCauseOfReading(reading: DecisionRefusalReading): 'engine_refused' | 'engine_error' | 'no_answer';
53
60
  export interface DecisionFailureMint {
54
61
  readonly lane: ApprovalResolutionLane;
@@ -1,9 +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, unboundWayOutContent } from '../checkpointRowVerdict.js';
7
8
  export const APPROVAL_RESOLUTION_LANES = Object.freeze(['respond', 'decide', 'ask']);
8
9
  export const APPROVAL_NOT_SENT_CAUSES = Object.freeze([
9
10
  'retracted',
@@ -14,6 +15,7 @@ export const APPROVAL_NOT_SENT_CAUSES = Object.freeze([
14
15
  'no_input',
15
16
  'card_unavailable',
16
17
  'safety_stop',
18
+ 'row_unresumable',
17
19
  ]);
18
20
  export const APPROVAL_UNSETTLED_CAUSES = Object.freeze([
19
21
  'engine_refused',
@@ -49,6 +51,7 @@ const NOT_SENT_SENTENCES = Object.freeze({
49
51
  no_input: 'the approval has no tool input or question to show, so no card was shown; nothing was sent',
50
52
  card_unavailable: 'no approval card could be shown on this host; nothing was sent',
51
53
  safety_stop: 'the decision was stopped by a local safety check before it was sent; nothing was sent',
54
+ row_unresumable: CHECKPOINT_ROW_BAR_SENTENCE,
52
55
  });
53
56
  function nonEmpty(v) {
54
57
  return typeof v === 'string' && v.length > 0 ? v : undefined;
@@ -77,8 +80,21 @@ export function approvalResolutionDetail(r) {
77
80
  if (cause === undefined || !Object.hasOwn(NOT_SENT_SENTENCES, cause))
78
81
  return undefined;
79
82
  const sentence = NOT_SENT_SENTENCES[cause];
83
+ if (cause === 'row_unresumable') {
84
+ let verdict;
85
+ try {
86
+ const d = Object.getOwnPropertyDescriptor(r, 'rowVerdict');
87
+ verdict = d !== undefined && Object.hasOwn(d, 'value') ? d.value : undefined;
88
+ }
89
+ catch {
90
+ verdict = undefined;
91
+ }
92
+ return ownStr(verdict, 'kind') !== 'unreadable' ? (ownStr(verdict, 'sentence') ?? sentence) : sentence;
93
+ }
80
94
  const code = cause === 'safety_stop' ? ownStr(r, 'safetyCode') : undefined;
81
- return code !== undefined ? `${sentence} (${code})` : sentence;
95
+ if (code === undefined)
96
+ return sentence;
97
+ return code === 'binding_missing' ? `${sentence} (${code}) · ${unboundWayOutContent('unknown')}` : `${sentence} (${code})`;
82
98
  }
83
99
  if (kind !== 'unsettled')
84
100
  return undefined;
@@ -93,6 +109,25 @@ export function approvalResolutionDetail(r) {
93
109
  const parts = [ownStr(refusal, 'errorCode'), ownStr(r, 'detail') ?? ownStr(refusal, 'message')].filter((x) => x !== undefined);
94
110
  return parts.length > 0 ? parts.join(' · ') : undefined;
95
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
+ }
96
131
  export function unsettledCauseOfReading(reading) {
97
132
  const standing = ownReadingSlot(reading, 'standing');
98
133
  if (standing === 'ambiguous')
@@ -1,8 +1,10 @@
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';
5
6
  import { approvalQueueRowFamilyOf, peerInboundQueueRowOf } from './approvalQueueRow.js';
7
+ import { parkRowDelegationLinksOf } from './parkRowDelegation.js';
6
8
  import { checkpointRowVerdictOf } from '../checkpointRowVerdict.js';
7
9
  const _realClientFitsFeedSlice = true;
8
10
  void _realClientFitsFeedSlice;
@@ -49,7 +51,7 @@ function readDurablePendingRows(raw) {
49
51
  }
50
52
  function durableDigestOf(rows) {
51
53
  return rows
52
- .map(r => [r.sessionId ?? '', r.taskId ?? '', r.toolCallId ?? '', r.boundCallId ?? '', r.boundInputHash ?? '', r.toolName ?? '', JSON.stringify(checkpointRowVerdictOf(r) ?? null)]
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)]
53
55
  .join(''))
54
56
  .sort()
55
57
  .join('');
@@ -175,12 +177,7 @@ export function startApprovalsFeed(client, onSnapshot, opts) {
175
177
  const at = Date.now();
176
178
  blind = { why, at };
177
179
  stats.unknowns++;
178
- try {
179
- onSnapshot({ kind: 'unknown', why, at, mode: via });
180
- }
181
- catch (e) {
182
- hostLog('debug', `approvalsFeed: subscriber threw on the unknown arm (swallowed): ${String(e)}`);
183
- }
180
+ invokeHostCallbackIsolated('approvalsFeed: subscriber (unknown arm)', () => onSnapshot({ kind: 'unknown', why, at, mode: via }));
184
181
  }
185
182
  async function take(via, leg) {
186
183
  if (stopped)
@@ -292,12 +289,7 @@ export function startApprovalsFeed(client, onSnapshot, opts) {
292
289
  };
293
290
  last = snap;
294
291
  stats.snapshots++;
295
- try {
296
- onSnapshot(snap);
297
- }
298
- catch (e) {
299
- hostLog('debug', `approvalsFeed: subscriber threw (swallowed): ${String(e)}`);
300
- }
292
+ invokeHostCallbackIsolated('approvalsFeed: subscriber', () => onSnapshot(snap));
301
293
  }
302
294
  function schedulePoll() {
303
295
  if (stopped || ac.signal.aborted)
@@ -3,6 +3,8 @@ import { isAskTool, questionCardVerdict } from './frameRouter.js';
3
3
  import { approvalCallKey } from './gateIdentity.js';
4
4
  import { askQuestionsFromPending, pendingRowIsOwnedByThisSession } from './parkOwnership.js';
5
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';
6
8
  export const ASK_PARK_ROW_WAIT_MS = 15000;
7
9
  export const ASK_PARK_ROW_POLL_MS = 500;
8
10
  export function classifyAskParkRows(queueRows, taskId, deps) {
@@ -29,6 +31,15 @@ export function classifyAskParkRows(queueRows, taskId, deps) {
29
31
  };
30
32
  }
31
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
+ rowTaskId: askParkRowTaskIdOf(taskId, pending),
41
+ };
42
+ }
32
43
  if (foreignKind !== null) {
33
44
  return {
34
45
  kind: 'unborn',
@@ -40,8 +51,11 @@ export function classifyAskParkRows(queueRows, taskId, deps) {
40
51
  function askParkRowGateKind(row) {
41
52
  return typeof row.gateKind === 'string' && row.gateKind.length > 0 ? row.gateKind : null;
42
53
  }
54
+ function askParkRowTaskIdOf(taskId, row) {
55
+ return typeof row.taskId === 'string' && row.taskId.length > 0 ? row.taskId : taskId;
56
+ }
43
57
  export function askParkRowIdentity(taskId, row) {
44
- const rowTaskId = typeof row.taskId === 'string' && row.taskId.length > 0 ? row.taskId : taskId;
58
+ const rowTaskId = askParkRowTaskIdOf(taskId, row);
45
59
  const gatedCallId = row.toolCallId ?? row.boundCallId ?? undefined;
46
60
  return { rowTaskId, gatedCallId, armedKey: approvalCallKey(gatedCallId, rowTaskId) };
47
61
  }
@@ -129,6 +143,8 @@ export function pendingRowIsOwnedAndDecidable(row, deps) {
129
143
  return true;
130
144
  if (leg !== 'approval')
131
145
  return false;
146
+ if (checkpointRowBarOf(row) !== undefined)
147
+ return false;
132
148
  return askParkRowArm(row) === 'question' ? askQuestionsFromPending(row) !== null : true;
133
149
  }
134
150
  export function countOwnedPendingRows(listed, deps) {
@@ -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 code = typeof facts.errorCode === 'string' && isDisplayableWireCode(facts.errorCode) ? ` ${facts.errorCode}` : '';
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':
@@ -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';
@@ -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';
@@ -10,7 +11,7 @@ import { readDecisionNoteAudit } from './approvalDecisionNoteAudit.js';
10
11
  import { carrierReadOf, deliverWithAttributionLadder, isLocalSafetyStop } from './attributionLadder.js';
11
12
  import { budgetSpent, deliverApprovalDecision, deliveryTiming, isAborted, newSendTally, PARKING_WAIT_CAP_MS, setDeliveryTimingForTests, sleepFor, settledTransportReadingOf, withTransportRetry, deliveryReadingOf, } from './approvalDelivery.js';
12
13
  import { ASK_DECIDED_CODE, classifyDeliveredDecisionRefusal, decisionRefusalClosesOut, notPendingAfterRetry } from './decisionRefusal.js';
13
- import { sessionAllowCarried } from './sessionAllowRoute.js';
14
+ import { sessionAllowEligible } from './sessionAllowRoute.js';
14
15
  import { addDecisionOpKeys, closeDecisionOp, decisionLedgerKeysOf, decisionOpsWithKey, openDecisionOp } from './decisionLedger.js';
15
16
  import { hostHoldIsActive, takeHostHoldLedgerOp, tryHoldApprovalNow } from './approvalHolds.js';
16
17
  import { answerPayloadFor, decisionAttributionKeyOf, isToolApprovalRespondReplayed, readApprovalDenySettledBy, readToolApprovalRespondAck, readToolApprovalRespondParking, } from './toolApprovalWire.js';
@@ -195,7 +196,7 @@ async function sendAskFamily(respondForFallback, decideAsk, req, ctx) {
195
196
  if (payload === undefined)
196
197
  return { family: 'ask', attempts: ctx.tally.attempts, kind: 'not_sent', cause: 'not_an_answer' };
197
198
  let fallbackRespond = respondForFallback;
198
- if (req.answer.kind === 'allow' && req.answer.allowSession === true && respondForFallback !== undefined && req.approvalId !== undefined && sessionAllowCarried('v1', req.approvalId)) {
199
+ if (req.answer.kind === 'allow' && req.answer.allowSession === true && respondForFallback !== undefined && req.approvalId !== undefined) {
199
200
  const viaAnswerGate = await sendApprovalFamily(respondForFallback, req.approvalId, req.answer, ctx);
200
201
  if (!answerGateCannotTake(viaAnswerGate))
201
202
  return { ...viaAnswerGate, family: 'ask', allowSessionCarried: true };
@@ -343,12 +344,7 @@ function holdFits(handle, req) {
343
344
  }
344
345
  }
345
346
  function callHold(call) {
346
- try {
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)
@@ -386,6 +382,14 @@ function snapshotAnswer(raw) {
386
382
  }
387
383
  return typeof kind === 'string' ? Object.freeze({ kind }) : undefined;
388
384
  }
385
+ function sessionGatedAnswer(answer, card) {
386
+ if (answer.kind !== 'allow' || answer.allowSession !== true)
387
+ return { answer };
388
+ const why = card === undefined ? 'card_absent' : typeof card === 'object' && card !== null ? sessionAllowEligible(card) : 'card_unreadable';
389
+ if (why === 'given')
390
+ return { answer };
391
+ return { answer: Object.freeze({ ...answer, allowSession: false }), dropped: why };
392
+ }
389
393
  function readRequest(req) {
390
394
  if (typeof req !== 'object' || req === null)
391
395
  return undefined;
@@ -399,17 +403,19 @@ function readRequest(req) {
399
403
  const rawAnswer = guardedRead(() => readOwnDataValue(req, 'answer'));
400
404
  if (typeof rawAnswer !== 'object' || rawAnswer === null)
401
405
  return undefined;
402
- const answer = snapshotAnswer(rawAnswer);
403
- if (answer === undefined)
406
+ const snapshot = snapshotAnswer(rawAnswer);
407
+ if (snapshot === undefined)
404
408
  return undefined;
409
+ const { answer, dropped } = sessionGatedAnswer(snapshot, guardedRead(() => readOwnDataValue(req, 'card')));
410
+ const droppedFact = dropped !== undefined ? { sessionAllowDropped: dropped } : {};
405
411
  if (family === 'approval') {
406
412
  const approvalId = s('approvalId');
407
- return approvalId !== undefined ? { family, approvalId, taskId: s('taskId'), toolCallId: s('toolCallId'), answer } : undefined;
413
+ return approvalId !== undefined ? { family, approvalId, taskId: s('taskId'), toolCallId: s('toolCallId'), answer, ...droppedFact } : undefined;
408
414
  }
409
415
  if (family === 'ask') {
410
416
  const taskId = s('taskId');
411
417
  const askId = s('askId');
412
- return taskId !== undefined && askId !== undefined ? { family, taskId, askId, approvalId: s('approvalId'), toolCallId: s('toolCallId'), answer } : undefined;
418
+ return taskId !== undefined && askId !== undefined ? { family, taskId, askId, approvalId: s('approvalId'), toolCallId: s('toolCallId'), answer, ...droppedFact } : undefined;
413
419
  }
414
420
  return undefined;
415
421
  }
@@ -519,6 +525,10 @@ export async function sendHitlDecision(request, deps) {
519
525
  out = outcomeOfThrown(e, 'elicitation', undefined, signal, ctx.tally, false);
520
526
  }
521
527
  }
528
+ if (req.family !== 'elicitation' && req.sessionAllowDropped !== undefined) {
529
+ hostLog('debug', `decisionSend: session-allow-not-eligible ${req.family}=${req.family === 'ask' ? req.askId : req.approvalId} why=${req.sessionAllowDropped} via=allow-once`);
530
+ out = { ...out, rememberDropped: true };
531
+ }
522
532
  const ambiguous = out.kind === 'unconfirmed' || (out.kind === 'not_applied' && (out.cause === 'parking' || out.cause === 'refused' || out.cause === 'idempotency_crossed'));
523
533
  if (ambiguous && out.cause !== 'aborted') {
524
534
  const gate = req.family === 'elicitation'
@@ -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 {