@sema-agent/client-core 0.107.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 (98) hide show
  1. package/CHANGELOG.md +118 -0
  2. package/README.md +19 -14
  3. package/dist/adapter/activeRunSelfHeal.d.ts +2 -0
  4. package/dist/adapter/activeRunSelfHeal.js +20 -3
  5. package/dist/checkpointRowVerdict.d.ts +5 -0
  6. package/dist/checkpointRowVerdict.js +26 -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/engineErrorCodes.d.ts +5 -0
  13. package/dist/engineErrorCodes.js +5 -0
  14. package/dist/engineNoticeCodes.d.ts +19 -1
  15. package/dist/engineNoticeCodes.js +65 -3
  16. package/dist/engineTargetSeat.js +1 -0
  17. package/dist/errorSupplementRoles.js +2 -0
  18. package/dist/eventLeg.js +1 -1
  19. package/dist/executionLaneWords.js +2 -1
  20. package/dist/gateOutcome.d.ts +10 -1
  21. package/dist/gateOutcome.js +48 -1
  22. package/dist/generated/engineFactTables.d.ts +1 -0
  23. package/dist/generated/engineFactTables.js +5 -0
  24. package/dist/generated/engineNoticeTables.js +3 -0
  25. package/dist/generated/settingsSchemaFns.d.ts +4 -2
  26. package/dist/generated/settingsSchemaFns.js +9 -3
  27. package/dist/generated/settingsSchemaMcpRequestEntry.d.ts +1 -1
  28. package/dist/generated/settingsSchemaMcpRequestEntry.js +9 -18
  29. package/dist/generated/settingsSchemaReservedMemberName.d.ts +1 -0
  30. package/dist/generated/settingsSchemaReservedMemberName.js +7 -0
  31. package/dist/generated/settingsSchemaTables.d.ts +2 -0
  32. package/dist/generated/settingsSchemaTables.js +10 -0
  33. package/dist/generated/settingsSchemaWireName.d.ts +1 -0
  34. package/dist/generated/settingsSchemaWireName.js +8 -0
  35. package/dist/headlessReconnectWire.js +12 -7
  36. package/dist/hitl/approvalAskers.d.ts +13 -0
  37. package/dist/hitl/approvalAskers.js +79 -0
  38. package/dist/hitl/approvalResolution.d.ts +3 -0
  39. package/dist/hitl/approvalResolution.js +22 -4
  40. package/dist/hitl/approvalsFeed.js +3 -12
  41. package/dist/hitl/askParkRowRouting.js +5 -1
  42. package/dist/hitl/decisionRefusal.d.ts +1 -0
  43. package/dist/hitl/decisionRefusal.js +5 -2
  44. package/dist/hitl/decisionSend.js +2 -6
  45. package/dist/hitl/frameRouter.d.ts +3 -2
  46. package/dist/hitl/frameRouter.js +28 -6
  47. package/dist/hitl/gateLedger.d.ts +2 -0
  48. package/dist/hitl/gateLedger.js +3 -1
  49. package/dist/hitl/hitlBridge.js +2 -3
  50. package/dist/hitl/parkResolver.js +32 -23
  51. package/dist/hitl/parkRowBirthWait.d.ts +2 -0
  52. package/dist/hitl/parkRowBirthWait.js +8 -1
  53. package/dist/hitl/persistedRulesWire.d.ts +5 -1
  54. package/dist/hitl/persistedRulesWire.js +20 -4
  55. package/dist/hitl/planReviewWire.js +12 -16
  56. package/dist/hitl/policyDenyCause.d.ts +3 -0
  57. package/dist/hitl/policyDenyCause.js +16 -0
  58. package/dist/hitl/sessionPolicyDeliverable.js +1 -1
  59. package/dist/hitl/toolApprovalWire.d.ts +8 -2
  60. package/dist/hitl/toolApprovalWire.js +22 -3
  61. package/dist/hooksReaderGenerations.d.ts +1 -0
  62. package/dist/hooksReaderGenerations.js +12 -0
  63. package/dist/hooksWireCaps.js +8 -4
  64. package/dist/i18n/messages.en.d.ts +38 -1
  65. package/dist/i18n/messages.en.js +40 -3
  66. package/dist/i18n/messages.zh.js +45 -3
  67. package/dist/index.d.ts +6 -1
  68. package/dist/index.js +4 -1
  69. package/dist/liveModelCatalog.d.ts +4 -2
  70. package/dist/liveModelCatalog.js +164 -26
  71. package/dist/model/catalogDefault.d.ts +25 -0
  72. package/dist/model/catalogDefault.js +44 -0
  73. package/dist/permissionWireCaps.d.ts +1 -0
  74. package/dist/permissionWireCaps.js +11 -0
  75. package/dist/pluginHooksWire.d.ts +5 -3
  76. package/dist/pluginHooksWire.js +116 -7
  77. package/dist/queuedDelivery.d.ts +1 -0
  78. package/dist/queuedDelivery.js +12 -0
  79. package/dist/resultFrameKeys.js +4 -2
  80. package/dist/resumeRefusalCopy.js +15 -8
  81. package/dist/runPermissionModeSwitch.d.ts +2 -1
  82. package/dist/runPermissionModeSwitch.js +16 -6
  83. package/dist/seatContract.d.ts +63 -10
  84. package/dist/seatContract.js +164 -11
  85. package/dist/sessionEngine.d.ts +2 -1
  86. package/dist/sessionEngine.js +5 -0
  87. package/dist/settingsHooksSalvage.d.ts +5 -0
  88. package/dist/settingsHooksSalvage.js +54 -0
  89. package/dist/subagentContentStore.js +1 -1
  90. package/dist/supportFloor.js +2 -0
  91. package/dist/taskNotificationAdmission.d.ts +19 -0
  92. package/dist/taskNotificationAdmission.js +84 -0
  93. package/dist/toolResult.js +2 -1
  94. package/dist/webSearchWireCaps.js +9 -4
  95. package/dist/wireRefusalCopy.d.ts +2 -1
  96. package/dist/wireRefusalCopy.js +2 -2
  97. package/docs/INTEGRATION-CLIENTS.md +816 -14
  98. package/package.json +4 -4
@@ -34,18 +34,20 @@ export declare const SETTINGS_READ_KEY: (record: object, key: PropertyKey) => ob
34
34
  export declare const SETTINGS_IS_RESERVED_MCP_SERVER_NAME: (name: string) => boolean;
35
35
  export declare const SETTINGS_REMOTE_MCP_SERVER_NAME_PREFIX: "remote-";
36
36
  export declare const SETTINGS_RESERVED_MCP_SERVER_NAME_REASON: "the \"remote-\" prefix is reserved for the remote MCP servers a device executor offers";
37
+ export declare const SETTINGS_IS_USABLE_WIRE_NAME: (v: unknown) => v is string;
38
+ export declare const SETTINGS_TOOL_WIRE_NAME_MAX_CHARS: 128;
39
+ export declare const SETTINGS_HAS_EDGE_WHITESPACE: (v: string) => boolean;
40
+ export declare const SETTINGS_IS_RESERVED_MEMBER_NAME: (name: string) => boolean;
37
41
  export declare const SETTINGS_READ_REQUEST_MCP_TRANSPORT: (t: unknown) => RequestMcpTransportRead;
38
42
  export declare const SETTINGS_READ_MCP_IDENTITY_HEADERS: (transport: Record<string, unknown>) => {
39
43
  principalHeader?: string;
40
44
  assertionHeader?: string;
41
45
  };
42
- export declare const SETTINGS_IS_USABLE_WIRE_NAME: (v: unknown) => v is string;
43
46
  export declare const SETTINGS_DESCRIBE_BAD_WIRE_NAME: (v: unknown) => string;
44
47
  export declare const SETTINGS_IS_USABLE_MCP_SERVER_NAME: (v: unknown) => v is string;
45
48
  export declare const SETTINGS_DESCRIBE_BAD_MCP_SERVER_NAME: (v: unknown) => string;
46
49
  export declare const SETTINGS_IS_CONTENT_ORIGIN_WORD: (v: unknown) => v is McpContentOrigin;
47
50
  export declare const SETTINGS_DESCRIBE_BAD_CONTENT_ORIGIN: (v: unknown) => string;
48
- export declare const SETTINGS_TOOL_WIRE_NAME_MAX_CHARS: 128;
49
51
  export declare const SETTINGS_URL_ALLOW_PATTERN_MATCHES: (url: string, pattern: string) => boolean;
50
52
  export declare const SETTINGS_IS_AT_LEAST: (layer: string, minTrust: string) => boolean;
51
53
  export declare const SETTINGS_MEMBER_ADMISSION: (category: string, member: string) => object;
@@ -4,6 +4,8 @@ import { SETTINGS_CALLER_TEXT_ECHO_CLOSURE } from './settingsSchemaCallerTextEch
4
4
  import { SETTINGS_PLAIN_JSON_OBJECT_CLOSURE } from './settingsSchemaPlainJsonObject.js';
5
5
  import { SETTINGS_OWN_KEY_READ_CLOSURE } from './settingsSchemaOwnKeyRead.js';
6
6
  import { SETTINGS_MCP_SERVER_NAME_CLOSURE } from './settingsSchemaMcpServerName.js';
7
+ import { SETTINGS_WIRE_NAME_CLOSURE } from './settingsSchemaWireName.js';
8
+ import { SETTINGS_RESERVED_MEMBER_NAME_CLOSURE } from './settingsSchemaReservedMemberName.js';
7
9
  import { SETTINGS_MCP_REQUEST_ENTRY_CLOSURE } from './settingsSchemaMcpRequestEntry.js';
8
10
  import { SETTINGS_MCP_CONTENT_ORIGINS } from './settingsSchemaTables.js';
9
11
  import { SETTINGS_URL_ALLOW_PATTERN_MATCHES_CLOSURE } from './settingsSchemaUrlPattern.js';
@@ -167,16 +169,20 @@ const SETTINGS_MCP_SERVER_NAME = SETTINGS_MCP_SERVER_NAME_CLOSURE();
167
169
  export const SETTINGS_IS_RESERVED_MCP_SERVER_NAME = SETTINGS_MCP_SERVER_NAME.isReservedMcpServerName;
168
170
  export const SETTINGS_REMOTE_MCP_SERVER_NAME_PREFIX = SETTINGS_MCP_SERVER_NAME.REMOTE_MCP_SERVER_NAME_PREFIX;
169
171
  export const SETTINGS_RESERVED_MCP_SERVER_NAME_REASON = SETTINGS_MCP_SERVER_NAME.RESERVED_MCP_SERVER_NAME_REASON;
170
- const SETTINGS_MCP_REQUEST_ENTRY = SETTINGS_MCP_REQUEST_ENTRY_CLOSURE(SETTINGS_MCP_CONTENT_ORIGINS, SETTINGS_STARTS_WITH_HTTP_SCHEME, SETTINGS_ECHO_CALLER_TEXT, SETTINGS_UNINSPECTABLE, SETTINGS_CAPTURE_STRING_ARRAY, SETTINGS_DATA_DESCRIPTOR, SETTINGS_INSPECT, SETTINGS_OWN_FIELDS_OF, SETTINGS_OWN_VALUE_OF, SETTINGS_READ_KEY, SETTINGS_IS_JSON_ARRAY, SETTINGS_JSON_SHAPE_OF, SETTINGS_IS_RESERVED_MCP_SERVER_NAME, SETTINGS_RESERVED_MCP_SERVER_NAME_REASON);
172
+ const SETTINGS_WIRE_NAME = SETTINGS_WIRE_NAME_CLOSURE();
173
+ export const SETTINGS_IS_USABLE_WIRE_NAME = SETTINGS_WIRE_NAME.isUsableWireName;
174
+ export const SETTINGS_TOOL_WIRE_NAME_MAX_CHARS = SETTINGS_WIRE_NAME.TOOL_WIRE_NAME_MAX_CHARS;
175
+ export const SETTINGS_HAS_EDGE_WHITESPACE = SETTINGS_WIRE_NAME.hasEdgeWhitespace;
176
+ const SETTINGS_RESERVED_MEMBER_NAME = SETTINGS_RESERVED_MEMBER_NAME_CLOSURE();
177
+ export const SETTINGS_IS_RESERVED_MEMBER_NAME = SETTINGS_RESERVED_MEMBER_NAME.isReservedMemberName;
178
+ const SETTINGS_MCP_REQUEST_ENTRY = SETTINGS_MCP_REQUEST_ENTRY_CLOSURE(SETTINGS_MCP_CONTENT_ORIGINS, SETTINGS_STARTS_WITH_HTTP_SCHEME, SETTINGS_ECHO_CALLER_TEXT, SETTINGS_UNINSPECTABLE, SETTINGS_CAPTURE_STRING_ARRAY, SETTINGS_DATA_DESCRIPTOR, SETTINGS_INSPECT, SETTINGS_OWN_FIELDS_OF, SETTINGS_OWN_VALUE_OF, SETTINGS_READ_KEY, SETTINGS_IS_JSON_ARRAY, SETTINGS_JSON_SHAPE_OF, SETTINGS_IS_RESERVED_MCP_SERVER_NAME, SETTINGS_RESERVED_MCP_SERVER_NAME_REASON, SETTINGS_TOOL_WIRE_NAME_MAX_CHARS, SETTINGS_HAS_EDGE_WHITESPACE, SETTINGS_IS_USABLE_WIRE_NAME, SETTINGS_IS_RESERVED_MEMBER_NAME);
171
179
  export const SETTINGS_READ_REQUEST_MCP_TRANSPORT = SETTINGS_MCP_REQUEST_ENTRY.readRequestMcpTransport;
172
180
  export const SETTINGS_READ_MCP_IDENTITY_HEADERS = SETTINGS_MCP_REQUEST_ENTRY.readMcpIdentityHeaders;
173
- export const SETTINGS_IS_USABLE_WIRE_NAME = SETTINGS_MCP_REQUEST_ENTRY.isUsableWireName;
174
181
  export const SETTINGS_DESCRIBE_BAD_WIRE_NAME = SETTINGS_MCP_REQUEST_ENTRY.describeBadWireName;
175
182
  export const SETTINGS_IS_USABLE_MCP_SERVER_NAME = SETTINGS_MCP_REQUEST_ENTRY.isUsableMcpServerName;
176
183
  export const SETTINGS_DESCRIBE_BAD_MCP_SERVER_NAME = SETTINGS_MCP_REQUEST_ENTRY.describeBadMcpServerName;
177
184
  export const SETTINGS_IS_CONTENT_ORIGIN_WORD = SETTINGS_MCP_REQUEST_ENTRY.isContentOriginWord;
178
185
  export const SETTINGS_DESCRIBE_BAD_CONTENT_ORIGIN = SETTINGS_MCP_REQUEST_ENTRY.describeBadContentOrigin;
179
- export const SETTINGS_TOOL_WIRE_NAME_MAX_CHARS = SETTINGS_MCP_REQUEST_ENTRY.TOOL_WIRE_NAME_MAX_CHARS;
180
186
  export const SETTINGS_URL_ALLOW_PATTERN_MATCHES = SETTINGS_URL_ALLOW_PATTERN_MATCHES_CLOSURE();
181
187
  const SETTINGS_SAFETY_MERGE = SETTINGS_SAFETY_MERGE_CLOSURE(SETTINGS_MIN_TRUST_WORDS);
182
188
  export const SETTINGS_IS_AT_LEAST = SETTINGS_SAFETY_MERGE.isAtLeast;
@@ -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,6 +1,7 @@
1
1
  import type { DecideReceiptView } from '../decideReceipt.js';
2
2
  import { type HitlSafetyCode } from './hitlBridge.js';
3
3
  import type { AskAnsweredOutput } from './gateLedger.js';
4
+ import type { PolicyDenyCause } from './policyDenyCause.js';
4
5
  import type { ApprovalDenySettledBy, ToolApprovalRespondAckView, ToolApprovalRespondDecision, ToolApprovalRespondParkingView } from './toolApprovalWire.js';
5
6
  import { type DecisionRefusalReading, type RefusalRouteContext } from './decisionRefusal.js';
6
7
  import { type DeliveredReading, type LadderSafetyStop } from './attributionLadder.js';
@@ -14,6 +15,7 @@ export type ApprovalUnsettledCause = (typeof APPROVAL_UNSETTLED_CAUSES)[number];
14
15
  export interface ApprovalDenyFacts {
15
16
  readonly settledBy?: ApprovalDenySettledBy;
16
17
  readonly reason?: string;
18
+ readonly policyCause?: PolicyDenyCause;
17
19
  readonly attributionKey?: 'dropped' | 'renamed';
18
20
  }
19
21
  interface ApprovalResolutionBase {
@@ -53,6 +55,7 @@ export declare function approvalUnsettledCause(r: ApprovalResolution): ApprovalU
53
55
  export declare const APPROVAL_NOTE_RETRACTED_DETAIL = "the card was retracted (this host no longer has a decision port for it)";
54
56
  export declare const APPROVAL_NOTE_EDIT_REFUSED_DETAIL = "edits are not accepted on this card";
55
57
  export declare function approvalResolutionDetail(r: ApprovalResolution): string | undefined;
58
+ export declare function approvalResolutionStatusTag(r: ApprovalResolution): string;
56
59
  export declare function unsettledCauseOfReading(reading: DecisionRefusalReading): 'engine_refused' | 'engine_error' | 'no_answer';
57
60
  export interface DecisionFailureMint {
58
61
  readonly lane: ApprovalResolutionLane;
@@ -1,11 +1,10 @@
1
1
  import { DecideTransportRetryExhaustedError, refusalCarrierOf, safetyStopHeadOf, safetyStopNamed } from './hitlBridge.js';
2
- import { mintDecisionRefusalReading } from './decisionRefusal.js';
2
+ import { decisionStatusTag, mintDecisionRefusalReading } from './decisionRefusal.js';
3
3
  import { isSlotCarrier, thrownIsInstanceOf } from '../wireFailureShape.js';
4
4
  import { carrierReadOf, isLocalSafetyStop, localCodeReadOf, topCauseReadOf } from './attributionLadder.js';
5
5
  import { directFailureReadingOf, transportReadingOf } from './approvalDelivery.js';
6
6
  import { ownReadingSlot } from '../engineWireFor.js';
7
- import { CHECKPOINT_ROW_BAR_SENTENCE } from '../checkpointRowVerdict.js';
8
- import { msg, renderMessage } from '../i18n/translate.js';
7
+ import { CHECKPOINT_ROW_BAR_SENTENCE, unboundWayOutContent } from '../checkpointRowVerdict.js';
9
8
  export const APPROVAL_RESOLUTION_LANES = Object.freeze(['respond', 'decide', 'ask']);
10
9
  export const APPROVAL_NOT_SENT_CAUSES = Object.freeze([
11
10
  'retracted',
@@ -95,7 +94,7 @@ export function approvalResolutionDetail(r) {
95
94
  const code = cause === 'safety_stop' ? ownStr(r, 'safetyCode') : undefined;
96
95
  if (code === undefined)
97
96
  return sentence;
98
- return code === 'binding_missing' ? `${sentence} (${code}) · ${renderMessage(msg('approval.decide.unboundWayOut'))}` : `${sentence} (${code})`;
97
+ return code === 'binding_missing' ? `${sentence} (${code}) · ${unboundWayOutContent('unknown')}` : `${sentence} (${code})`;
99
98
  }
100
99
  if (kind !== 'unsettled')
101
100
  return undefined;
@@ -110,6 +109,25 @@ export function approvalResolutionDetail(r) {
110
109
  const parts = [ownStr(refusal, 'errorCode'), ownStr(r, 'detail') ?? ownStr(refusal, 'message')].filter((x) => x !== undefined);
111
110
  return parts.length > 0 ? parts.join(' · ') : undefined;
112
111
  }
112
+ export function approvalResolutionStatusTag(r) {
113
+ try {
114
+ if (typeof r !== 'object' || r === null)
115
+ return '';
116
+ const kd = Object.getOwnPropertyDescriptor(r, 'kind');
117
+ if (kd === undefined || !Object.hasOwn(kd, 'value') || kd.value !== 'unsettled')
118
+ return '';
119
+ const rd = Object.getOwnPropertyDescriptor(r, 'refusal');
120
+ const refusal = rd !== undefined && Object.hasOwn(rd, 'value') ? rd.value : undefined;
121
+ if (typeof refusal !== 'object' || refusal === null)
122
+ return '';
123
+ const sd = Object.getOwnPropertyDescriptor(refusal, 'status');
124
+ const status = sd !== undefined && Object.hasOwn(sd, 'value') ? sd.value : undefined;
125
+ return typeof status === 'number' && Number.isInteger(status) && status >= 400 && status <= 599 ? decisionStatusTag(status) : '';
126
+ }
127
+ catch {
128
+ return '';
129
+ }
130
+ }
113
131
  export function unsettledCauseOfReading(reading) {
114
132
  const standing = ownReadingSlot(reading, 'standing');
115
133
  if (standing === 'ambiguous')
@@ -1,4 +1,5 @@
1
1
  import { hostLog } from '../host.js';
2
+ import { invokeHostCallbackIsolated } from '../hostCallbackGuard.js';
2
3
  import { unrefTimer } from '../unrefTimer.js';
3
4
  import { readLivePendingRows } from './livePendingAsk.js';
4
5
  import { createStreamDrainingLegs } from '../streamDrainingLegs.js';
@@ -176,12 +177,7 @@ export function startApprovalsFeed(client, onSnapshot, opts) {
176
177
  const at = Date.now();
177
178
  blind = { why, at };
178
179
  stats.unknowns++;
179
- try {
180
- onSnapshot({ kind: 'unknown', why, at, mode: via });
181
- }
182
- catch (e) {
183
- hostLog('debug', `approvalsFeed: subscriber threw on the unknown arm (swallowed): ${String(e)}`);
184
- }
180
+ invokeHostCallbackIsolated('approvalsFeed: subscriber (unknown arm)', () => onSnapshot({ kind: 'unknown', why, at, mode: via }));
185
181
  }
186
182
  async function take(via, leg) {
187
183
  if (stopped)
@@ -293,12 +289,7 @@ export function startApprovalsFeed(client, onSnapshot, opts) {
293
289
  };
294
290
  last = snap;
295
291
  stats.snapshots++;
296
- try {
297
- onSnapshot(snap);
298
- }
299
- catch (e) {
300
- hostLog('debug', `approvalsFeed: subscriber threw (swallowed): ${String(e)}`);
301
- }
292
+ invokeHostCallbackIsolated('approvalsFeed: subscriber', () => onSnapshot(snap));
302
293
  }
303
294
  function schedulePoll() {
304
295
  if (stopped || ac.signal.aborted)
@@ -37,6 +37,7 @@ export function classifyAskParkRows(queueRows, taskId, deps) {
37
37
  kind: 'settled',
38
38
  reason: renderMessage(msg('approval.rowUnresumable.askNotSurfaced', { taskId: String(pending.taskId), sentence: checkpointRowBarSentence(bar) })),
39
39
  rowVerdict: bar,
40
+ rowTaskId: askParkRowTaskIdOf(taskId, pending),
40
41
  };
41
42
  }
42
43
  if (foreignKind !== null) {
@@ -50,8 +51,11 @@ export function classifyAskParkRows(queueRows, taskId, deps) {
50
51
  function askParkRowGateKind(row) {
51
52
  return typeof row.gateKind === 'string' && row.gateKind.length > 0 ? row.gateKind : null;
52
53
  }
54
+ function askParkRowTaskIdOf(taskId, row) {
55
+ return typeof row.taskId === 'string' && row.taskId.length > 0 ? row.taskId : taskId;
56
+ }
53
57
  export function askParkRowIdentity(taskId, row) {
54
- const rowTaskId = typeof row.taskId === 'string' && row.taskId.length > 0 ? row.taskId : taskId;
58
+ const rowTaskId = askParkRowTaskIdOf(taskId, row);
55
59
  const gatedCallId = row.toolCallId ?? row.boundCallId ?? undefined;
56
60
  return { rowTaskId, gatedCallId, armedKey: approvalCallKey(gatedCallId, rowTaskId) };
57
61
  }
@@ -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':
@@ -1,5 +1,6 @@
1
1
  import { settleWithinDeadline } from '../abortableSleep.js';
2
2
  import { hostLog } from '../host.js';
3
+ import { invokeHostCallbackIsolated } from '../hostCallbackGuard.js';
3
4
  import { msg, renderMessage } from '../i18n/translate.js';
4
5
  import { askGoneFromError } from '../decideReceipt.js';
5
6
  import { appendOwnElement, guardedRead, readOwnDataNonEmptyString, readOwnDataValue } from '../ownKey.js';
@@ -343,12 +344,7 @@ function holdFits(handle, req) {
343
344
  }
344
345
  }
345
346
  function callHold(call) {
346
- 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)
@@ -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 {
@@ -13,6 +13,8 @@ import { surfaceForCurrentSession, surfaceReplayedApprovalListUnreadable } from
13
13
  import { liveCardHoldOf, noteEngineClosedApproval, settleEngineClosedApproval } from './approvalHolds.js';
14
14
  import { approvalCompleteParked } from './approvalCompleteParked.js';
15
15
  import { liveFrameCallKey } from './gateIdentity.js';
16
+ import { readPolicyDenyCause } from './policyDenyCause.js';
17
+ import { msg, renderMessage } from '../i18n/translate.js';
16
18
  import { SEMA_DENIAL_KIND_KEY, hasLedgerPositionKey } from './gateLedger.js';
17
19
  import { replayedApprovalClosesCardFrame, replayedApprovalDisposition, settledApprovalDisposition } from './replayedApproval.js';
18
20
  import { settleWithinDeadline } from '../abortableSleep.js';
@@ -64,10 +66,33 @@ export function policyDenyReason(facts) {
64
66
  function denyOutputForRender(attribution) {
65
67
  if (attribution?.settledBy !== 'policy')
66
68
  return HITL_REJECT_MESSAGE;
69
+ const head = policyDenyHeadFor(readPolicyDenyCause(attribution));
67
70
  const reason = attribution.reason;
68
71
  return reason !== undefined && reason.trim() !== ''
69
- ? `${HITL_POLICY_DENY_MESSAGE}\n${reason}`
70
- : HITL_POLICY_DENY_MESSAGE;
72
+ ? `${head}\n${reason}`
73
+ : head;
74
+ }
75
+ function policyDenyHeadFor(cause) {
76
+ const tail = msg('approval.policyDeny.tail');
77
+ switch (cause) {
78
+ case 'dont_ask':
79
+ return renderMessage(msg('approval.policyDeny.dontAsk', { tail }));
80
+ case 'deny_rule':
81
+ return renderMessage(msg('approval.policyDeny.denyRule', { tail }));
82
+ case 'engine_floor':
83
+ return renderMessage(msg('approval.policyDeny.engineFloor', { tail }));
84
+ case 'no_approval_ui':
85
+ case undefined:
86
+ return HITL_POLICY_DENY_MESSAGE;
87
+ }
88
+ }
89
+ export function denyAttributionOf(deny) {
90
+ const policyCause = readPolicyDenyCause(deny);
91
+ return {
92
+ ...(deny?.settledBy !== undefined ? { settledBy: deny.settledBy } : {}),
93
+ ...(deny?.reason !== undefined ? { reason: deny.reason } : {}),
94
+ ...(policyCause !== undefined ? { policyCause } : {}),
95
+ };
71
96
  }
72
97
  function denialKindForTranscript(attribution) {
73
98
  return ccToolDenialKindForSettledBy(attribution?.settledBy);
@@ -354,10 +379,7 @@ function settleLiveCardOutcome(ev, outcome, ctx, fromSubagent, gatedCallId) {
354
379
  invokeHostCallbackIsolated('liveHitlAskWire: onToolApprovalOutcome', () => deps.onToolApprovalOutcome?.(ev, outcome));
355
380
  }
356
381
  if (outcome.kind === 'decided' && outcome.decision === 'deny' && !fromSubagent) {
357
- const attribution = {
358
- ...(outcome.deny?.settledBy !== undefined ? { settledBy: outcome.deny.settledBy } : {}),
359
- ...(outcome.deny?.reason !== undefined ? { reason: outcome.deny.reason } : {}),
360
- };
382
+ const attribution = denyAttributionOf(outcome.deny);
361
383
  if (gatedCallId !== undefined)
362
384
  led.markDenied(gatedCallId, attribution);
363
385
  else
@@ -1,9 +1,11 @@
1
1
  import type { AgentEvent } from '@sema-agent/sdk';
2
+ import { type PolicyDenyCause } from './policyDenyCause.js';
2
3
  export declare const SEMA_COLLATERAL_ABORT_KEY = "_sema_collateral_abort";
3
4
  export declare const SEMA_DENIAL_KIND_KEY = "_sema_denial_kind";
4
5
  export interface GateDenyAttribution {
5
6
  settledBy?: 'human' | 'policy';
6
7
  reason?: string;
8
+ policyCause?: PolicyDenyCause;
7
9
  }
8
10
  export interface AskAnsweredOutput {
9
11
  type: 'ask-user-question';
@@ -1,5 +1,6 @@
1
1
  import { parkedToolEndRoleOf } from '../engineRowRef.js';
2
2
  import { inheritFrameBinding } from '../frameBinding.js';
3
+ import { readPolicyDenyCause } from './policyDenyCause.js';
3
4
  export const SEMA_COLLATERAL_ABORT_KEY = '_sema_collateral_abort';
4
5
  export const SEMA_DENIAL_KIND_KEY = '_sema_denial_kind';
5
6
  export function durableSeqOf(ev) {
@@ -27,9 +28,10 @@ function normalizeDenyAttribution(a) {
27
28
  return undefined;
28
29
  const settledBy = a.settledBy === 'human' || a.settledBy === 'policy' ? a.settledBy : undefined;
29
30
  const reason = typeof a.reason === 'string' && a.reason.trim() !== '' ? a.reason : undefined;
31
+ const policyCause = settledBy === 'policy' ? readPolicyDenyCause(a) : undefined;
30
32
  if (settledBy === undefined && reason === undefined)
31
33
  return undefined;
32
- return { ...(settledBy !== undefined ? { settledBy } : {}), ...(reason !== undefined ? { reason } : {}) };
34
+ return { ...(settledBy !== undefined ? { settledBy } : {}), ...(reason !== undefined ? { reason } : {}), ...(policyCause !== undefined ? { policyCause } : {}) };
33
35
  }
34
36
  export function createGateLedger() {
35
37
  const startedCalls = new Set();