@sema-agent/client-core 0.93.1 → 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 (321) hide show
  1. package/CHANGELOG.md +554 -0
  2. package/README.md +89 -55
  3. package/dist/adapt/arms.js +13 -11
  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 +13 -6
  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 +5 -3
  17. package/dist/agentsWireCaps.d.ts +17 -0
  18. package/dist/agentsWireCaps.js +111 -1
  19. package/dist/approvalDecidedByCapability.d.ts +0 -1
  20. package/dist/approvalDecidedByCapability.js +2 -7
  21. package/dist/approvalReachWire.d.ts +18 -0
  22. package/dist/approvalReachWire.js +58 -0
  23. package/dist/approvalsStreamLiveCapability.d.ts +0 -1
  24. package/dist/approvalsStreamLiveCapability.js +15 -14
  25. package/dist/atMostOnce.d.ts +8 -0
  26. package/dist/atMostOnce.js +36 -0
  27. package/dist/attachmentSeatCapability.d.ts +0 -1
  28. package/dist/attachmentSeatCapability.js +0 -3
  29. package/dist/attachmentsWireCaps.js +11 -6
  30. package/dist/bashExitReading.d.ts +10 -0
  31. package/dist/bashExitReading.js +12 -0
  32. package/dist/callerCwdCapability.d.ts +15 -0
  33. package/dist/callerCwdCapability.js +42 -0
  34. package/dist/centerWiringCapability.d.ts +1 -3
  35. package/dist/centerWiringCapability.js +18 -21
  36. package/dist/classifierStatus.js +4 -4
  37. package/dist/cloudConfigWireCaps.js +43 -21
  38. package/dist/compensations.js +1 -1
  39. package/dist/controlRouter.js +3 -10
  40. package/dist/coreValuePorts.d.ts +64 -1
  41. package/dist/coreValuePorts.js +30 -0
  42. package/dist/cycleOrder.d.ts +15 -0
  43. package/dist/cycleOrder.js +45 -0
  44. package/dist/decideFailureNote.js +4 -1
  45. package/dist/decideReceipt.d.ts +2 -1
  46. package/dist/decideReceipt.js +41 -13
  47. package/dist/declared/supportFloorDeclared.d.ts +1 -0
  48. package/dist/declared/supportFloorDeclared.js +5 -0
  49. package/dist/detachWire.d.ts +1 -4
  50. package/dist/detachWire.js +1 -1
  51. package/dist/deviceExecutorManagementCapability.d.ts +0 -1
  52. package/dist/deviceExecutorManagementCapability.js +36 -40
  53. package/dist/deviceFlowPolling.d.ts +5 -0
  54. package/dist/deviceFlowPolling.js +28 -0
  55. package/dist/deviceRebind.d.ts +88 -0
  56. package/dist/deviceRebind.js +242 -0
  57. package/dist/displayUntrusted.d.ts +1 -0
  58. package/dist/displayUntrusted.js +963 -30
  59. package/dist/engineAgentAbsence.d.ts +2 -2
  60. package/dist/engineAgentPanelStore.d.ts +8 -18
  61. package/dist/engineAgentPanelStore.js +19 -537
  62. package/dist/engineCapReader.d.ts +6 -6
  63. package/dist/engineCapReader.js +30 -43
  64. package/dist/engineCapsCache.d.ts +7 -2
  65. package/dist/engineCapsCache.js +64 -26
  66. package/dist/engineCredentialRequirement.d.ts +9 -0
  67. package/dist/engineCredentialRequirement.js +23 -0
  68. package/dist/engineEnvSourcing.d.ts +53 -0
  69. package/dist/engineEnvSourcing.js +81 -0
  70. package/dist/engineErrorCodes.d.ts +19 -4
  71. package/dist/engineErrorCodes.js +39 -21
  72. package/dist/engineIdentity.js +2 -0
  73. package/dist/engineNoticeCodes.d.ts +22 -2
  74. package/dist/engineNoticeCodes.js +73 -6
  75. package/dist/engineRefusedToolName.d.ts +1 -0
  76. package/dist/engineRefusedToolName.js +8 -0
  77. package/dist/engineWireSdk.js +2 -2
  78. package/dist/executionLaneCapability.d.ts +2 -3
  79. package/dist/executionLaneCapability.js +28 -28
  80. package/dist/fileHistoryCaptureCapability.d.ts +0 -1
  81. package/dist/fileHistoryCaptureCapability.js +13 -12
  82. package/dist/fileHistoryLegNotice.d.ts +14 -2
  83. package/dist/fileHistoryLegNotice.js +101 -15
  84. package/dist/fleet/fleetLedger.d.ts +2 -0
  85. package/dist/fleet/fleetLedger.js +74 -52
  86. package/dist/fleet/fleetProjection.d.ts +0 -3
  87. package/dist/fleet/fleetProjection.js +9 -16
  88. package/dist/fleetAgentPanelProjection.d.ts +4 -17
  89. package/dist/fleetAgentPanelProjection.js +7 -197
  90. package/dist/fleetAgentRowLike.d.ts +16 -0
  91. package/dist/fleetAgentRowLike.js +1 -0
  92. package/dist/gateOutcome.d.ts +2 -1
  93. package/dist/gateOutcome.js +33 -18
  94. package/dist/gateVocabulary.js +1 -1
  95. package/dist/generated/engineAskFaceTables.d.ts +3 -0
  96. package/dist/generated/engineAskFaceTables.js +12 -0
  97. package/dist/generated/engineFactTables.d.ts +4 -2
  98. package/dist/generated/engineFactTables.js +13 -0
  99. package/dist/generated/engineNoticeTables.d.ts +5 -0
  100. package/dist/generated/engineNoticeTables.js +7 -0
  101. package/dist/generated/sdkFactTables.d.ts +5 -0
  102. package/dist/generated/sdkFactTables.js +34 -0
  103. package/dist/generated/settingsSchemaFns.d.ts +10 -0
  104. package/dist/generated/settingsSchemaFns.js +22 -0
  105. package/dist/generated/settingsSchemaTables.d.ts +3 -0
  106. package/dist/generated/settingsSchemaTables.js +3 -0
  107. package/dist/headlessPermissionModeWire.d.ts +2 -2
  108. package/dist/headlessPermissionModeWire.js +11 -21
  109. package/dist/headlessReconnectWire.js +49 -20
  110. package/dist/hitl/allowRuleShadow.d.ts +1 -1
  111. package/dist/hitl/allowRuleShadow.js +49 -8
  112. package/dist/hitl/approvalCompleteParked.d.ts +1 -0
  113. package/dist/hitl/approvalCompleteParked.js +14 -0
  114. package/dist/hitl/approvalEndingCause.d.ts +5 -0
  115. package/dist/hitl/approvalEndingCause.js +61 -0
  116. package/dist/hitl/approvalHolds.d.ts +46 -0
  117. package/dist/hitl/approvalHolds.js +140 -0
  118. package/dist/hitl/approvalOutcomeNote.js +2 -1
  119. package/dist/hitl/approvalResolution.js +9 -1
  120. package/dist/hitl/approvalsFeed.js +23 -6
  121. package/dist/hitl/askGateWire.d.ts +2 -1
  122. package/dist/hitl/askGateWire.js +29 -1
  123. package/dist/hitl/automaticAnswerVerdict.d.ts +8 -2
  124. package/dist/hitl/automaticAnswerVerdict.js +71 -23
  125. package/dist/hitl/crashConverged.js +2 -0
  126. package/dist/hitl/decisionConflict.d.ts +3 -0
  127. package/dist/hitl/decisionConflict.js +43 -0
  128. package/dist/hitl/decisionRefusal.d.ts +23 -0
  129. package/dist/hitl/decisionRefusal.js +88 -0
  130. package/dist/hitl/frameRouter.d.ts +10 -0
  131. package/dist/hitl/frameRouter.js +71 -32
  132. package/dist/hitl/gateLedger.d.ts +8 -0
  133. package/dist/hitl/gateLedger.js +38 -0
  134. package/dist/hitl/hitlBridge.d.ts +14 -3
  135. package/dist/hitl/hitlBridge.js +75 -62
  136. package/dist/hitl/hitlHostSurface.d.ts +3 -0
  137. package/dist/hitl/hitlHostSurface.js +17 -15
  138. package/dist/hitl/livePendingAsk.d.ts +16 -6
  139. package/dist/hitl/livePendingAsk.js +36 -4
  140. package/dist/hitl/localAllowRule.js +2 -1
  141. package/dist/hitl/noAllowCause.d.ts +9 -0
  142. package/dist/hitl/noAllowCause.js +26 -0
  143. package/dist/hitl/parkExpiryJudgements.d.ts +19 -0
  144. package/dist/hitl/parkExpiryJudgements.js +46 -0
  145. package/dist/hitl/parkResolver.d.ts +3 -7
  146. package/dist/hitl/parkResolver.js +55 -28
  147. package/dist/hitl/parkRowBirthWait.js +2 -1
  148. package/dist/hitl/persistedRulesWire.d.ts +6 -1
  149. package/dist/hitl/persistedRulesWire.js +16 -4
  150. package/dist/hitl/planReviewWire.d.ts +2 -3
  151. package/dist/hitl/planReviewWire.js +86 -39
  152. package/dist/hitl/replayedApproval.d.ts +8 -0
  153. package/dist/hitl/replayedApproval.js +125 -10
  154. package/dist/hitl/resumeRunningCard.d.ts +2 -0
  155. package/dist/hitl/resumeRunningCard.js +15 -4
  156. package/dist/hitl/sessionPolicyDeliverable.d.ts +1 -1
  157. package/dist/hitl/sessionPolicyDeliverable.js +3 -8
  158. package/dist/hitl/sessionPolicyWire.js +1 -1
  159. package/dist/hitl/toolApprovalWire.d.ts +50 -5
  160. package/dist/hitl/toolApprovalWire.js +368 -56
  161. package/dist/hooksWireCaps.js +38 -6
  162. package/dist/host.d.ts +5 -0
  163. package/dist/host.js +3 -1
  164. package/dist/hostCallbackGuard.d.ts +1 -0
  165. package/dist/hostCallbackGuard.js +25 -0
  166. package/dist/humanTurnRead.d.ts +15 -1
  167. package/dist/humanTurnRead.js +28 -2
  168. package/dist/index.d.ts +45 -14
  169. package/dist/index.js +33 -12
  170. package/dist/interactiveInterrupt.d.ts +8 -0
  171. package/dist/interactiveInterrupt.js +54 -0
  172. package/dist/limitsWire.d.ts +5 -1
  173. package/dist/limitsWire.js +51 -13
  174. package/dist/liveModelCatalog.d.ts +109 -0
  175. package/dist/liveModelCatalog.js +344 -18
  176. package/dist/mcpEngineLeg.d.ts +25 -0
  177. package/dist/mcpEngineLeg.js +71 -15
  178. package/dist/mcpPanel.js +2 -1
  179. package/dist/mcpProbeCapability.d.ts +0 -1
  180. package/dist/mcpProbeCapability.js +13 -12
  181. package/dist/mcpReconnect.d.ts +1 -3
  182. package/dist/mcpReconnect.js +20 -10
  183. package/dist/memoryComplianceCapability.d.ts +0 -1
  184. package/dist/memoryComplianceCapability.js +14 -13
  185. package/dist/memoryOriginCapability.d.ts +0 -1
  186. package/dist/memoryOriginCapability.js +14 -13
  187. package/dist/memoryVerbsWire.d.ts +1 -1
  188. package/dist/memoryVerbsWire.js +4 -0
  189. package/dist/model/liveCatalogShape.d.ts +14 -0
  190. package/dist/model/liveCatalogShape.js +71 -0
  191. package/dist/model/modelSupplyRules.d.ts +1 -0
  192. package/dist/model/modelSupplyRules.js +30 -9
  193. package/dist/model/modelsPolicy.d.ts +21 -0
  194. package/dist/model/modelsPolicy.js +90 -0
  195. package/dist/modelIdentityResolvability.d.ts +4 -2
  196. package/dist/modelIdentityResolvability.js +25 -5
  197. package/dist/modelSwitchFallback.d.ts +69 -0
  198. package/dist/modelSwitchFallback.js +206 -0
  199. package/dist/notifications.js +12 -11
  200. package/dist/outputStyleSeatCapability.d.ts +15 -0
  201. package/dist/outputStyleSeatCapability.js +42 -0
  202. package/dist/ownKey.d.ts +7 -0
  203. package/dist/ownKey.js +58 -0
  204. package/dist/panelReduce.d.ts +114 -0
  205. package/dist/panelReduce.js +1135 -0
  206. package/dist/panelStateHolder.d.ts +17 -0
  207. package/dist/panelStateHolder.js +201 -0
  208. package/dist/peerLaneCapability.d.ts +0 -1
  209. package/dist/peerLaneCapability.js +15 -14
  210. package/dist/permissionModesCapability.d.ts +0 -1
  211. package/dist/permissionModesCapability.js +5 -10
  212. package/dist/permissionRuleIssue.js +1 -1
  213. package/dist/permissionRulesWriteCapability.d.ts +0 -1
  214. package/dist/permissionRulesWriteCapability.js +15 -14
  215. package/dist/permissionsAllowGrantCapability.d.ts +2 -1
  216. package/dist/permissionsAllowGrantCapability.js +35 -19
  217. package/dist/permissionsDeclaration.d.ts +16 -1
  218. package/dist/permissionsDeclaration.js +142 -15
  219. package/dist/printToolResultFrame.js +2 -10
  220. package/dist/promptDelivery.js +0 -8
  221. package/dist/protocolSegment.d.ts +1 -0
  222. package/dist/protocolSegment.js +13 -1
  223. package/dist/request/taskRequest.d.ts +11 -3
  224. package/dist/request/taskRequest.js +13 -1
  225. package/dist/resultFrameKeys.d.ts +4 -0
  226. package/dist/resultFrameKeys.js +13 -0
  227. package/dist/resumeRefusalCopy.d.ts +18 -1
  228. package/dist/resumeRefusalCopy.js +132 -31
  229. package/dist/retryStatus.js +6 -4
  230. package/dist/rewindArchiveCapability.d.ts +2 -1
  231. package/dist/rewindArchiveCapability.js +28 -15
  232. package/dist/rewindEngineAction.d.ts +21 -0
  233. package/dist/rewindEngineAction.js +36 -0
  234. package/dist/rewindWireCaps.d.ts +2 -1
  235. package/dist/rewindWireCaps.js +1 -0
  236. package/dist/{hitl/rosterMountedNames.d.ts → rosterMountedNames.d.ts} +1 -1
  237. package/dist/runCancelContext.js +2 -1
  238. package/dist/runTerminal.d.ts +0 -11
  239. package/dist/runTerminal.js +4 -27
  240. package/dist/sdkRegistryTransit.d.ts +2 -1
  241. package/dist/sdkRegistryTransit.js +1 -0
  242. package/dist/sealedKeyCapability.d.ts +0 -1
  243. package/dist/sealedKeyCapability.js +19 -20
  244. package/dist/seatContract.d.ts +85 -28
  245. package/dist/seatContract.js +512 -148
  246. package/dist/sessionIdSegment.d.ts +1 -0
  247. package/dist/sessionIdSegment.js +11 -0
  248. package/dist/sessionMemoryErase.d.ts +1 -1
  249. package/dist/sessionMemoryErase.js +6 -1
  250. package/dist/sessionMemoryStatus.js +3 -2
  251. package/dist/sessionPolicyCapability.d.ts +0 -1
  252. package/dist/sessionPolicyCapability.js +14 -13
  253. package/dist/sessionReadRedactionCapability.d.ts +15 -0
  254. package/dist/sessionReadRedactionCapability.js +42 -0
  255. package/dist/sessionSyncFileHistoryCapability.d.ts +0 -1
  256. package/dist/sessionSyncFileHistoryCapability.js +13 -12
  257. package/dist/skillToolListsCapability.d.ts +0 -1
  258. package/dist/skillToolListsCapability.js +13 -12
  259. package/dist/skillsWireCaps.d.ts +4 -0
  260. package/dist/skillsWireCaps.js +66 -1
  261. package/dist/sqlEngineCapability.d.ts +0 -1
  262. package/dist/sqlEngineCapability.js +21 -21
  263. package/dist/steerPriorityCapability.d.ts +0 -1
  264. package/dist/steerPriorityCapability.js +18 -19
  265. package/dist/storePostureCapability.d.ts +1 -1
  266. package/dist/storePostureCapability.js +16 -16
  267. package/dist/streamDrainingLegs.d.ts +6 -0
  268. package/dist/streamDrainingLegs.js +23 -0
  269. package/dist/subagent/agentStateDetail.d.ts +1 -0
  270. package/dist/subagent/agentStateDetail.js +41 -0
  271. package/dist/subagent/engineCompactWire.d.ts +15 -0
  272. package/dist/subagent/engineCompactWire.js +82 -45
  273. package/dist/subagent/engineDelegatedPrompt.js +10 -6
  274. package/dist/subagent/engineSubagentOutput.d.ts +0 -1
  275. package/dist/subagent/engineSubagentOutput.js +5 -20
  276. package/dist/subagent/engineSubagentTail.d.ts +0 -1
  277. package/dist/subagent/engineSubagentTail.js +7 -32
  278. package/dist/subagentContentStore.js +3 -3
  279. package/dist/supportFloor.js +2 -5
  280. package/dist/taskRequestWords.d.ts +2 -4
  281. package/dist/taskRequestWords.js +3 -2
  282. package/dist/terminalStatuses.d.ts +30 -0
  283. package/dist/terminalStatuses.js +67 -0
  284. package/dist/toolResult.d.ts +5 -0
  285. package/dist/toolResult.js +88 -36
  286. package/dist/types/engineState.d.ts +2 -1
  287. package/dist/usageAnalytics.d.ts +146 -0
  288. package/dist/usageAnalytics.js +311 -0
  289. package/dist/userAttachmentEnvelope.d.ts +22 -1
  290. package/dist/userAttachmentEnvelope.js +90 -2
  291. package/dist/userInvokedSkillsCapability.d.ts +0 -1
  292. package/dist/userInvokedSkillsCapability.js +13 -12
  293. package/dist/webSearchBackendCapability.d.ts +0 -1
  294. package/dist/webSearchBackendCapability.js +20 -19
  295. package/dist/webSearchWireCaps.js +3 -11
  296. package/dist/wireErrorTriage.d.ts +11 -0
  297. package/dist/wireErrorTriage.js +35 -0
  298. package/dist/wireFailureShape.d.ts +10 -0
  299. package/dist/wireFailureShape.js +72 -5
  300. package/dist/wireRefusalCopy.d.ts +6 -1
  301. package/dist/wireRefusalCopy.js +23 -25
  302. package/dist/wiringInstructionsAttribution.d.ts +10 -0
  303. package/dist/wiringInstructionsAttribution.js +67 -0
  304. package/dist/workflowClient.js +19 -2
  305. package/dist/workflowsJournalCapability.d.ts +0 -1
  306. package/dist/workflowsJournalCapability.js +13 -12
  307. package/dist/writeProtectionCapability.d.ts +0 -1
  308. package/dist/writeProtectionCapability.js +26 -26
  309. package/docs/INTEGRATION-CLIENTS.md +1733 -52
  310. package/package.json +5 -5
  311. package/dist/askSurvivesStandingAnswer.d.ts +0 -13
  312. package/dist/askSurvivesStandingAnswer.js +0 -53
  313. package/dist/engineCapsGenerationGuard.d.ts +0 -4
  314. package/dist/engineCapsGenerationGuard.js +0 -19
  315. package/dist/hitl/askSurvivesPosture.d.ts +0 -20
  316. package/dist/hitl/askSurvivesPosture.js +0 -48
  317. package/dist/panelRunningHistory.d.ts +0 -22
  318. package/dist/panelRunningHistory.js +0 -82
  319. package/dist/registryConflict.d.ts +0 -3
  320. package/dist/registryConflict.js +0 -44
  321. /package/dist/{hitl/rosterMountedNames.js → rosterMountedNames.js} +0 -0
@@ -0,0 +1,43 @@
1
+ import { APPROVAL_BINDING_MISMATCH, CHECKPOINT_UNSUPPORTED_VERSION, RESUME_OUTCOME_INVALID } from '../engineErrorCodes.js';
2
+ import { readRefusalField } from '../wireFailureShape.js';
3
+ const BINDING_SEAT_FIELDS = new Set(['boundCallId', 'boundInputHash']);
4
+ const ANSWER_FIELD = 'answer';
5
+ const BINDING_MISMATCH_ERROR_NAME = 'ApprovalBindingMismatchError';
6
+ export function decisionConflictOf(err) {
7
+ if (typeof err !== 'object' || err === null)
8
+ return undefined;
9
+ let code;
10
+ let name;
11
+ try {
12
+ code = err.errorCode;
13
+ }
14
+ catch {
15
+ code = undefined;
16
+ }
17
+ try {
18
+ name = err.name;
19
+ }
20
+ catch {
21
+ name = undefined;
22
+ }
23
+ if (code === CHECKPOINT_UNSUPPORTED_VERSION)
24
+ return 'format_version';
25
+ const bindingFamily = code === APPROVAL_BINDING_MISMATCH || (code === undefined && name === BINDING_MISMATCH_ERROR_NAME);
26
+ if (!bindingFamily && code !== RESUME_OUTCOME_INVALID)
27
+ return undefined;
28
+ let field;
29
+ try {
30
+ field = readRefusalField(err);
31
+ }
32
+ catch {
33
+ field = undefined;
34
+ }
35
+ if (code === RESUME_OUTCOME_INVALID)
36
+ return field === ANSWER_FIELD ? 'answer_invalid' : undefined;
37
+ if (field === ANSWER_FIELD)
38
+ return 'answer_invalid';
39
+ if (field === undefined)
40
+ return 'row_integrity';
41
+ return BINDING_SEAT_FIELDS.has(field) ? 'binding_mismatch' : undefined;
42
+ }
43
+ export const DECISION_ANSWER_INVALID_CONTENT = 'The engine rejected the answer itself because it does not fit the question that was asked · Nothing was decided and the question is still waiting · Correct the answer and send it again';
@@ -0,0 +1,23 @@
1
+ import { type DecisionRefusalConflict } from './decisionConflict.js';
2
+ export type DecisionRefusalStanding = 'settled-elsewhere' | 'ambiguous' | 'refused-pending';
3
+ export type { DecisionRefusalConflict } from './decisionConflict.js';
4
+ export declare function decisionRefusalSaysAskGone(err: unknown): boolean;
5
+ export interface DecisionRefusalClassified {
6
+ readonly standing: DecisionRefusalStanding;
7
+ readonly status: number;
8
+ readonly errorCode?: string;
9
+ readonly transient?: true;
10
+ readonly conflict?: DecisionRefusalConflict;
11
+ }
12
+ export declare function classifyDecisionRefusal(err: unknown): DecisionRefusalClassified | undefined;
13
+ export type LiveAskPendingReading = 'pending' | 'not_pending' | 'unknown';
14
+ export declare function liveAskPendingReading(envelope: unknown, approvalId: string): LiveAskPendingReading;
15
+ export declare function decisionRefusalClosesOut(refusal: DecisionRefusalClassified | undefined, pending: LiveAskPendingReading): boolean;
16
+ export type UndeliverableDecisionEnd = 'run-stopped' | 'run-unconfirmed' | 'turn-stopped';
17
+ export interface UndeliverableDecisionFacts {
18
+ readonly status: number;
19
+ readonly errorCode?: string;
20
+ readonly end: UndeliverableDecisionEnd;
21
+ readonly runId?: string;
22
+ }
23
+ export declare function undeliverableDecisionContent(facts: UndeliverableDecisionFacts): string;
@@ -0,0 +1,88 @@
1
+ import { refusalSaysStillPending } from '../engineErrorCodes.js';
2
+ import { notPendingCauseSaysEnded } from './approvalEndingCause.js';
3
+ import { decisionConflictOf } from './decisionConflict.js';
4
+ import { readLivePendingRows } from './livePendingAsk.js';
5
+ import { readToolApprovalRespondRefusal } from './toolApprovalWire.js';
6
+ const ASK_DECIDED_CODE = 'conflict.ask_decided';
7
+ const TRANSIENT_STATUSES = new Set([408, 425, 429, 502, 503, 504]);
8
+ const DISPLAYABLE_CODE = /^[A-Za-z0-9._:-]{1,64}$/;
9
+ export function decisionRefusalSaysAskGone(err) {
10
+ try {
11
+ if (typeof err === 'object' && err !== null && 'code' in err) {
12
+ const code = err.code;
13
+ if (code === 'no_pending')
14
+ return true;
15
+ }
16
+ const c = classifyDecisionRefusal(err);
17
+ if (c?.standing !== 'settled-elsewhere')
18
+ return false;
19
+ return c.status !== 404 || (typeof err === 'object' && err !== null && notPendingCauseSaysEnded(err));
20
+ }
21
+ catch {
22
+ return false;
23
+ }
24
+ }
25
+ export function classifyDecisionRefusal(err) {
26
+ const r = readToolApprovalRespondRefusal(err);
27
+ const status = r?.status;
28
+ if (status === undefined || !Number.isInteger(status) || status < 400 || status > 599)
29
+ return undefined;
30
+ const code = r?.errorCode;
31
+ const errorCode = code !== undefined && DISPLAYABLE_CODE.test(code) ? code : undefined;
32
+ const standing = status === 404 || status === 410 || (status === 409 && code === ASK_DECIDED_CODE)
33
+ ? 'settled-elsewhere'
34
+ : status >= 500 && status !== 501
35
+ ? 'ambiguous'
36
+ : 'refused-pending';
37
+ const transient = TRANSIENT_STATUSES.has(status) || (typeof err === 'object' && err !== null && refusalSaysStillPending(err));
38
+ const conflict = status === 409 ? decisionConflictOf(err) : undefined;
39
+ return Object.freeze({
40
+ standing,
41
+ status,
42
+ ...(errorCode !== undefined ? { errorCode } : {}),
43
+ ...(transient ? { transient: true } : {}),
44
+ ...(conflict !== undefined ? { conflict } : {}),
45
+ });
46
+ }
47
+ export function liveAskPendingReading(envelope, approvalId) {
48
+ if (typeof approvalId !== 'string' || approvalId === '')
49
+ return 'unknown';
50
+ try {
51
+ const reading = readLivePendingRows(envelope);
52
+ if (reading.kind !== 'present')
53
+ return 'unknown';
54
+ if (reading.rows.some((row) => row.approvalId === approvalId))
55
+ return 'pending';
56
+ return reading.dropped === 0 ? 'not_pending' : 'unknown';
57
+ }
58
+ catch {
59
+ return 'unknown';
60
+ }
61
+ }
62
+ export function decisionRefusalClosesOut(refusal, pending) {
63
+ if (pending !== 'pending' || typeof refusal !== 'object' || refusal === null)
64
+ return false;
65
+ try {
66
+ const standing = refusal.standing;
67
+ if (refusal.transient === true)
68
+ return false;
69
+ return standing === 'ambiguous' || standing === 'refused-pending';
70
+ }
71
+ catch {
72
+ return false;
73
+ }
74
+ }
75
+ export function undeliverableDecisionContent(facts) {
76
+ const code = typeof facts.errorCode === 'string' && DISPLAYABLE_CODE.test(facts.errorCode) ? ` ${facts.errorCode}` : '';
77
+ 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`;
78
+ const runId = typeof facts.runId === 'string' && DISPLAYABLE_CODE.test(facts.runId) ? ` ${facts.runId}` : '';
79
+ switch (facts.end) {
80
+ case 'run-stopped':
81
+ return `${head}; the run was stopped instead of being left waiting for the approval window to close. Update the client, or run the task in an interactive session and answer the approval there.`;
82
+ case 'run-unconfirmed':
83
+ return `${head}; this client stopped waiting, but the engine did not confirm that it stopped the run${runId}, so that approval may stay open until its window closes. Update the client, or run the task in an interactive session and answer the approval there.`;
84
+ case 'turn-stopped':
85
+ default:
86
+ return `${head}; this turn was stopped instead of being left waiting. Update the client, or switch to a permission mode that shows you the approval and try again.`;
87
+ }
88
+ }
@@ -2,9 +2,19 @@ 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, type ToolApprovalFrameOutcome } from './toolApprovalWire.js';
4
4
  import type { GateLedger } from './gateLedger.js';
5
+ import type { NoAllowCause } from './noAllowCause.js';
5
6
  import { type ReplayedApprovalDisposition } from './replayedApproval.js';
6
7
  export declare const HITL_REJECT_MESSAGE = "The user doesn't want to proceed with this tool use. The tool use was rejected (eg. if it was a file edit, the new_string was NOT written to the file). STOP what you are doing and wait for the user to tell you how to proceed.";
7
8
  export declare const HITL_POLICY_DENY_MESSAGE: string;
9
+ export type PolicyDenyLane = 'no_approval_ui' | 'dont_ask';
10
+ export interface PolicyDenyReasonFacts {
11
+ readonly lane: PolicyDenyLane;
12
+ readonly toolName: string;
13
+ readonly cause?: NoAllowCause;
14
+ readonly allowRuleFlag?: string;
15
+ readonly budgetSetting?: string;
16
+ }
17
+ export declare function policyDenyReason(facts: PolicyDenyReasonFacts): string;
8
18
  export declare const HITL_INTERRUPT_MESSAGE_FOR_TOOL_USE = "[Request interrupted by user for tool use]";
9
19
  export declare const ENGINE_ABORT_TOOL_RESULT = "Operation aborted";
10
20
  export declare function toolEndOutputText(output: unknown): string | undefined;
@@ -1,11 +1,15 @@
1
1
  import { hostLog } from '../host.js';
2
+ import { invokeHostCallbackIsolated } from '../hostCallbackGuard.js';
2
3
  import { isToolApprovalGate, toolNameIsFsWrite, toolNameIsShellExec, isToolApprovalFrame, isFromSubagent, surfaceToolApprovalFrameAndRespond, } from './toolApprovalWire.js';
3
4
  import { classifierDenyFromToolEnd } from '../classifierVerdictWire.js';
4
5
  import { GATE_PARKED_ERROR_CODE } from '../engineErrorCodes.js';
5
6
  import { readRunTerminal, runTerminalCode, runTerminalGateKind, runTerminalGateToolName } from '../runTerminal.js';
6
7
  import { surfaceForCurrentSession, surfaceReplayedApprovalListUnreadable } from './hitlHostSurface.js';
8
+ import { liveCardAnsweredHow, liveCardHoldOf, supersedeLiveCard } from './approvalHolds.js';
9
+ import { approvalCompleteParked } from './approvalCompleteParked.js';
10
+ import { liveFrameCallKey } from './gateIdentity.js';
7
11
  import { SEMA_DENIAL_KIND_KEY, hasLedgerPositionKey } from './gateLedger.js';
8
- import { replayedApprovalDisposition } from './replayedApproval.js';
12
+ import { replayedApprovalDisposition, settledApprovalDisposition } from './replayedApproval.js';
9
13
  import { settleWithinDeadline } from '../abortableSleep.js';
10
14
  import { ccToolDenialKindForSettledBy } from '../gateVocabulary.js';
11
15
  import { REJECT_MESSAGE } from '../adapt/wireShapes.js';
@@ -14,6 +18,38 @@ export const HITL_REJECT_MESSAGE = REJECT_MESSAGE;
14
18
  export const HITL_POLICY_DENY_MESSAGE = 'Permission for this tool use was denied: it requires interactive approval, and permission prompts are ' +
15
19
  'not available in this session. The action was NOT performed. Do not claim it succeeded, and do not retry ' +
16
20
  'it in this session \u2014 report the limitation to the user, or suggest an alternative.';
21
+ const SENTENCE_TOOL_NAME = /^[A-Za-z0-9_][A-Za-z0-9_.:@-]{0,199}$/;
22
+ export function policyDenyReason(facts) {
23
+ const one = typeof facts.toolName === 'string' && SENTENCE_TOOL_NAME.test(facts.toolName) ? `this one "${facts.toolName}" call` : 'this one call';
24
+ const flag = typeof facts.allowRuleFlag === 'string' && SENTENCE_TOOL_NAME.test(facts.allowRuleFlag.replace(/^--?/, '')) ? ` (or ${facts.allowRuleFlag})` : '';
25
+ const budgetKnob = typeof facts.budgetSetting === 'string' && SENTENCE_TOOL_NAME.test(facts.budgetSetting) ? facts.budgetSetting : undefined;
26
+ const cause = facts.cause === 'no_allow_rule' || facts.cause === 'ask_rule' || facts.cause === 'budget' ? facts.cause : 'other';
27
+ if (facts.lane === 'dont_ask') {
28
+ const mode = 'denied by the dontAsk permission mode';
29
+ switch (cause) {
30
+ case 'no_allow_rule':
31
+ return `${mode}: ${one} needed approval, no permission rule allowed it, and this mode refuses anything that would ask — calls that need no approval still run; an allow rule in settings${flag} can approve calls like this ahead of time`;
32
+ case 'ask_rule':
33
+ return `${mode}: an ask rule matched ${one}, and this mode refuses anything that would ask (an ask rule outranks allow rules) — narrow or remove that ask rule, or use another permission mode to answer it`;
34
+ case 'budget':
35
+ return `${mode}: ${one} needed approval, and this session's automatic-approval budget is used up, so saved rules no longer approve calls${budgetKnob !== undefined ? ` — raise ${budgetKnob} before launch to change the cap` : ''}`;
36
+ default:
37
+ return `${mode}: ${one} needed a person's approval that saved permission rules cannot approve here (the engine or your deployment requires a person for it, or it could not be checked against your rules), and this mode refuses anything that would ask — use another permission mode to answer it`;
38
+ }
39
+ }
40
+ const lane = 'no approval UI on this lane';
41
+ const tail = 'nobody can be asked here, so only this call was refused — calls that need no approval still run';
42
+ switch (cause) {
43
+ case 'no_allow_rule':
44
+ return `${lane}: ${one} needed a person's approval, no permission rule answered it, and ${tail}; a matching allow rule in settings${flag} can approve calls like this ahead of time`;
45
+ case 'ask_rule':
46
+ return `${lane}: an ask rule matched ${one}, so it needed a person's answer, and ${tail}; an ask rule outranks allow rules, so narrow or remove that ask rule, or run the task interactively to answer it`;
47
+ case 'budget':
48
+ return `${lane}: ${one} needed a person's approval, and this session's automatic-approval budget is used up, so saved rules no longer approve calls; ${tail}${budgetKnob !== undefined ? `; raise ${budgetKnob} before launch to change the cap` : ''}`;
49
+ default:
50
+ return `${lane}: ${one} needed a person's approval, and saved permission rules cannot approve it here (the engine or your deployment requires a person for it, or it could not be checked against your rules); ${tail}; run the task interactively to answer it`;
51
+ }
52
+ }
17
53
  function denyOutputForRender(attribution) {
18
54
  if (attribution?.settledBy !== 'policy')
19
55
  return HITL_REJECT_MESSAGE;
@@ -234,32 +270,32 @@ const TOOL_END_ARMS = [
234
270
  }
235
271
  async function routeToolApprovalFrame(ev, ctx) {
236
272
  const { led, deps } = ctx;
237
- if (ev.type === 'tool_approval_complete')
273
+ if (ev.type === 'tool_approval_complete') {
274
+ const id = ev.approvalId;
275
+ if (typeof id === 'string' && id !== '' && supersedeLiveCard(liveFrameCallKey(id), approvalCompleteParked(ev))) {
276
+ hostLog('debug', `liveHitlAskWire: tool_approval_complete for ${id} arrived while its card was waiting — card withdrawn (nothing will be sent from it)`);
277
+ }
278
+ if (typeof id === 'string' && id !== '')
279
+ led.noteApprovalSettled(id, 'closed_by_engine');
238
280
  return { kind: 'skip' };
281
+ }
239
282
  if (!deps.respondToolApproval) {
240
283
  hostLog('debug', `liveHitlAskWire: tool_approval frame ${ev.approvalId} but no respond wire — engine self-settles (TTL deny)`);
241
284
  return { kind: 'skip' };
242
285
  }
243
- if (hasLedgerPositionKey(ev) && !led.preambleApprovals().has(ev.approvalId)) {
244
- const disposition = await judgeLedgerApprovalFrame(ev, ctx);
286
+ const settledHere = settledApprovalDisposition(ev, led.settledApprovals());
287
+ if (settledHere !== undefined || (hasLedgerPositionKey(ev) && !led.preambleApprovals().has(ev.approvalId))) {
288
+ const disposition = settledHere ?? (await judgeLedgerApprovalFrame(ev, ctx));
245
289
  if (disposition.kind !== 'live') {
246
- hostLog('debug', `liveHitlAskWire: tool_approval frame ${ev.approvalId} read back from the run event log is ${disposition.kind}` +
247
- `${disposition.kind === 'unknown' ? ` (${disposition.why})` : disposition.cause !== undefined ? ` (${disposition.cause})` : ''}` +
248
- ' — not raised as a question, no decision sent');
290
+ hostLog('debug', disposition.kind === 'decided' && disposition.settled !== undefined
291
+ ? `liveHitlAskWire: tool_approval frame ${ev.approvalId} repeats a question already settled on this bridge (${disposition.settled}) — not raised again, no decision sent`
292
+ : `liveHitlAskWire: tool_approval frame ${ev.approvalId} read back from the run event log is ${disposition.kind}` +
293
+ `${disposition.kind === 'unknown' ? ` (${disposition.why})` : disposition.cause !== undefined ? ` (${disposition.cause})` : ''}` +
294
+ ' — not raised as a question, no decision sent');
249
295
  if (disposition.kind === 'unknown' && ctx.signal?.aborted !== true)
250
296
  surfaceReplayedApprovalListUnreadable();
251
297
  if (deps.onReplayedApproval !== undefined) {
252
- try {
253
- const out = deps.onReplayedApproval(ev, disposition);
254
- if (out && typeof out.then === 'function') {
255
- void Promise.resolve(out).catch((e) => {
256
- hostLog('debug', `liveHitlAskWire: onReplayedApproval rejected: ${String(e).slice(0, 160)}`);
257
- });
258
- }
259
- }
260
- catch (e) {
261
- hostLog('debug', `liveHitlAskWire: onReplayedApproval threw: ${String(e).slice(0, 160)}`);
262
- }
298
+ invokeHostCallbackIsolated('liveHitlAskWire: onReplayedApproval', () => deps.onReplayedApproval?.(ev, disposition));
263
299
  }
264
300
  return { kind: 'skip' };
265
301
  }
@@ -269,20 +305,24 @@ async function routeToolApprovalFrame(ev, ctx) {
269
305
  const frameCallId = !fromSubagent && typeof ev.toolCallId === 'string' && ev.toolCallId !== '' ? ev.toolCallId : undefined;
270
306
  const gatedCallId = fromSubagent ? undefined : frameCallId ?? led.lastPendingFsCall();
271
307
  const argsCallId = frameCallId === undefined ? gatedCallId : typeof ev.toolName === 'string' && toolNameIsFsWrite(ev.toolName) ? frameCallId : undefined;
272
- const outcome = await surfaceToolApprovalFrameAndRespond(ev, deps.respondToolApproval, argsOfGatedStart(led, argsCallId), ctx.signal, deps.approvalLane);
308
+ const runTaskId = ctx.taskId.current;
309
+ const approvalIdAtLaunch = ev.approvalId;
310
+ const launched = surfaceToolApprovalFrameAndRespond(ev, deps.respondToolApproval, argsOfGatedStart(led, argsCallId), ctx.signal, deps.approvalLane, typeof runTaskId === 'string' && runTaskId !== '' ? { taskId: runTaskId } : undefined);
311
+ const hold = liveCardHoldOf(liveFrameCallKey(ev.approvalId));
312
+ const handled = launched.then((outcome) => settleLiveCardOutcome(ev, approvalIdAtLaunch, outcome, ctx, fromSubagent, gatedCallId), (e) => {
313
+ hostLog('debug', `liveHitlAskWire: tool_approval card for ${ev.approvalId} failed: ${String(e).slice(0, 160)}`);
314
+ });
315
+ led.trackLiveCard(() => hold?.phase ?? 'card', handled);
316
+ return { kind: 'skip' };
317
+ }
318
+ function settleLiveCardOutcome(ev, approvalId, outcome, ctx, fromSubagent, gatedCallId) {
319
+ const { led, deps } = ctx;
273
320
  const { decision } = outcome;
321
+ const settledHow = liveCardAnsweredHow(outcome);
322
+ if (settledHow !== undefined)
323
+ led.noteApprovalSettled(approvalId, settledHow);
274
324
  if (deps.onToolApprovalOutcome !== undefined) {
275
- try {
276
- const out = deps.onToolApprovalOutcome(ev, outcome);
277
- if (out && typeof out.then === 'function') {
278
- void Promise.resolve(out).catch((e) => {
279
- hostLog('debug', `liveHitlAskWire: onToolApprovalOutcome rejected: ${String(e).slice(0, 160)}`);
280
- });
281
- }
282
- }
283
- catch (e) {
284
- hostLog('debug', `liveHitlAskWire: onToolApprovalOutcome threw: ${String(e).slice(0, 160)}`);
285
- }
325
+ invokeHostCallbackIsolated('liveHitlAskWire: onToolApprovalOutcome', () => deps.onToolApprovalOutcome?.(ev, outcome));
286
326
  }
287
327
  if (decision === 'deny' && !fromSubagent) {
288
328
  const attribution = {
@@ -294,7 +334,6 @@ async function routeToolApprovalFrame(ev, ctx) {
294
334
  else
295
335
  led.armDenyStamp(attribution);
296
336
  }
297
- return { kind: 'skip' };
298
337
  }
299
338
  const REPLAYED_APPROVAL_LIST_DEADLINE_MS = 3000;
300
339
  async function judgeLedgerApprovalFrame(ev, ctx) {
@@ -318,7 +357,7 @@ async function judgeLedgerApprovalFrame(ev, ctx) {
318
357
  .finally(release);
319
358
  });
320
359
  const approvals = got.kind === 'value' ? { read: 'ok', body: got.value } : { read: 'failed' };
321
- return replayedApprovalDisposition(ev, { preamble: ctx.led.preambleApprovals(), approvals });
360
+ return replayedApprovalDisposition(ev, { preamble: ctx.led.preambleApprovals(), approvals, settled: ctx.led.settledApprovals() });
322
361
  }
323
362
  function routeToolStart(ev, callId, led) {
324
363
  led.noteStart(callId, ev);
@@ -16,6 +16,9 @@ export interface AskAnsweredOutput {
16
16
  export declare function durableSeqOf(ev: object): string | undefined;
17
17
  export declare function hasLedgerPositionKey(ev: object): boolean;
18
18
  export declare const PREAMBLE_APPROVALS_MAX_ENTRIES = 4096;
19
+ export declare const APPROVAL_SETTLED_HOWS: readonly ["answered", "interrupted", "closed_by_engine"];
20
+ export type ApprovalSettledHow = (typeof APPROVAL_SETTLED_HOWS)[number];
21
+ export declare const SETTLED_APPROVALS_MAX_ENTRIES = 4096;
19
22
  export interface GateLedger {
20
23
  noteSeq(ev: AgentEvent): void;
21
24
  lastSeq(): string | undefined;
@@ -23,6 +26,11 @@ export interface GateLedger {
23
26
  notePreambleApproval(approvalId: string): void;
24
27
  preambleApprovals(): ReadonlySet<string>;
25
28
  beginStreamSegment(): void;
29
+ noteApprovalSettled(approvalId: string, how: ApprovalSettledHow): void;
30
+ settledApprovals(): ReadonlyMap<string, ApprovalSettledHow>;
31
+ trackLiveCard(phaseOf: () => 'card' | 'respond', handled: Promise<void>): void;
32
+ answeringLiveCards(): Promise<void>[];
33
+ liveCardsSettled(): Promise<void>;
26
34
  markStarted(callId: string): boolean;
27
35
  noteGatedStart(callId: string, ev: AgentEvent): void;
28
36
  gatedStartArgs(): ReadonlyMap<string, unknown>;
@@ -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,8 @@ export function createGateLedger() {
88
90
  let denyStampAttribution;
89
91
  let seq;
90
92
  const preambleApprovalIds = new Set();
93
+ const settledApprovalHows = new Map();
94
+ const liveCards = new Set();
91
95
  return {
92
96
  noteSeq(ev) {
93
97
  const s = durableSeqOf(ev);
@@ -120,6 +124,40 @@ export function createGateLedger() {
120
124
  beginStreamSegment() {
121
125
  preambleApprovalIds.clear();
122
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
+ },
145
+ trackLiveCard(phaseOf, handled) {
146
+ const entry = { phaseOf, handled };
147
+ liveCards.add(entry);
148
+ void handled.then(() => { liveCards.delete(entry); }, () => { liveCards.delete(entry); });
149
+ },
150
+ answeringLiveCards() {
151
+ const out = [];
152
+ for (const e of liveCards)
153
+ if (e.phaseOf() === 'respond')
154
+ out.push(e.handled);
155
+ return out;
156
+ },
157
+ async liveCardsSettled() {
158
+ while (liveCards.size > 0)
159
+ await Promise.allSettled([...liveCards].map((e) => e.handled));
160
+ },
123
161
  markStarted(callId) {
124
162
  if (startedCalls.has(callId))
125
163
  return false;
@@ -1,4 +1,4 @@
1
- import type { AgentEvent, ApprovalDecision, ApprovalStaleError, PendingCheckpoint, CheckpointGate, PlanReviewRequest, AssistantTaskStatus } from '@sema-agent/sdk';
1
+ import type { AgentEvent, ApprovalDecidedBy, ApprovalDecision, ApprovalStaleError, PendingCheckpoint, CheckpointGate, PlanReviewRequest, AssistantTaskStatus } from '@sema-agent/sdk';
2
2
  import type { PermissionResult } from '@sema-agent/agent-types';
3
3
  import type { ApprovalsListEnvelope } from './crashConverged.js';
4
4
  import { type SuspendedReopenReading } from './suspendedReopen.js';
@@ -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";
@@ -56,15 +57,25 @@ export interface HitlDecideDenyOutcome {
56
57
  decision: 'deny';
57
58
  reason?: string | undefined;
58
59
  settledBy?: 'policy' | undefined;
59
- decidedBy?: 'policy' | undefined;
60
+ decidedBy?: Extract<ApprovalDecidedBy, 'policy'> | undefined;
60
61
  }
61
62
  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;