@sema-agent/client-core 0.94.0 → 0.95.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 (255) hide show
  1. package/CHANGELOG.md +341 -0
  2. package/README.md +70 -47
  3. package/dist/adapt/arms.js +5 -6
  4. package/dist/adapt/panelTasks.js +4 -10
  5. package/dist/adapt/toolCards.js +2 -2
  6. package/dist/adapt/wireShapes.js +3 -8
  7. package/dist/adapter/activeRunSelfHeal.d.ts +8 -3
  8. package/dist/adapter/activeRunSelfHeal.js +20 -12
  9. package/dist/adapter/downstream/eventToSdkMessage.js +24 -17
  10. package/dist/adapter/downstream/terminalToSdkResult.js +11 -3
  11. package/dist/adapter/runStream.js +2 -1
  12. package/dist/adapter/types.d.ts +7 -0
  13. package/dist/adapter/types.js +15 -0
  14. package/dist/agentSession/backgroundView.js +5 -1
  15. package/dist/agentSession/engineAgentRegistryRead.js +2 -1
  16. package/dist/agentSession/engineSessionBackgroundStop.js +3 -2
  17. package/dist/agentsWireCaps.d.ts +2 -0
  18. package/dist/approvalDecidedByCapability.d.ts +0 -1
  19. package/dist/approvalDecidedByCapability.js +2 -7
  20. package/dist/approvalsStreamLiveCapability.d.ts +0 -1
  21. package/dist/approvalsStreamLiveCapability.js +2 -6
  22. package/dist/atMostOnce.d.ts +8 -0
  23. package/dist/atMostOnce.js +36 -0
  24. package/dist/attachmentSeatCapability.d.ts +0 -1
  25. package/dist/attachmentSeatCapability.js +0 -3
  26. package/dist/attachmentsWireCaps.js +11 -6
  27. package/dist/bashExitReading.d.ts +10 -0
  28. package/dist/bashExitReading.js +12 -0
  29. package/dist/callerCwdCapability.d.ts +0 -1
  30. package/dist/callerCwdCapability.js +2 -7
  31. package/dist/centerWiringCapability.d.ts +1 -3
  32. package/dist/centerWiringCapability.js +18 -21
  33. package/dist/classifierStatus.js +4 -4
  34. package/dist/cloudConfigWireCaps.js +43 -21
  35. package/dist/compensations.js +1 -1
  36. package/dist/cycleOrder.d.ts +15 -0
  37. package/dist/cycleOrder.js +45 -0
  38. package/dist/decideFailureNote.js +4 -1
  39. package/dist/decideReceipt.d.ts +2 -1
  40. package/dist/decideReceipt.js +41 -13
  41. package/dist/declared/supportFloorDeclared.d.ts +1 -0
  42. package/dist/declared/supportFloorDeclared.js +5 -0
  43. package/dist/deviceExecutorManagementCapability.d.ts +0 -1
  44. package/dist/deviceExecutorManagementCapability.js +7 -16
  45. package/dist/deviceRebind.d.ts +88 -0
  46. package/dist/deviceRebind.js +242 -0
  47. package/dist/displayUntrusted.d.ts +1 -0
  48. package/dist/displayUntrusted.js +313 -11
  49. package/dist/engineAgentAbsence.d.ts +2 -2
  50. package/dist/engineAgentPanelStore.d.ts +8 -18
  51. package/dist/engineAgentPanelStore.js +19 -537
  52. package/dist/engineCapReader.d.ts +6 -6
  53. package/dist/engineCapReader.js +30 -43
  54. package/dist/engineCapsCache.d.ts +7 -2
  55. package/dist/engineCapsCache.js +64 -26
  56. package/dist/engineCredentialRequirement.d.ts +9 -0
  57. package/dist/engineCredentialRequirement.js +23 -0
  58. package/dist/engineEnvSourcing.d.ts +53 -0
  59. package/dist/engineEnvSourcing.js +81 -0
  60. package/dist/engineErrorCodes.d.ts +14 -3
  61. package/dist/engineErrorCodes.js +31 -10
  62. package/dist/engineIdentity.js +2 -0
  63. package/dist/engineWireSdk.js +2 -2
  64. package/dist/executionLaneCapability.d.ts +2 -3
  65. package/dist/executionLaneCapability.js +18 -23
  66. package/dist/fileHistoryCaptureCapability.d.ts +0 -1
  67. package/dist/fileHistoryCaptureCapability.js +2 -6
  68. package/dist/fileHistoryLegNotice.d.ts +3 -2
  69. package/dist/fileHistoryLegNotice.js +51 -2
  70. package/dist/fleet/fleetLedger.d.ts +2 -0
  71. package/dist/fleet/fleetLedger.js +69 -52
  72. package/dist/fleet/fleetProjection.d.ts +0 -3
  73. package/dist/fleet/fleetProjection.js +9 -16
  74. package/dist/fleetAgentPanelProjection.d.ts +4 -17
  75. package/dist/fleetAgentPanelProjection.js +7 -197
  76. package/dist/fleetAgentRowLike.d.ts +16 -0
  77. package/dist/fleetAgentRowLike.js +1 -0
  78. package/dist/gateOutcome.js +30 -18
  79. package/dist/generated/sdkFactTables.d.ts +2 -0
  80. package/dist/generated/sdkFactTables.js +17 -0
  81. package/dist/generated/settingsSchemaFns.d.ts +10 -0
  82. package/dist/generated/settingsSchemaFns.js +22 -0
  83. package/dist/headlessPermissionModeWire.d.ts +1 -1
  84. package/dist/headlessPermissionModeWire.js +1 -1
  85. package/dist/headlessReconnectWire.js +49 -20
  86. package/dist/hitl/allowRuleShadow.d.ts +1 -1
  87. package/dist/hitl/allowRuleShadow.js +49 -8
  88. package/dist/hitl/approvalCompleteParked.d.ts +1 -0
  89. package/dist/hitl/approvalCompleteParked.js +14 -0
  90. package/dist/hitl/approvalEndingCause.d.ts +5 -0
  91. package/dist/hitl/approvalEndingCause.js +61 -0
  92. package/dist/hitl/approvalHolds.d.ts +12 -2
  93. package/dist/hitl/approvalHolds.js +53 -2
  94. package/dist/hitl/approvalsFeed.js +23 -11
  95. package/dist/hitl/askGateWire.d.ts +2 -1
  96. package/dist/hitl/askGateWire.js +26 -1
  97. package/dist/hitl/automaticAnswerVerdict.js +2 -2
  98. package/dist/hitl/crashConverged.js +2 -0
  99. package/dist/hitl/decisionConflict.d.ts +3 -0
  100. package/dist/hitl/decisionConflict.js +43 -0
  101. package/dist/hitl/decisionRefusal.d.ts +4 -0
  102. package/dist/hitl/decisionRefusal.js +26 -1
  103. package/dist/hitl/frameRouter.js +26 -43
  104. package/dist/hitl/gateLedger.d.ts +5 -0
  105. package/dist/hitl/gateLedger.js +21 -0
  106. package/dist/hitl/hitlBridge.d.ts +12 -1
  107. package/dist/hitl/hitlBridge.js +68 -53
  108. package/dist/hitl/hitlHostSurface.js +3 -11
  109. package/dist/hitl/livePendingAsk.d.ts +16 -6
  110. package/dist/hitl/livePendingAsk.js +36 -4
  111. package/dist/hitl/parkExpiryJudgements.d.ts +19 -0
  112. package/dist/hitl/parkExpiryJudgements.js +46 -0
  113. package/dist/hitl/parkResolver.d.ts +3 -7
  114. package/dist/hitl/parkResolver.js +50 -26
  115. package/dist/hitl/persistedRulesWire.js +5 -1
  116. package/dist/hitl/planReviewWire.d.ts +2 -2
  117. package/dist/hitl/planReviewWire.js +56 -30
  118. package/dist/hitl/replayedApproval.d.ts +8 -0
  119. package/dist/hitl/replayedApproval.js +125 -10
  120. package/dist/hitl/resumeRunningCard.d.ts +2 -0
  121. package/dist/hitl/resumeRunningCard.js +15 -4
  122. package/dist/hitl/toolApprovalWire.d.ts +24 -4
  123. package/dist/hitl/toolApprovalWire.js +115 -38
  124. package/dist/hooksWireCaps.js +38 -6
  125. package/dist/host.d.ts +5 -0
  126. package/dist/host.js +3 -1
  127. package/dist/hostCallbackGuard.d.ts +1 -0
  128. package/dist/hostCallbackGuard.js +25 -0
  129. package/dist/index.d.ts +30 -11
  130. package/dist/index.js +20 -8
  131. package/dist/interactiveInterrupt.d.ts +8 -0
  132. package/dist/interactiveInterrupt.js +54 -0
  133. package/dist/limitsWire.d.ts +5 -0
  134. package/dist/limitsWire.js +49 -3
  135. package/dist/liveModelCatalog.d.ts +95 -0
  136. package/dist/liveModelCatalog.js +297 -32
  137. package/dist/mcpEngineLeg.d.ts +25 -0
  138. package/dist/mcpEngineLeg.js +71 -15
  139. package/dist/mcpPanel.js +2 -1
  140. package/dist/mcpProbeCapability.d.ts +0 -1
  141. package/dist/mcpProbeCapability.js +2 -6
  142. package/dist/mcpReconnect.d.ts +1 -3
  143. package/dist/mcpReconnect.js +10 -5
  144. package/dist/memoryComplianceCapability.d.ts +0 -1
  145. package/dist/memoryComplianceCapability.js +2 -6
  146. package/dist/memoryOriginCapability.d.ts +0 -1
  147. package/dist/memoryOriginCapability.js +2 -6
  148. package/dist/memoryVerbsWire.d.ts +1 -1
  149. package/dist/memoryVerbsWire.js +4 -0
  150. package/dist/model/liveCatalogShape.d.ts +14 -0
  151. package/dist/model/liveCatalogShape.js +71 -0
  152. package/dist/model/modelSupplyRules.d.ts +1 -0
  153. package/dist/model/modelSupplyRules.js +30 -9
  154. package/dist/model/modelsPolicy.d.ts +21 -0
  155. package/dist/model/modelsPolicy.js +90 -0
  156. package/dist/modelIdentityResolvability.d.ts +1 -1
  157. package/dist/modelIdentityResolvability.js +5 -12
  158. package/dist/modelSwitchFallback.d.ts +69 -0
  159. package/dist/modelSwitchFallback.js +206 -0
  160. package/dist/notifications.js +12 -11
  161. package/dist/outputStyleSeatCapability.d.ts +0 -1
  162. package/dist/outputStyleSeatCapability.js +2 -7
  163. package/dist/ownKey.d.ts +6 -0
  164. package/dist/ownKey.js +48 -0
  165. package/dist/panelReduce.d.ts +114 -0
  166. package/dist/panelReduce.js +1135 -0
  167. package/dist/panelStateHolder.d.ts +17 -0
  168. package/dist/panelStateHolder.js +201 -0
  169. package/dist/peerLaneCapability.d.ts +0 -1
  170. package/dist/peerLaneCapability.js +2 -6
  171. package/dist/permissionModesCapability.d.ts +0 -1
  172. package/dist/permissionModesCapability.js +5 -10
  173. package/dist/permissionRulesWriteCapability.d.ts +0 -1
  174. package/dist/permissionRulesWriteCapability.js +2 -6
  175. package/dist/permissionsAllowGrantCapability.d.ts +0 -1
  176. package/dist/permissionsAllowGrantCapability.js +3 -9
  177. package/dist/permissionsDeclaration.d.ts +6 -0
  178. package/dist/permissionsDeclaration.js +45 -0
  179. package/dist/printToolResultFrame.js +2 -10
  180. package/dist/promptDelivery.js +0 -8
  181. package/dist/resumeRefusalCopy.d.ts +18 -1
  182. package/dist/resumeRefusalCopy.js +126 -15
  183. package/dist/rewindArchiveCapability.d.ts +2 -1
  184. package/dist/rewindArchiveCapability.js +15 -7
  185. package/dist/rewindEngineAction.d.ts +21 -0
  186. package/dist/rewindEngineAction.js +36 -0
  187. package/dist/rewindWireCaps.d.ts +2 -1
  188. package/dist/rewindWireCaps.js +1 -0
  189. package/dist/runTerminal.d.ts +0 -11
  190. package/dist/runTerminal.js +4 -27
  191. package/dist/sdkRegistryTransit.d.ts +2 -1
  192. package/dist/sdkRegistryTransit.js +1 -0
  193. package/dist/sealedKeyCapability.d.ts +0 -1
  194. package/dist/sealedKeyCapability.js +3 -9
  195. package/dist/seatContract.d.ts +54 -25
  196. package/dist/seatContract.js +394 -171
  197. package/dist/sessionIdSegment.d.ts +1 -0
  198. package/dist/sessionIdSegment.js +11 -0
  199. package/dist/sessionMemoryErase.d.ts +1 -1
  200. package/dist/sessionMemoryErase.js +6 -1
  201. package/dist/sessionMemoryStatus.js +3 -2
  202. package/dist/sessionPolicyCapability.d.ts +0 -1
  203. package/dist/sessionPolicyCapability.js +2 -6
  204. package/dist/sessionReadRedactionCapability.d.ts +0 -1
  205. package/dist/sessionReadRedactionCapability.js +2 -7
  206. package/dist/sessionSyncFileHistoryCapability.d.ts +0 -1
  207. package/dist/sessionSyncFileHistoryCapability.js +2 -6
  208. package/dist/skillToolListsCapability.d.ts +0 -1
  209. package/dist/skillToolListsCapability.js +2 -6
  210. package/dist/skillsWireCaps.d.ts +4 -0
  211. package/dist/skillsWireCaps.js +66 -1
  212. package/dist/sqlEngineCapability.d.ts +0 -1
  213. package/dist/sqlEngineCapability.js +9 -14
  214. package/dist/steerPriorityCapability.d.ts +0 -1
  215. package/dist/steerPriorityCapability.js +3 -9
  216. package/dist/storePostureCapability.d.ts +1 -1
  217. package/dist/storePostureCapability.js +16 -16
  218. package/dist/streamDrainingLegs.d.ts +6 -0
  219. package/dist/streamDrainingLegs.js +23 -0
  220. package/dist/subagent/engineCompactWire.js +13 -38
  221. package/dist/subagent/engineDelegatedPrompt.js +10 -6
  222. package/dist/subagent/engineSubagentOutput.d.ts +0 -1
  223. package/dist/subagent/engineSubagentOutput.js +5 -20
  224. package/dist/subagent/engineSubagentTail.d.ts +0 -1
  225. package/dist/subagent/engineSubagentTail.js +7 -32
  226. package/dist/subagentContentStore.js +3 -3
  227. package/dist/supportFloor.js +2 -5
  228. package/dist/terminalStatuses.d.ts +30 -0
  229. package/dist/terminalStatuses.js +67 -0
  230. package/dist/toolResult.d.ts +5 -0
  231. package/dist/toolResult.js +88 -36
  232. package/dist/types/engineState.d.ts +2 -1
  233. package/dist/usageAnalytics.d.ts +146 -0
  234. package/dist/usageAnalytics.js +311 -0
  235. package/dist/userInvokedSkillsCapability.d.ts +0 -1
  236. package/dist/userInvokedSkillsCapability.js +2 -6
  237. package/dist/webSearchBackendCapability.d.ts +0 -1
  238. package/dist/webSearchBackendCapability.js +3 -7
  239. package/dist/webSearchWireCaps.js +3 -11
  240. package/dist/wireFailureShape.d.ts +4 -0
  241. package/dist/wireFailureShape.js +42 -2
  242. package/dist/wireRefusalCopy.js +2 -18
  243. package/dist/workflowClient.js +7 -11
  244. package/dist/workflowsJournalCapability.d.ts +0 -1
  245. package/dist/workflowsJournalCapability.js +2 -6
  246. package/dist/writeProtectionCapability.d.ts +0 -1
  247. package/dist/writeProtectionCapability.js +5 -10
  248. package/docs/INTEGRATION-CLIENTS.md +1033 -26
  249. package/package.json +5 -5
  250. package/dist/engineCapsGenerationGuard.d.ts +0 -4
  251. package/dist/engineCapsGenerationGuard.js +0 -19
  252. package/dist/panelRunningHistory.d.ts +0 -22
  253. package/dist/panelRunningHistory.js +0 -82
  254. package/dist/registryConflict.d.ts +0 -3
  255. package/dist/registryConflict.js +0 -44
@@ -13,6 +13,8 @@ export function hasLedgerPositionKey(ev) {
13
13
  return (id !== undefined && id !== null) || (seq !== undefined && seq !== null);
14
14
  }
15
15
  export const PREAMBLE_APPROVALS_MAX_ENTRIES = 4096;
16
+ export const APPROVAL_SETTLED_HOWS = Object.freeze(['answered', 'interrupted', 'closed_by_engine']);
17
+ export const SETTLED_APPROVALS_MAX_ENTRIES = 4096;
16
18
  export const START_ARGS_MAX_ENTRIES = 256;
17
19
  function normalizeDenyAttribution(a) {
18
20
  if (a === undefined)
@@ -88,6 +90,7 @@ export function createGateLedger() {
88
90
  let denyStampAttribution;
89
91
  let seq;
90
92
  const preambleApprovalIds = new Set();
93
+ const settledApprovalHows = new Map();
91
94
  const liveCards = new Set();
92
95
  return {
93
96
  noteSeq(ev) {
@@ -121,6 +124,24 @@ export function createGateLedger() {
121
124
  beginStreamSegment() {
122
125
  preambleApprovalIds.clear();
123
126
  },
127
+ noteApprovalSettled(approvalId, how) {
128
+ if (typeof approvalId !== 'string' || approvalId === '')
129
+ return;
130
+ if (!APPROVAL_SETTLED_HOWS.includes(how))
131
+ return;
132
+ if (settledApprovalHows.has(approvalId))
133
+ return;
134
+ settledApprovalHows.set(approvalId, how);
135
+ while (settledApprovalHows.size > SETTLED_APPROVALS_MAX_ENTRIES) {
136
+ const oldest = settledApprovalHows.keys().next();
137
+ if (oldest.done === true)
138
+ break;
139
+ settledApprovalHows.delete(oldest.value);
140
+ }
141
+ },
142
+ settledApprovals() {
143
+ return settledApprovalHows;
144
+ },
124
145
  trackLiveCard(phaseOf, handled) {
125
146
  const entry = { phaseOf, handled };
126
147
  liveCards.add(entry);
@@ -46,7 +46,8 @@ export interface PlanReviewOutcome {
46
46
  export declare const PLAN_REVIEW_MODE_AFTER_WORDS: readonly ["default", "acceptEdits"];
47
47
  export type PlanReviewModeAfter = (typeof PLAN_REVIEW_MODE_AFTER_WORDS)[number];
48
48
  export declare function isPlanReviewModeAfter(v: string | undefined): v is PlanReviewModeAfter;
49
- export type HitlSafetyCode = 'binding_mismatch' | 'no_pending' | 'wrong_gate' | 'bad_plan_edit' | 'bad_plan_mode' | 'empty_answer';
49
+ export declare const GATE_FAILURE_CODES: readonly ["no_pending", "binding_mismatch", "wrong_gate", "bad_plan_edit", "bad_plan_mode", "empty_answer"];
50
+ export type HitlSafetyCode = (typeof GATE_FAILURE_CODES)[number];
50
51
  export type HitlFailureStage = 'fetch' | 'input' | 'card' | 'decide' | 'orchestration';
51
52
  export declare const NO_APPROVAL_CARD_PORT_REASON = "no approval card port installed (print/non-REPL mode, or host forgot installApprovalCardPort)";
52
53
  export declare const APPROVAL_CARD_PORT_KEY_MISMATCH_REASON = "no approval card port installed for the default session key, but a non-default sessionKey has one \u2014 likely a keyed-install/default-read mismatch (installApprovalCardPortFor vs the zero-arg default-key read), not a missing install";
@@ -62,9 +63,19 @@ export declare class HitlSafetyError extends Error {
62
63
  readonly code: HitlSafetyCode;
63
64
  constructor(message: string, code: HitlSafetyCode);
64
65
  }
66
+ export declare function hitlSafetyCodeOf(e: unknown): HitlSafetyCode | undefined;
65
67
  export type GateCurrentPending = Readonly<NonNullable<ApprovalStaleError['currentPending']>>;
66
68
  export declare function readDecideCurrentPending(e: unknown): GateCurrentPending | undefined;
67
69
  export declare function readWireErrorCode(e: unknown): string | undefined;
70
+ export type WireErrorCodeReading = {
71
+ readonly state: 'code';
72
+ readonly code: string;
73
+ } | {
74
+ readonly state: 'absent';
75
+ } | {
76
+ readonly state: 'unreadable';
77
+ };
78
+ export declare function readWireErrorCodeReading(e: unknown): WireErrorCodeReading;
68
79
  export declare function __setDecideTimeoutRetryBudgetForTests(ms?: number): void;
69
80
  export declare class DecideTransportRetryExhaustedError extends Error {
70
81
  readonly attempts: number;
@@ -1,9 +1,11 @@
1
1
  import { askParkForeignGateKind } from '../adapter/activeRunSelfHeal.js';
2
2
  import { eventSeq } from '../adapter/types.js';
3
3
  import { hostLog } from '../host.js';
4
+ import { invokeHostCallbackIsolated } from '../hostCallbackGuard.js';
4
5
  import { abortableSleep } from '../abortableSleep.js';
5
6
  import { readOwnDataValue } from '../ownKey.js';
6
- import { wireFailureTextsOf } from '../wireFailureShape.js';
7
+ import { THROWN_SLOT_UNREADABLE, readThrownSlot, thrownIsInstanceOf, wireFailureTextsOf } from '../wireFailureShape.js';
8
+ import { decisionConflictOf } from './decisionConflict.js';
7
9
  import { suspendedReopenOf } from './suspendedReopen.js';
8
10
  export const DEFAULT_DENY_REASON = 'The user rejected this tool use';
9
11
  const MAX_DENY_REASON_CHARS = 4096;
@@ -27,6 +29,14 @@ export const PLAN_REVIEW_MODE_AFTER_WORDS = Object.freeze(['default', 'acceptEdi
27
29
  export function isPlanReviewModeAfter(v) {
28
30
  return v !== undefined && PLAN_REVIEW_MODE_AFTER_WORDS.includes(v);
29
31
  }
32
+ export const GATE_FAILURE_CODES = [
33
+ 'no_pending',
34
+ 'binding_mismatch',
35
+ 'wrong_gate',
36
+ 'bad_plan_edit',
37
+ 'bad_plan_mode',
38
+ 'empty_answer',
39
+ ];
30
40
  export const NO_APPROVAL_CARD_PORT_REASON = 'no approval card port installed (print/non-REPL mode, or host forgot installApprovalCardPort)';
31
41
  export const APPROVAL_CARD_PORT_KEY_MISMATCH_REASON = 'no approval card port installed for the default session key, but a non-default sessionKey has one — likely a keyed-install/default-read mismatch (installApprovalCardPortFor vs the zero-arg default-key read), not a missing install';
32
42
  export const NO_QUESTION_OVERLAY_REASON = 'no question overlay mounted (print/non-REPL mode)';
@@ -41,28 +51,46 @@ export class HitlSafetyError extends Error {
41
51
  this.name = 'HitlSafetyError';
42
52
  }
43
53
  }
54
+ export function hitlSafetyCodeOf(e) {
55
+ if (!thrownIsInstanceOf(e, HitlSafetyError))
56
+ return undefined;
57
+ const raw = readThrownSlot(e, 'code');
58
+ return typeof raw === 'string' && GATE_FAILURE_CODES.includes(raw) ? raw : undefined;
59
+ }
44
60
  const _gateCurrentPendingReadonlyPin = true;
45
61
  void _gateCurrentPendingReadonlyPin;
46
62
  export function readDecideCurrentPending(e) {
47
- const raw = e?.currentPending;
63
+ if (e === null || e === undefined)
64
+ return undefined;
65
+ const raw = readThrownSlot(e, 'currentPending');
48
66
  if (typeof raw !== 'object' || raw === null)
49
67
  return undefined;
50
- const o = raw;
51
- if (typeof o.toolName !== 'string' || o.toolName.length === 0)
68
+ const toolName = readThrownSlot(raw, 'toolName');
69
+ const boundCallId = readThrownSlot(raw, 'boundCallId');
70
+ const boundInputHash = readThrownSlot(raw, 'boundInputHash');
71
+ if (typeof toolName !== 'string' || toolName.length === 0)
52
72
  return undefined;
53
- if (typeof o.boundCallId !== 'string' || o.boundCallId.length === 0)
73
+ if (typeof boundCallId !== 'string' || boundCallId.length === 0)
54
74
  return undefined;
55
75
  return {
56
- toolName: o.toolName,
57
- boundCallId: o.boundCallId,
58
- ...(typeof o.boundInputHash === 'string' && o.boundInputHash.length > 0
59
- ? { boundInputHash: o.boundInputHash }
76
+ toolName,
77
+ boundCallId,
78
+ ...(typeof boundInputHash === 'string' && boundInputHash.length > 0
79
+ ? { boundInputHash }
60
80
  : {}),
61
81
  };
62
82
  }
63
83
  export function readWireErrorCode(e) {
64
- const raw = e?.errorCode;
65
- return typeof raw === 'string' && raw.length > 0 ? raw : undefined;
84
+ const reading = readWireErrorCodeReading(e);
85
+ return reading.state === 'code' ? reading.code : undefined;
86
+ }
87
+ export function readWireErrorCodeReading(e) {
88
+ if (e === null || e === undefined)
89
+ return { state: 'absent' };
90
+ const raw = readThrownSlot(e, 'errorCode');
91
+ if (raw === THROWN_SLOT_UNREADABLE)
92
+ return { state: 'unreadable' };
93
+ return typeof raw === 'string' && raw.length > 0 ? { state: 'code', code: raw } : { state: 'absent' };
66
94
  }
67
95
  const DECIDE_TRANSPORT_RETRY_BACKOFF_MS = 750;
68
96
  const DECIDE_RETRY_BACKOFF_MAX_MS = 5_000;
@@ -80,10 +108,9 @@ function decideTimeoutRetryBudgetMs() {
80
108
  function isDecideAttemptTimeout(e, depth = 0) {
81
109
  if (depth > 3 || e === null || typeof e !== 'object')
82
110
  return false;
83
- const o = e;
84
- if (o.name === 'TimeoutError')
111
+ if (readThrownSlot(e, 'name') === 'TimeoutError')
85
112
  return true;
86
- return isDecideAttemptTimeout(o.cause, depth + 1);
113
+ return isDecideAttemptTimeout(readThrownSlot(e, 'cause'), depth + 1);
87
114
  }
88
115
  const TRANSIENT_NETWORK_CODES = new Set([
89
116
  'ECONNREFUSED', 'ECONNRESET', 'ETIMEDOUT', 'EPIPE', 'EAI_AGAIN',
@@ -93,18 +120,21 @@ const TRANSIENT_NETWORK_CODES = new Set([
93
120
  function isTransientDecideTransportFailure(e, depth = 0) {
94
121
  if (depth > 3 || e === null || typeof e !== 'object')
95
122
  return false;
96
- if (e instanceof HitlSafetyError)
123
+ if (thrownIsInstanceOf(e, HitlSafetyError))
97
124
  return false;
98
- const o = e;
99
- if (typeof o.status === 'number')
125
+ const status = readThrownSlot(e, 'status');
126
+ if (status === THROWN_SLOT_UNREADABLE || typeof status === 'number')
100
127
  return false;
101
- if (o.name === 'TimeoutError' || o.name === 'AbortError')
128
+ const name = readThrownSlot(e, 'name');
129
+ if (name === 'TimeoutError' || name === 'AbortError')
102
130
  return true;
103
- if (typeof o.code === 'string' && TRANSIENT_NETWORK_CODES.has(o.code))
131
+ const code = readThrownSlot(e, 'code');
132
+ if (typeof code === 'string' && TRANSIENT_NETWORK_CODES.has(code))
104
133
  return true;
105
- if (typeof o.message === 'string' && o.message.toLowerCase().includes('fetch failed'))
134
+ const message = readThrownSlot(e, 'message');
135
+ if (typeof message === 'string' && message.toLowerCase().includes('fetch failed'))
106
136
  return true;
107
- return isTransientDecideTransportFailure(o.cause, depth + 1);
137
+ return isTransientDecideTransportFailure(readThrownSlot(e, 'cause'), depth + 1);
108
138
  }
109
139
  export class DecideTransportRetryExhaustedError extends Error {
110
140
  attempts;
@@ -149,7 +179,7 @@ class DecideSpan {
149
179
  }
150
180
  catch (e) {
151
181
  this.ok = false;
152
- this.retryExhausted = e instanceof DecideTransportRetryExhaustedError;
182
+ this.retryExhausted = thrownIsInstanceOf(e, DecideTransportRetryExhaustedError);
153
183
  throw e;
154
184
  }
155
185
  finally {
@@ -175,32 +205,13 @@ class DecideSpan {
175
205
  notifyDecideObserver(this.observer, Object.freeze({ ...this.identity, phase: 'end', ok: this.ok, attempts: this.attempts, retryExhausted: this.retryExhausted }));
176
206
  }
177
207
  }
178
- function reportObserverFault(phase, what, e) {
179
- try {
180
- hostLog('debug', `hitlBridge: onDecideOperation(${phase}) ${what}: ${String(e).slice(0, 160)}`);
181
- return true;
182
- }
183
- catch {
184
- return false;
185
- }
186
- }
187
208
  function wireOptsOf(opts) {
188
209
  if (opts === undefined || opts.operation === undefined)
189
210
  return opts;
190
211
  return opts.signal !== undefined ? { signal: opts.signal } : undefined;
191
212
  }
192
213
  function notifyDecideObserver(observer, ev) {
193
- try {
194
- const out = observer(ev);
195
- if (out && typeof out.then === 'function') {
196
- void Promise.resolve(out).then(undefined, (e) => {
197
- reportObserverFault(ev.phase, 'rejected', e);
198
- });
199
- }
200
- }
201
- catch (e) {
202
- reportObserverFault(ev.phase, 'threw', e);
203
- }
214
+ invokeHostCallbackIsolated(`hitlBridge: onDecideOperation(${ev.phase})`, () => observer(ev));
204
215
  }
205
216
  const ANY_TOOL_FAMILY = () => true;
206
217
  export async function findPendingForTask(client, taskId, matches, opts, callId, identityAccepts = (r) => matches(typeof r.toolName === 'string' ? r.toolName : undefined)) {
@@ -374,7 +385,7 @@ export class HitlBridge {
374
385
  return r;
375
386
  }
376
387
  catch (e) {
377
- retryExhausted = e instanceof DecideTransportRetryExhaustedError;
388
+ retryExhausted = thrownIsInstanceOf(e, DecideTransportRetryExhaustedError);
378
389
  throw e;
379
390
  }
380
391
  finally {
@@ -407,9 +418,12 @@ export class HitlBridge {
407
418
  return r;
408
419
  }
409
420
  catch (e) {
410
- if (isBindingMismatch(e)) {
421
+ const binding = bindingMismatchReading(e);
422
+ if (binding === 'mismatch') {
411
423
  throw new HitlSafetyError('approval_binding_mismatch — the pending action changed under the human; refetch + re-present', 'binding_mismatch');
412
424
  }
425
+ if (binding === 'unreadable')
426
+ throw e;
413
427
  if (!isTransientDecideTransportFailure(e) || callerAborted())
414
428
  throw e;
415
429
  if (isDecideAttemptTimeout(e)) {
@@ -479,16 +493,17 @@ function marshalAnswer(a) {
479
493
  entry.note = a.note;
480
494
  return entry;
481
495
  }
482
- function isBindingMismatch(e) {
496
+ function bindingMismatchReading(e) {
483
497
  if (!e || typeof e !== 'object')
484
- return false;
485
- const o = e;
486
- const code = o.errorCode;
487
- if (code === 'approval_binding_mismatch')
488
- return true;
489
- if (typeof o.name === 'string' && o.name === 'ApprovalBindingMismatchError')
490
- return true;
491
- return false;
498
+ return 'not';
499
+ const code = readWireErrorCodeReading(e);
500
+ const name = readThrownSlot(e, 'name');
501
+ const family = (code.state === 'code' && code.code === 'approval_binding_mismatch') || name === 'ApprovalBindingMismatchError';
502
+ if (family)
503
+ return decisionConflictOf(e) !== 'answer_invalid' ? 'mismatch' : 'not';
504
+ if (code.state === 'unreadable')
505
+ return 'unreadable';
506
+ return 'not';
492
507
  }
493
508
  export function backendDeny(reason) {
494
509
  return {
@@ -2,7 +2,7 @@ import { createSessionSlot, DEFAULT_SESSION_KEY } from '../sessionSlot.js';
2
2
  import { hostLog } from '../host.js';
3
3
  import { unrefTimer } from '../unrefTimer.js';
4
4
  import { decideFailureNote } from '../decideFailureNote.js';
5
- import { HitlSafetyError } from './hitlBridge.js';
5
+ import { decisionRefusalSaysAskGone } from './decisionRefusal.js';
6
6
  const hostSurfaceByKey = createSessionSlot();
7
7
  const hostSurfaceMissesByKey = new Map();
8
8
  export function installHitlHostSurface(surface) {
@@ -133,14 +133,6 @@ const RULE_NOT_SENT_REJECTED_TIMEOUT_MS = 10_000;
133
133
  export function surfaceRuleArmRejected(why) {
134
134
  surfaceSelfClearingWarn(RULE_NOT_SENT_REJECTED_KEY, ruleNotSentRejectedText(why), RULE_NOT_SENT_REJECTED_TIMEOUT_MS);
135
135
  }
136
- function isNoPendingError(e) {
137
- if (e instanceof HitlSafetyError)
138
- return e.code === 'no_pending';
139
- if (typeof e !== 'object' || e === null || !('code' in e))
140
- return false;
141
- const code = e.code;
142
- return typeof code === 'string' && code === 'no_pending';
143
- }
144
136
  export function observeCancelByDeny(settle, taskId) {
145
137
  let timer;
146
138
  const budget = new Promise((_, reject) => {
@@ -152,8 +144,8 @@ export function observeCancelByDeny(settle, taskId) {
152
144
  hostLog('debug', `[hitl-cancel-deny] cancel-by-deny settled for run ${taskId} (session unlocked)`);
153
145
  })
154
146
  .catch((e) => {
155
- if (isNoPendingError(e)) {
156
- hostLog('debug', `[hitl-cancel-deny] cancel-by-deny no_pending for run ${taskId} (benign — already resolved)`);
147
+ if (decisionRefusalSaysAskGone(e)) {
148
+ hostLog('debug', `[hitl-cancel-deny] cancel-by-deny found the question no longer pending for run ${taskId} (benign — settled elsewhere, parked or gone)`);
157
149
  return;
158
150
  }
159
151
  const rowNote = decideFailureNote(e, 'deny');
@@ -22,16 +22,26 @@ export type LivePendingReading = {
22
22
  dropped: number;
23
23
  };
24
24
  export declare function readLivePendingRows(body: unknown): LivePendingReading;
25
- export interface SuspendedAskFilter {
26
- sessionId?: string;
27
- }
28
- export declare function suspendedSubagentAsks(snapshot: ApprovalsFeedEmission | null | undefined, filter?: SuspendedAskFilter): LivePendingAskView[];
25
+ export type SuspendedAskFilter = {
26
+ readonly sessionId: string;
27
+ readonly allSessions?: never;
28
+ readonly identityPending?: never;
29
+ } | {
30
+ readonly allSessions: true;
31
+ readonly sessionId?: never;
32
+ readonly identityPending?: never;
33
+ } | {
34
+ readonly identityPending: true;
35
+ readonly sessionId?: never;
36
+ readonly allSessions?: never;
37
+ };
38
+ export declare function suspendedSubagentAsks(snapshot: ApprovalsFeedEmission | null | undefined, filter: SuspendedAskFilter): LivePendingAskView[];
29
39
  export interface ApprovalsAwaitingDecisionCount {
30
40
  durable: number | null;
31
41
  live: number | null;
32
42
  suspendedSubagent: number | null;
33
43
  }
34
- export declare function countApprovalsAwaitingDecision(snapshot: ApprovalsFeedEmission | null | undefined, filter?: SuspendedAskFilter): ApprovalsAwaitingDecisionCount;
44
+ export declare function countApprovalsAwaitingDecision(snapshot: ApprovalsFeedEmission | null | undefined, filter: SuspendedAskFilter): ApprovalsAwaitingDecisionCount;
35
45
  export declare function livePendingRowToApprovalFrame(row: LivePendingAskView): ToolApprovalFrame;
36
46
  export declare function surfaceSuspendedAskAndRespond(row: LivePendingAskView, respond: RespondToolApprovalFn, signal?: AbortSignal, lane?: ToolApprovalFrameLaneOpts): Promise<ToolApprovalFrameOutcome>;
37
47
  export interface SuspendedAskDelta {
@@ -45,4 +55,4 @@ export interface SuspendedAskTracker {
45
55
  requeue(approvalId: string): void;
46
56
  noteDecided(approvalId: string): void;
47
57
  }
48
- export declare function createSuspendedAskTracker(filter?: SuspendedAskFilter): SuspendedAskTracker;
58
+ export declare function createSuspendedAskTracker(filter: SuspendedAskFilter): SuspendedAskTracker;
@@ -1,3 +1,4 @@
1
+ import { THROWN_SLOT_UNREADABLE, readThrownSlot } from '../wireFailureShape.js';
1
2
  import { isToolApprovalFrame, surfaceToolApprovalFrameAndRespond, } from './toolApprovalWire.js';
2
3
  function nonEmptyString(v) {
3
4
  return typeof v === 'string' && v !== '';
@@ -69,20 +70,48 @@ export function readLivePendingRows(body) {
69
70
  return { kind: 'malformed' };
70
71
  return { kind: 'present', rows, dropped };
71
72
  }
72
- export function suspendedSubagentAsks(snapshot, filter) {
73
+ const IDENTITY_PENDING_SCOPE = Object.freeze({ kind: 'identity_pending' });
74
+ function suspendedAskScopeOf(filter) {
75
+ if (typeof filter !== 'object' || filter === null)
76
+ return IDENTITY_PENDING_SCOPE;
77
+ const sessionId = readThrownSlot(filter, 'sessionId', true);
78
+ const allSessions = readThrownSlot(filter, 'allSessions', true);
79
+ const identityPending = readThrownSlot(filter, 'identityPending', true);
80
+ if (sessionId === THROWN_SLOT_UNREADABLE || allSessions === THROWN_SLOT_UNREADABLE || identityPending === THROWN_SLOT_UNREADABLE)
81
+ return IDENTITY_PENDING_SCOPE;
82
+ const sessionOk = typeof sessionId === 'string' && sessionId !== '';
83
+ const allOk = allSessions === true;
84
+ const pendingOk = identityPending === true;
85
+ if ((sessionId !== undefined && !sessionOk) || (allSessions !== undefined && !allOk) || (identityPending !== undefined && !pendingOk))
86
+ return IDENTITY_PENDING_SCOPE;
87
+ if (sessionOk && !allOk && !pendingOk)
88
+ return { kind: 'session', sessionId };
89
+ if (allOk && !sessionOk && !pendingOk)
90
+ return { kind: 'all' };
91
+ return IDENTITY_PENDING_SCOPE;
92
+ }
93
+ function subagentAsksIn(snapshot, scope) {
94
+ if (scope.kind === 'identity_pending')
95
+ return [];
73
96
  if (snapshot?.kind === 'unknown')
74
97
  return [];
75
98
  const rows = snapshot?.livePending;
76
99
  if (!Array.isArray(rows))
77
100
  return [];
78
- return rows.filter(r => r.fromSubagent === true && (filter?.sessionId === undefined || r.sessionId === filter.sessionId));
101
+ return rows.filter(r => r.fromSubagent === true && (scope.kind === 'all' || r.sessionId === scope.sessionId));
102
+ }
103
+ export function suspendedSubagentAsks(snapshot, filter) {
104
+ return subagentAsksIn(snapshot, suspendedAskScopeOf(filter));
79
105
  }
80
106
  export function countApprovalsAwaitingDecision(snapshot, filter) {
107
+ const scope = suspendedAskScopeOf(filter);
108
+ if (scope.kind === 'identity_pending')
109
+ return { durable: null, live: null, suspendedSubagent: null };
81
110
  if (snapshot === null || snapshot === undefined)
82
111
  return { durable: null, live: null, suspendedSubagent: null };
83
112
  if (snapshot.kind === 'unknown')
84
113
  return { durable: null, live: null, suspendedSubagent: null };
85
- const bySession = (rows) => filter?.sessionId === undefined ? [...rows] : rows.filter(r => r.sessionId === filter.sessionId);
114
+ const bySession = (rows) => scope.kind === 'session' ? rows.filter(r => r.sessionId === scope.sessionId) : [...rows];
86
115
  const durable = (snapshot.pendingDropped ?? 0) > 0 ? null : Array.isArray(snapshot.pending) ? bySession(snapshot.pending).length : null;
87
116
  if (!Array.isArray(snapshot.livePending))
88
117
  return { durable, live: null, suspendedSubagent: null };
@@ -113,6 +142,7 @@ export function surfaceSuspendedAskAndRespond(row, respond, signal, lane) {
113
142
  }
114
143
  const TRACKER_UNSEEN_CLAIMS_MAX = 512;
115
144
  export function createSuspendedAskTracker(filter) {
145
+ const scope = suspendedAskScopeOf(filter);
116
146
  const shown = new Set();
117
147
  const shownWithFrame = new Set();
118
148
  const claimed = new Map();
@@ -137,7 +167,9 @@ export function createSuspendedAskTracker(filter) {
137
167
  ingest(snapshot) {
138
168
  if (snapshot?.kind === 'unknown')
139
169
  return { appeared: [], gone: [], upgraded: [] };
140
- const rows = suspendedSubagentAsks(snapshot, filter);
170
+ if (scope.kind === 'identity_pending')
171
+ return { appeared: [], gone: [], upgraded: [] };
172
+ const rows = subagentAsksIn(snapshot, scope);
141
173
  const present = new Set(rows.map(r => r.approvalId));
142
174
  const appeared = [];
143
175
  const upgraded = [];
@@ -0,0 +1,19 @@
1
+ export type ApprovalCompleteDisposition = 'live-expired-parked' | 'live-expired-retract' | 'settled' | null;
2
+ export declare function classifyApprovalCompleteFrame(frame: unknown): ApprovalCompleteDisposition;
3
+ export type ParkRowDeadlineState = {
4
+ kind: 'none';
5
+ } | {
6
+ kind: 'pending';
7
+ deadlineMs: number;
8
+ remainingMs: number;
9
+ } | {
10
+ kind: 'past';
11
+ deadlineMs: number;
12
+ remainingMs: number;
13
+ };
14
+ export declare function parkRowDeadlineState(row: unknown, nowMs: number): ParkRowDeadlineState;
15
+ export declare function lateDecideRoute(o: {
16
+ windowClosed: boolean;
17
+ durableRowFound: boolean;
18
+ }): 'decide' | 'respond';
19
+ export declare function runReapedByDeadline(client: unknown, taskId: string): Promise<boolean>;
@@ -0,0 +1,46 @@
1
+ import { APPROVAL_EXPIRED } from '../engineErrorCodes.js';
2
+ import { approvalCompleteParked } from './approvalCompleteParked.js';
3
+ export function classifyApprovalCompleteFrame(frame) {
4
+ if (typeof frame !== 'object' || frame === null)
5
+ return null;
6
+ const f = frame;
7
+ if (f.type !== 'tool_approval_complete')
8
+ return null;
9
+ const outcome = f.outcome;
10
+ if (outcome === 'allowed' || outcome === 'denied')
11
+ return 'settled';
12
+ if (outcome !== 'expired')
13
+ return null;
14
+ return approvalCompleteParked(frame) ? 'live-expired-parked' : 'live-expired-retract';
15
+ }
16
+ const PARK_DEADLINE_MAX_SANE_MS = 24 * 60 * 60 * 1000;
17
+ export function parkRowDeadlineState(row, nowMs) {
18
+ if (typeof row !== 'object' || row === null)
19
+ return { kind: 'none' };
20
+ const raw = row.deadline;
21
+ if (typeof raw !== 'number' || !Number.isFinite(raw) || raw <= 0)
22
+ return { kind: 'none' };
23
+ const remainingMs = raw - nowMs;
24
+ if (remainingMs > PARK_DEADLINE_MAX_SANE_MS)
25
+ return { kind: 'none' };
26
+ return remainingMs > 0
27
+ ? { kind: 'pending', deadlineMs: raw, remainingMs }
28
+ : { kind: 'past', deadlineMs: raw, remainingMs };
29
+ }
30
+ export function lateDecideRoute(o) {
31
+ if (!o.windowClosed)
32
+ return 'respond';
33
+ return o.durableRowFound ? 'decide' : 'respond';
34
+ }
35
+ export async function runReapedByDeadline(client, taskId) {
36
+ try {
37
+ const runs = client?.runs;
38
+ if (typeof runs?.get !== 'function')
39
+ return false;
40
+ const rec = (await runs.get(taskId));
41
+ return rec?.errorCode === APPROVAL_EXPIRED;
42
+ }
43
+ catch {
44
+ return false;
45
+ }
46
+ }
@@ -1,7 +1,6 @@
1
1
  import type { AgentEvent } from '@sema-agent/sdk';
2
- import { type GateCurrentPending, type HitlFailureStage } from './hitlBridge.js';
2
+ import { type GateCurrentPending, type HitlFailureStage, type HitlSafetyCode } from './hitlBridge.js';
3
3
  import { type QuestionAnswer } from '../liveQuestionStore.js';
4
- import { type FsApprovalOutcome } from './toolApprovalWire.js';
5
4
  import type { AskAnsweredOutput, GateLedger } from './gateLedger.js';
6
5
  import { type AskGateWireDeps, type GatePark } from './frameRouter.js';
7
6
  import { type DecideReceiptView } from '../decideReceipt.js';
@@ -13,8 +12,7 @@ export interface HopBudget {
13
12
  }
14
13
  export declare function nextHopBudget(prev: HopBudget | undefined, round: HopRound): HopBudget;
15
14
  export declare const MAX_TOTAL_PARKS = 64;
16
- export declare const GATE_FAILURE_CODES: readonly ["no_pending", "binding_mismatch", "wrong_gate", "bad_plan_edit", "bad_plan_mode", "empty_answer"];
17
- export type GateFailureCode = (typeof GATE_FAILURE_CODES)[number];
15
+ export type GateFailureCode = HitlSafetyCode;
18
16
  export type GateOutcome = {
19
17
  kind: 'decided';
20
18
  gatedCallId?: string | undefined;
@@ -35,9 +33,7 @@ export type GateOutcome = {
35
33
  currentPending?: GateCurrentPending | undefined;
36
34
  };
37
35
  export declare function isAlreadyResolvedGateReason(reason: unknown): boolean;
38
- export declare function isAlreadyResolvedFailure(outcome: Extract<GateOutcome | FsApprovalOutcome, {
39
- kind: 'failed';
40
- }>): boolean;
36
+ export declare function isAlreadyResolvedFailure(failure: unknown): boolean;
41
37
  export declare function isGateStandingErrorCode(code: string | null | undefined, retriable?: boolean): boolean;
42
38
  export declare function isCodeClassifiedGateFailure(code: string | null | undefined, retriable?: boolean): boolean;
43
39
  export declare function toAnsweredOutput(questions: unknown[], answer: QuestionAnswer): AskAnsweredOutput;