open-multi-agent-kit 0.98.4 → 0.98.5

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 (252) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +3 -2
  3. package/dist/commands/run-command.d.ts +2 -1
  4. package/dist/commands/run-command.d.ts.map +1 -1
  5. package/dist/commands/run-command.js +9 -1
  6. package/dist/commands/run-command.js.map +1 -1
  7. package/dist/commands/verified-run-cli.d.ts +6 -0
  8. package/dist/commands/verified-run-cli.d.ts.map +1 -0
  9. package/dist/commands/verified-run-cli.js +190 -0
  10. package/dist/commands/verified-run-cli.js.map +1 -0
  11. package/dist/core/agent-session-services.d.ts +8 -1
  12. package/dist/core/agent-session-services.d.ts.map +1 -1
  13. package/dist/core/agent-session-services.js +41 -0
  14. package/dist/core/agent-session-services.js.map +1 -1
  15. package/dist/core/agent-session.d.ts +7 -8
  16. package/dist/core/agent-session.d.ts.map +1 -1
  17. package/dist/core/agent-session.js +61 -41
  18. package/dist/core/agent-session.js.map +1 -1
  19. package/dist/core/prompt-settlement.d.ts +4 -3
  20. package/dist/core/prompt-settlement.d.ts.map +1 -1
  21. package/dist/core/prompt-settlement.js.map +1 -1
  22. package/dist/core/run-budget-policy.d.ts +18 -0
  23. package/dist/core/run-budget-policy.d.ts.map +1 -0
  24. package/dist/core/run-budget-policy.js +52 -0
  25. package/dist/core/run-budget-policy.js.map +1 -0
  26. package/dist/core/run-budget.d.ts +33 -0
  27. package/dist/core/run-budget.d.ts.map +1 -0
  28. package/dist/core/run-budget.js +89 -0
  29. package/dist/core/run-budget.js.map +1 -0
  30. package/dist/core/run-execution-api.d.ts +15 -0
  31. package/dist/core/run-execution-api.d.ts.map +1 -0
  32. package/dist/core/run-execution-api.js +7 -0
  33. package/dist/core/run-execution-api.js.map +1 -0
  34. package/dist/core/run-journal.d.ts.map +1 -1
  35. package/dist/core/run-journal.js +30 -208
  36. package/dist/core/run-journal.js.map +1 -1
  37. package/dist/core/session-bash-service.d.ts +2 -2
  38. package/dist/core/session-bash-service.d.ts.map +1 -1
  39. package/dist/core/session-bash-service.js +21 -9
  40. package/dist/core/session-bash-service.js.map +1 -1
  41. package/dist/core/session-failure-cause.d.ts.map +1 -1
  42. package/dist/core/session-failure-cause.js +5 -0
  43. package/dist/core/session-failure-cause.js.map +1 -1
  44. package/dist/core/session-prompt-lifecycle.d.ts +25 -0
  45. package/dist/core/session-prompt-lifecycle.d.ts.map +1 -0
  46. package/dist/core/session-prompt-lifecycle.js +87 -0
  47. package/dist/core/session-prompt-lifecycle.js.map +1 -0
  48. package/dist/core/session-run-budget.d.ts +28 -0
  49. package/dist/core/session-run-budget.d.ts.map +1 -0
  50. package/dist/core/session-run-budget.js +127 -0
  51. package/dist/core/session-run-budget.js.map +1 -0
  52. package/dist/core/session-run-termination.d.ts.map +1 -1
  53. package/dist/core/session-run-termination.js +14 -3
  54. package/dist/core/session-run-termination.js.map +1 -1
  55. package/dist/core/session-termination-types.d.ts +97 -0
  56. package/dist/core/session-termination-types.d.ts.map +1 -0
  57. package/dist/core/session-termination-types.js +26 -0
  58. package/dist/core/session-termination-types.js.map +1 -0
  59. package/dist/core/session-termination.d.ts +3 -97
  60. package/dist/core/session-termination.d.ts.map +1 -1
  61. package/dist/core/session-termination.js +24 -28
  62. package/dist/core/session-termination.js.map +1 -1
  63. package/dist/core/slash-commands.d.ts.map +1 -1
  64. package/dist/core/slash-commands.js +1 -0
  65. package/dist/core/slash-commands.js.map +1 -1
  66. package/dist/core/subagent-lane-launcher.d.ts +3 -2
  67. package/dist/core/subagent-lane-launcher.d.ts.map +1 -1
  68. package/dist/core/subagent-lane-launcher.js +24 -13
  69. package/dist/core/subagent-lane-launcher.js.map +1 -1
  70. package/dist/core/verified-run/broker.d.ts +26 -0
  71. package/dist/core/verified-run/broker.d.ts.map +1 -0
  72. package/dist/core/verified-run/broker.js +210 -0
  73. package/dist/core/verified-run/broker.js.map +1 -0
  74. package/dist/core/verified-run/candidate.d.ts +24 -0
  75. package/dist/core/verified-run/candidate.d.ts.map +1 -0
  76. package/dist/core/verified-run/candidate.js +167 -0
  77. package/dist/core/verified-run/candidate.js.map +1 -0
  78. package/dist/core/verified-run/check-receipt.d.ts +18 -0
  79. package/dist/core/verified-run/check-receipt.d.ts.map +1 -0
  80. package/dist/core/verified-run/check-receipt.js +92 -0
  81. package/dist/core/verified-run/check-receipt.js.map +1 -0
  82. package/dist/core/verified-run/coordinator.d.ts +39 -0
  83. package/dist/core/verified-run/coordinator.d.ts.map +1 -0
  84. package/dist/core/verified-run/coordinator.js +190 -0
  85. package/dist/core/verified-run/coordinator.js.map +1 -0
  86. package/dist/core/verified-run/dag-candidates.d.ts +8 -0
  87. package/dist/core/verified-run/dag-candidates.d.ts.map +1 -0
  88. package/dist/core/verified-run/dag-candidates.js +65 -0
  89. package/dist/core/verified-run/dag-candidates.js.map +1 -0
  90. package/dist/core/verified-run/dag-phase.d.ts +7 -0
  91. package/dist/core/verified-run/dag-phase.d.ts.map +1 -0
  92. package/dist/core/verified-run/dag-phase.js +92 -0
  93. package/dist/core/verified-run/dag-phase.js.map +1 -0
  94. package/dist/core/verified-run/dag-projection.d.ts +7 -0
  95. package/dist/core/verified-run/dag-projection.d.ts.map +1 -0
  96. package/dist/core/verified-run/dag-projection.js +90 -0
  97. package/dist/core/verified-run/dag-projection.js.map +1 -0
  98. package/dist/core/verified-run/dag-recovery.d.ts +13 -0
  99. package/dist/core/verified-run/dag-recovery.d.ts.map +1 -0
  100. package/dist/core/verified-run/dag-recovery.js +98 -0
  101. package/dist/core/verified-run/dag-recovery.js.map +1 -0
  102. package/dist/core/verified-run/dag-retry-projection.d.ts +9 -0
  103. package/dist/core/verified-run/dag-retry-projection.d.ts.map +1 -0
  104. package/dist/core/verified-run/dag-retry-projection.js +43 -0
  105. package/dist/core/verified-run/dag-retry-projection.js.map +1 -0
  106. package/dist/core/verified-run/dag-types.d.ts +47 -0
  107. package/dist/core/verified-run/dag-types.d.ts.map +1 -0
  108. package/dist/core/verified-run/dag-types.js +2 -0
  109. package/dist/core/verified-run/dag-types.js.map +1 -0
  110. package/dist/core/verified-run/event-parser.d.ts +3 -0
  111. package/dist/core/verified-run/event-parser.d.ts.map +1 -0
  112. package/dist/core/verified-run/event-parser.js +153 -0
  113. package/dist/core/verified-run/event-parser.js.map +1 -0
  114. package/dist/core/verified-run/events.d.ts +4 -0
  115. package/dist/core/verified-run/events.d.ts.map +1 -0
  116. package/dist/core/verified-run/events.js +3 -0
  117. package/dist/core/verified-run/events.js.map +1 -0
  118. package/dist/core/verified-run/evidence-binding.d.ts +18 -0
  119. package/dist/core/verified-run/evidence-binding.d.ts.map +1 -0
  120. package/dist/core/verified-run/evidence-binding.js +81 -0
  121. package/dist/core/verified-run/evidence-binding.js.map +1 -0
  122. package/dist/core/verified-run/evidence.d.ts +27 -0
  123. package/dist/core/verified-run/evidence.d.ts.map +1 -0
  124. package/dist/core/verified-run/evidence.js +100 -0
  125. package/dist/core/verified-run/evidence.js.map +1 -0
  126. package/dist/core/verified-run/journal.d.ts +32 -0
  127. package/dist/core/verified-run/journal.d.ts.map +1 -0
  128. package/dist/core/verified-run/journal.js +103 -0
  129. package/dist/core/verified-run/journal.js.map +1 -0
  130. package/dist/core/verified-run/namespace-identity.d.ts +11 -0
  131. package/dist/core/verified-run/namespace-identity.d.ts.map +1 -0
  132. package/dist/core/verified-run/namespace-identity.js +77 -0
  133. package/dist/core/verified-run/namespace-identity.js.map +1 -0
  134. package/dist/core/verified-run/owned-execution.d.ts +21 -0
  135. package/dist/core/verified-run/owned-execution.d.ts.map +1 -0
  136. package/dist/core/verified-run/owned-execution.js +43 -0
  137. package/dist/core/verified-run/owned-execution.js.map +1 -0
  138. package/dist/core/verified-run/phase-context.d.ts +9 -0
  139. package/dist/core/verified-run/phase-context.d.ts.map +1 -0
  140. package/dist/core/verified-run/phase-context.js +2 -0
  141. package/dist/core/verified-run/phase-context.js.map +1 -0
  142. package/dist/core/verified-run/process-gate.d.ts +5 -0
  143. package/dist/core/verified-run/process-gate.d.ts.map +1 -0
  144. package/dist/core/verified-run/process-gate.js +31 -0
  145. package/dist/core/verified-run/process-gate.js.map +1 -0
  146. package/dist/core/verified-run/projection.d.ts +4 -0
  147. package/dist/core/verified-run/projection.d.ts.map +1 -0
  148. package/dist/core/verified-run/projection.js +219 -0
  149. package/dist/core/verified-run/projection.js.map +1 -0
  150. package/dist/core/verified-run/recovery-clock.d.ts +19 -0
  151. package/dist/core/verified-run/recovery-clock.d.ts.map +1 -0
  152. package/dist/core/verified-run/recovery-clock.js +69 -0
  153. package/dist/core/verified-run/recovery-clock.js.map +1 -0
  154. package/dist/core/verified-run/recovery-command.d.ts +11 -0
  155. package/dist/core/verified-run/recovery-command.d.ts.map +1 -0
  156. package/dist/core/verified-run/recovery-command.js +73 -0
  157. package/dist/core/verified-run/recovery-command.js.map +1 -0
  158. package/dist/core/verified-run/recovery-projection.d.ts +12 -0
  159. package/dist/core/verified-run/recovery-projection.d.ts.map +1 -0
  160. package/dist/core/verified-run/recovery-projection.js +88 -0
  161. package/dist/core/verified-run/recovery-projection.js.map +1 -0
  162. package/dist/core/verified-run/recovery.d.ts +12 -0
  163. package/dist/core/verified-run/recovery.d.ts.map +1 -0
  164. package/dist/core/verified-run/recovery.js +115 -0
  165. package/dist/core/verified-run/recovery.js.map +1 -0
  166. package/dist/core/verified-run/run-types.d.ts +103 -0
  167. package/dist/core/verified-run/run-types.d.ts.map +1 -0
  168. package/dist/core/verified-run/run-types.js +2 -0
  169. package/dist/core/verified-run/run-types.js.map +1 -0
  170. package/dist/core/verified-run/scripted-writer.d.ts +15 -0
  171. package/dist/core/verified-run/scripted-writer.d.ts.map +1 -0
  172. package/dist/core/verified-run/scripted-writer.js +94 -0
  173. package/dist/core/verified-run/scripted-writer.js.map +1 -0
  174. package/dist/core/verified-run/session-port.d.ts +27 -0
  175. package/dist/core/verified-run/session-port.d.ts.map +1 -0
  176. package/dist/core/verified-run/session-port.js +2 -0
  177. package/dist/core/verified-run/session-port.js.map +1 -0
  178. package/dist/core/verified-run/storage.d.ts +15 -0
  179. package/dist/core/verified-run/storage.d.ts.map +1 -0
  180. package/dist/core/verified-run/storage.js +96 -0
  181. package/dist/core/verified-run/storage.js.map +1 -0
  182. package/dist/core/verified-run/verification-phase.d.ts +5 -0
  183. package/dist/core/verified-run/verification-phase.d.ts.map +1 -0
  184. package/dist/core/verified-run/verification-phase.js +56 -0
  185. package/dist/core/verified-run/verification-phase.js.map +1 -0
  186. package/dist/core/verified-run/work-recovery.d.ts +8 -0
  187. package/dist/core/verified-run/work-recovery.d.ts.map +1 -0
  188. package/dist/core/verified-run/work-recovery.js +44 -0
  189. package/dist/core/verified-run/work-recovery.js.map +1 -0
  190. package/dist/core/verified-run/writer-completion.d.ts +4 -0
  191. package/dist/core/verified-run/writer-completion.d.ts.map +1 -0
  192. package/dist/core/verified-run/writer-completion.js +27 -0
  193. package/dist/core/verified-run/writer-completion.js.map +1 -0
  194. package/dist/core/verified-run/writer-phase.d.ts +8 -0
  195. package/dist/core/verified-run/writer-phase.d.ts.map +1 -0
  196. package/dist/core/verified-run/writer-phase.js +76 -0
  197. package/dist/core/verified-run/writer-phase.js.map +1 -0
  198. package/dist/core/verified-run/writer-projection.d.ts +11 -0
  199. package/dist/core/verified-run/writer-projection.d.ts.map +1 -0
  200. package/dist/core/verified-run/writer-projection.js +70 -0
  201. package/dist/core/verified-run/writer-projection.js.map +1 -0
  202. package/dist/core/verified-run/writer-recovery.d.ts +16 -0
  203. package/dist/core/verified-run/writer-recovery.d.ts.map +1 -0
  204. package/dist/core/verified-run/writer-recovery.js +107 -0
  205. package/dist/core/verified-run/writer-recovery.js.map +1 -0
  206. package/dist/core/workload-permit-pool.d.ts +1 -3
  207. package/dist/core/workload-permit-pool.d.ts.map +1 -1
  208. package/dist/core/workload-permit-pool.js +11 -11
  209. package/dist/core/workload-permit-pool.js.map +1 -1
  210. package/dist/index.d.ts +3 -2
  211. package/dist/index.d.ts.map +1 -1
  212. package/dist/index.js +2 -2
  213. package/dist/index.js.map +1 -1
  214. package/dist/main.d.ts.map +1 -1
  215. package/dist/main.js +2 -8
  216. package/dist/main.js.map +1 -1
  217. package/dist/modes/interactive/components/session-failure.d.ts +13 -0
  218. package/dist/modes/interactive/components/session-failure.d.ts.map +1 -0
  219. package/dist/modes/interactive/components/session-failure.js +81 -0
  220. package/dist/modes/interactive/components/session-failure.js.map +1 -0
  221. package/dist/modes/interactive/interactive-mode.d.ts +1 -0
  222. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  223. package/dist/modes/interactive/interactive-mode.js +45 -31
  224. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  225. package/dist/modes/interactive/tui-diagnostics.d.ts +36 -0
  226. package/dist/modes/interactive/tui-diagnostics.d.ts.map +1 -0
  227. package/dist/modes/interactive/tui-diagnostics.js +105 -0
  228. package/dist/modes/interactive/tui-diagnostics.js.map +1 -0
  229. package/dist/modes/interactive/tui-runtime-info.d.ts +20 -0
  230. package/dist/modes/interactive/tui-runtime-info.d.ts.map +1 -0
  231. package/dist/modes/interactive/tui-runtime-info.js +76 -0
  232. package/dist/modes/interactive/tui-runtime-info.js.map +1 -0
  233. package/docs/development.md +10 -0
  234. package/docs/keybindings.md +1 -1
  235. package/docs/release-audit-0.98.5.md +84 -0
  236. package/docs/run-protocol.md +33 -1
  237. package/docs/runtime-algorithms.md +26 -0
  238. package/docs/sdk.md +193 -0
  239. package/docs/usage.md +54 -0
  240. package/docs/verified-run-testing.md +417 -0
  241. package/docs/verified-run.md +388 -0
  242. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  243. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  244. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  245. package/examples/extensions/gondolin/package-lock.json +2 -2
  246. package/examples/extensions/gondolin/package.json +1 -1
  247. package/examples/extensions/sandbox/package-lock.json +2 -2
  248. package/examples/extensions/sandbox/package.json +1 -1
  249. package/examples/extensions/with-deps/package-lock.json +2 -2
  250. package/examples/extensions/with-deps/package.json +1 -1
  251. package/npm-shrinkwrap.json +18 -18
  252. package/package.json +6 -6
@@ -1 +1 @@
1
- {"version":3,"file":"session-run-termination.js","sourceRoot":"","sources":["../../src/core/session-run-termination.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentMessage } from \"omk-agent-core\";\nimport type { Api, AssistantMessage, Model } from \"omk-ai\";\nimport { providerFailureCause, terminationMessage } from \"./session-failure-cause.ts\";\nimport {\n\ttype ClassifySessionTerminationInput,\n\tclassifySessionTermination,\n\ttype SessionTermination,\n\ttype SessionTerminationCause,\n} from \"./session-termination.ts\";\n\ninterface RunTerminationContext extends Pick<ClassifySessionTerminationInput, \"sessionId\" | \"runId\" | \"timestamp\"> {\n\treadonly model?: Pick<Model<Api>, \"provider\" | \"id\" | \"contextWindow\">;\n\treadonly elevatedRisk: boolean;\n\treadonly userAbortRequested: boolean;\n\treadonly pendingCause?: SessionTerminationCause;\n\treadonly toolTimeout?: {\n\t\treadonly toolCallId: string;\n\t\treadonly toolName: string;\n\t\treadonly executionStarted: boolean;\n\t};\n}\n\n/** Translate one settled core run into a cause; lifecycle persistence stays with AgentSession. */\nexport function classifyRunTermination(\n\tmessages: readonly AgentMessage[],\n\tcontext: RunTerminationContext,\n): SessionTermination {\n\tlet assistant: AssistantMessage | undefined;\n\tfor (let index = messages.length - 1; index >= 0; index--) {\n\t\tconst candidate = messages[index];\n\t\tif (candidate?.role === \"assistant\") {\n\t\t\tassistant = candidate;\n\t\t\tbreak;\n\t\t}\n\t}\n\tlet cause: SessionTerminationCause;\n\tlet message: string;\n\tlet sideEffects: \"none\" | \"possible\" = context.elevatedRisk ? \"possible\" : \"none\";\n\tlet toolCallId: string | undefined;\n\tlet toolName: string | undefined;\n\n\tif (context.toolTimeout) {\n\t\tcause = { area: \"tool\", code: \"timeout\" };\n\t\tmessage = `Tool ${context.toolTimeout.toolName} timed out.`;\n\t\ttoolCallId = context.toolTimeout.toolCallId;\n\t\ttoolName = context.toolTimeout.toolName;\n\t\tsideEffects = context.toolTimeout.executionStarted ? \"possible\" : sideEffects;\n\t} else if (context.pendingCause?.area === \"configuration\") {\n\t\tcause = context.pendingCause;\n\t\tmessage = \"Model dispatch was rejected by the configured model contract.\";\n\t} else if (!assistant) {\n\t\tcause = { area: \"internal\", code: \"unclassified\" };\n\t\tmessage = \"Agent run ended without an assistant result.\";\n\t} else if (assistant.stopReason === \"aborted\") {\n\t\tcause = context.userAbortRequested ? { area: \"user\", code: \"abort\" } : { area: \"provider\", code: \"abort\" };\n\t\tmessage = terminationMessage(\n\t\t\tassistant.errorMessage,\n\t\t\tcontext.userAbortRequested ? \"The user aborted the run.\" : \"The provider aborted the run.\",\n\t\t);\n\t} else if (assistant.stopReason === \"error\") {\n\t\tcause = providerFailureCause(assistant, context.model?.contextWindow ?? 0);\n\t\tmessage = terminationMessage(assistant.errorMessage, \"The provider request failed.\");\n\t} else {\n\t\tcause = { area: \"completed\" };\n\t\tmessage = \"Run completed.\";\n\t}\n\tconst provider = assistant?.provider || context.model?.provider;\n\tconst model = assistant?.model || context.model?.id;\n\treturn classifySessionTermination({\n\t\tsessionId: context.sessionId,\n\t\trunId: context.runId,\n\t\ttimestamp: context.timestamp,\n\t\tsource: \"observed\",\n\t\tmessage,\n\t\tcause,\n\t\tsideEffects,\n\t\t...(provider ? { provider } : {}),\n\t\t...(model ? { model } : {}),\n\t\t...(toolCallId ? { toolCallId } : {}),\n\t\t...(toolName ? { toolName } : {}),\n\t});\n}\n"]}
1
+ {"version":3,"file":"session-run-termination.js","sourceRoot":"","sources":["../../src/core/session-run-termination.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentMessage } from \"omk-agent-core\";\nimport type { Api, AssistantMessage, Model } from \"omk-ai\";\nimport { providerFailureCause, terminationMessage } from \"./session-failure-cause.ts\";\nimport {\n\ttype ClassifySessionTerminationInput,\n\tclassifySessionTermination,\n\ttype SessionTermination,\n\ttype SessionTerminationCause,\n} from \"./session-termination.ts\";\n\ninterface RunTerminationContext extends Pick<ClassifySessionTerminationInput, \"sessionId\" | \"runId\" | \"timestamp\"> {\n\treadonly model?: Pick<Model<Api>, \"provider\" | \"id\" | \"contextWindow\">;\n\treadonly elevatedRisk: boolean;\n\treadonly userAbortRequested: boolean;\n\treadonly pendingCause?: SessionTerminationCause;\n\treadonly toolTimeout?: {\n\t\treadonly toolCallId: string;\n\t\treadonly toolName: string;\n\t\treadonly executionStarted: boolean;\n\t};\n}\n\n/** Translate one settled core run into a cause; lifecycle persistence stays with AgentSession. */\nexport function classifyRunTermination(\n\tmessages: readonly AgentMessage[],\n\tcontext: RunTerminationContext,\n): SessionTermination {\n\tlet assistant: AssistantMessage | undefined;\n\tfor (let index = messages.length - 1; index >= 0; index--) {\n\t\tconst candidate = messages[index];\n\t\tif (candidate?.role === \"assistant\") {\n\t\t\tassistant = candidate;\n\t\t\tbreak;\n\t\t}\n\t}\n\tlet cause: SessionTerminationCause;\n\tlet message: string;\n\tlet sideEffects: \"none\" | \"possible\" = context.elevatedRisk ? \"possible\" : \"none\";\n\tlet toolCallId: string | undefined;\n\tlet toolName: string | undefined;\n\n\tif (context.pendingCause?.area === \"budget\") {\n\t\tcause = context.pendingCause;\n\t\tmessage = `Run budget exhausted: ${context.pendingCause.code}`;\n\t\tsideEffects = \"possible\";\n\t} else if (context.toolTimeout) {\n\t\tcause = { area: \"tool\", code: \"timeout\" };\n\t\tmessage = `Tool ${context.toolTimeout.toolName} timed out.`;\n\t\ttoolCallId = context.toolTimeout.toolCallId;\n\t\ttoolName = context.toolTimeout.toolName;\n\t\tsideEffects = context.toolTimeout.executionStarted ? \"possible\" : sideEffects;\n\t} else if (context.pendingCause?.area === \"configuration\") {\n\t\tcause = context.pendingCause;\n\t\tmessage = \"Model dispatch was rejected by the configured model contract.\";\n\t} else if (context.userAbortRequested) {\n\t\tcause = { area: \"user\", code: \"abort\" };\n\t\tmessage = \"The user aborted the run.\";\n\t\tif (messages.some((entry) => entry.role === \"toolResult\")) sideEffects = \"possible\";\n\t} else if (!assistant) {\n\t\tcause = { area: \"internal\", code: \"unclassified\" };\n\t\tmessage = \"Agent run ended without an assistant result.\";\n\t} else if (assistant.stopReason === \"aborted\") {\n\t\tcause = { area: \"provider\", code: \"abort\" };\n\t\tmessage = terminationMessage(assistant.errorMessage, \"The provider aborted the run.\");\n\t} else if (assistant.stopReason === \"error\") {\n\t\tcause = providerFailureCause(assistant, context.model?.contextWindow ?? 0);\n\t\tmessage = terminationMessage(assistant.errorMessage, \"The provider request failed.\");\n\t} else {\n\t\tcause = { area: \"completed\" };\n\t\tmessage = \"Run completed.\";\n\t}\n\tconst provider = assistant?.provider || context.model?.provider;\n\tconst model = assistant?.model || context.model?.id;\n\treturn classifySessionTermination({\n\t\tsessionId: context.sessionId,\n\t\trunId: context.runId,\n\t\ttimestamp: context.timestamp,\n\t\tsource: \"observed\",\n\t\tmessage,\n\t\tcause,\n\t\tsideEffects,\n\t\t...(provider ? { provider } : {}),\n\t\t...(model ? { model } : {}),\n\t\t...(toolCallId ? { toolCallId } : {}),\n\t\t...(toolName ? { toolName } : {}),\n\t});\n}\n"]}
@@ -0,0 +1,97 @@
1
+ import type { RunBudgetStopCode } from "./run-budget-policy.ts";
2
+ export declare const SESSION_TERMINATION_SCHEMA_VERSION: 1;
3
+ export declare const MAX_SESSION_TERMINATION_MESSAGE_LENGTH = 512;
4
+ /** The journal validator derives its accepted kinds from this tuple. */
5
+ export declare const SESSION_TERMINATION_KIND_VALUES: readonly ["completed", "user_abort", "provider_abort", "provider_auth", "provider_rate_limit", "provider_network", "provider_protocol", "provider_refusal", "context_overflow", "transcript_invalid", "tool_timeout", "tool_fatal", "compaction", "persistence", "process_signal", "process_crash", "configuration", "internal_error", "resource_pressure", "budget_exhausted"];
6
+ export type SessionTerminationKind = (typeof SESSION_TERMINATION_KIND_VALUES)[number];
7
+ export type SessionTerminationPhase = "completed" | "control" | "preflight" | "provider" | "tool" | "compaction" | "persistence" | "process" | "resume";
8
+ export type SessionTerminationSource = "observed" | "inferred_on_resume";
9
+ export type SessionSideEffects = "none" | "possible" | "confirmed";
10
+ export type SessionProcessSignal = "SIGINT" | "SIGTERM" | "SIGHUP" | "SIGQUIT";
11
+ export type ProviderTerminationCauseCode = "abort" | "auth" | "rate_limit" | "network" | "protocol" | "refusal" | "context_overflow";
12
+ export type ToolTerminationCauseCode = "timeout" | "fatal";
13
+ export type ResourceTerminationCauseCode = "memory" | "disk" | "cpu" | "heap" | "probe_unavailable" | "queue_overflow";
14
+ export type CompactionTerminationCauseCode = "aborted" | "failed" | "stale" | "quota_exhausted";
15
+ export type PersistenceTerminationCauseCode = "read_failed" | "append_failed" | "replace_failed" | "fsync_failed" | "lock_failed";
16
+ export type TranscriptTerminationCauseCode = "missing_result" | "duplicate_result" | "orphan_result" | "duplicate_call_id" | "interleaved_non_result" | "invalid_jsonl" | "invalid_tree" | "unsupported_version" | "trailing_fragment";
17
+ export type SessionTerminationCauseCode = "session.completed" | "session.user_abort" | `provider.${ProviderTerminationCauseCode}` | `tool.${ToolTerminationCauseCode}` | `compaction.${CompactionTerminationCauseCode}` | `persistence.${PersistenceTerminationCauseCode}` | "process.signal" | "process.crash" | `transcript.${TranscriptTerminationCauseCode}` | "configuration.invalid" | "internal.unclassified" | `resource.${ResourceTerminationCauseCode}` | `budget.${RunBudgetStopCode}`;
18
+ export type SessionTerminationCause = {
19
+ readonly area: "completed";
20
+ } | {
21
+ readonly area: "user";
22
+ readonly code: "abort";
23
+ } | {
24
+ readonly area: "provider";
25
+ readonly code: ProviderTerminationCauseCode;
26
+ } | {
27
+ readonly area: "tool";
28
+ readonly code: ToolTerminationCauseCode;
29
+ } | {
30
+ readonly area: "compaction";
31
+ readonly code: CompactionTerminationCauseCode;
32
+ } | {
33
+ readonly area: "persistence";
34
+ readonly code: PersistenceTerminationCauseCode;
35
+ } | {
36
+ readonly area: "process";
37
+ readonly code: "signal";
38
+ readonly signal: SessionProcessSignal;
39
+ } | {
40
+ readonly area: "process";
41
+ readonly code: "crash";
42
+ } | {
43
+ readonly area: "transcript";
44
+ readonly code: TranscriptTerminationCauseCode;
45
+ } | {
46
+ readonly area: "configuration";
47
+ readonly code: "invalid";
48
+ } | {
49
+ readonly area: "internal";
50
+ readonly code: "unclassified";
51
+ } | {
52
+ readonly area: "resource";
53
+ readonly code: ResourceTerminationCauseCode;
54
+ } | {
55
+ readonly area: "budget";
56
+ readonly code: RunBudgetStopCode;
57
+ };
58
+ export interface ClassifySessionTerminationInput {
59
+ readonly sessionId: string;
60
+ readonly runId: string;
61
+ /** Deterministic caller-provided ISO-8601 timestamp. */
62
+ readonly timestamp: string;
63
+ readonly source: SessionTerminationSource;
64
+ /** Caller-supplied, pre-redacted diagnostic text. */
65
+ readonly message: string;
66
+ readonly cause: SessionTerminationCause;
67
+ readonly sideEffects: SessionSideEffects;
68
+ readonly retryAfterMs?: number;
69
+ readonly provider?: string;
70
+ readonly model?: string;
71
+ readonly toolCallId?: string;
72
+ readonly toolName?: string;
73
+ }
74
+ export interface SessionTermination {
75
+ readonly schemaVersion: typeof SESSION_TERMINATION_SCHEMA_VERSION;
76
+ readonly sessionId: string;
77
+ readonly runId: string;
78
+ readonly kind: SessionTerminationKind;
79
+ readonly phase: SessionTerminationPhase;
80
+ readonly source: SessionTerminationSource;
81
+ readonly message: string;
82
+ readonly causeCode: SessionTerminationCauseCode;
83
+ /** Stable operator guidance suitable for print, JSON, RPC, and TUI surfaces. */
84
+ readonly nextAction: string;
85
+ readonly retryable: boolean;
86
+ readonly safeToAutoRetry: boolean;
87
+ readonly sideEffects: SessionSideEffects;
88
+ readonly timestamp: string;
89
+ readonly retryAfterMs?: number;
90
+ readonly provider?: string;
91
+ readonly model?: string;
92
+ readonly toolCallId?: string;
93
+ readonly toolName?: string;
94
+ readonly processSignal?: SessionProcessSignal;
95
+ readonly transcriptIssue?: TranscriptTerminationCauseCode;
96
+ }
97
+ //# sourceMappingURL=session-termination-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-termination-types.d.ts","sourceRoot":"","sources":["../../src/core/session-termination-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAEhE,eAAO,MAAM,kCAAkC,GAAa,CAAC;AAC7D,eAAO,MAAM,sCAAsC,MAAM,CAAC;AAE1D,wEAAwE;AACxE,eAAO,MAAM,+BAA+B,iXAqBlC,CAAC;AACX,MAAM,MAAM,sBAAsB,GAAG,CAAC,OAAO,+BAA+B,CAAC,CAAC,MAAM,CAAC,CAAC;AACtF,MAAM,MAAM,uBAAuB,GAChC,WAAW,GACX,SAAS,GACT,WAAW,GACX,UAAU,GACV,MAAM,GACN,YAAY,GACZ,aAAa,GACb,SAAS,GACT,QAAQ,CAAC;AACZ,MAAM,MAAM,wBAAwB,GAAG,UAAU,GAAG,oBAAoB,CAAC;AACzE,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,UAAU,GAAG,WAAW,CAAC;AACnE,MAAM,MAAM,oBAAoB,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;AAC/E,MAAM,MAAM,4BAA4B,GACrC,OAAO,GACP,MAAM,GACN,YAAY,GACZ,SAAS,GACT,UAAU,GACV,SAAS,GACT,kBAAkB,CAAC;AACtB,MAAM,MAAM,wBAAwB,GAAG,SAAS,GAAG,OAAO,CAAC;AAC3D,MAAM,MAAM,4BAA4B,GAAG,QAAQ,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,mBAAmB,GAAG,gBAAgB,CAAC;AACvH,MAAM,MAAM,8BAA8B,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,iBAAiB,CAAC;AAChG,MAAM,MAAM,+BAA+B,GACxC,aAAa,GACb,eAAe,GACf,gBAAgB,GAChB,cAAc,GACd,aAAa,CAAC;AACjB,MAAM,MAAM,8BAA8B,GACvC,gBAAgB,GAChB,kBAAkB,GAClB,eAAe,GACf,mBAAmB,GACnB,wBAAwB,GACxB,eAAe,GACf,cAAc,GACd,qBAAqB,GACrB,mBAAmB,CAAC;AACvB,MAAM,MAAM,2BAA2B,GACpC,mBAAmB,GACnB,oBAAoB,GACpB,YAAY,4BAA4B,EAAE,GAC1C,QAAQ,wBAAwB,EAAE,GAClC,cAAc,8BAA8B,EAAE,GAC9C,eAAe,+BAA+B,EAAE,GAChD,gBAAgB,GAChB,eAAe,GACf,cAAc,8BAA8B,EAAE,GAC9C,uBAAuB,GACvB,uBAAuB,GACvB,YAAY,4BAA4B,EAAE,GAC1C,UAAU,iBAAiB,EAAE,CAAC;AAEjC,MAAM,MAAM,uBAAuB,GAChC;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAA;CAAE,GAC9B;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GACjD;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,4BAA4B,CAAA;CAAE,GAC1E;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,wBAAwB,CAAA;CAAE,GAClE;IAAE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,8BAA8B,CAAA;CAAE,GAC9E;IAAE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,+BAA+B,CAAA;CAAE,GAChF;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,oBAAoB,CAAA;CAAE,GAC5F;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GACpD;IAAE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,8BAA8B,CAAA;CAAE,GAC9E;IAAE,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;CAAE,GAC5D;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAA;CAAE,GAC5D;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,4BAA4B,CAAA;CAAE,GAC1E;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAA;CAAE,CAAC;AAEjE,MAAM,WAAW,+BAA+B;IAC/C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,wDAAwD;IACxD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,wBAAwB,CAAC;IAC1C,qDAAqD;IACrD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,uBAAuB,CAAC;IACxC,QAAQ,CAAC,WAAW,EAAE,kBAAkB,CAAC;IACzC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,aAAa,EAAE,OAAO,kCAAkC,CAAC;IAClE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,sBAAsB,CAAC;IACtC,QAAQ,CAAC,KAAK,EAAE,uBAAuB,CAAC;IACxC,QAAQ,CAAC,MAAM,EAAE,wBAAwB,CAAC;IAC1C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,2BAA2B,CAAC;IAChD,gFAAgF;IAChF,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;IAClC,QAAQ,CAAC,WAAW,EAAE,kBAAkB,CAAC;IACzC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,aAAa,CAAC,EAAE,oBAAoB,CAAC;IAC9C,QAAQ,CAAC,eAAe,CAAC,EAAE,8BAA8B,CAAC;CAC1D","sourcesContent":["import type { RunBudgetStopCode } from \"./run-budget-policy.ts\";\n\nexport const SESSION_TERMINATION_SCHEMA_VERSION = 1 as const;\nexport const MAX_SESSION_TERMINATION_MESSAGE_LENGTH = 512;\n\n/** The journal validator derives its accepted kinds from this tuple. */\nexport const SESSION_TERMINATION_KIND_VALUES = [\n\t\"completed\",\n\t\"user_abort\",\n\t\"provider_abort\",\n\t\"provider_auth\",\n\t\"provider_rate_limit\",\n\t\"provider_network\",\n\t\"provider_protocol\",\n\t\"provider_refusal\",\n\t\"context_overflow\",\n\t\"transcript_invalid\",\n\t\"tool_timeout\",\n\t\"tool_fatal\",\n\t\"compaction\",\n\t\"persistence\",\n\t\"process_signal\",\n\t\"process_crash\",\n\t\"configuration\",\n\t\"internal_error\",\n\t\"resource_pressure\",\n\t\"budget_exhausted\",\n] as const;\nexport type SessionTerminationKind = (typeof SESSION_TERMINATION_KIND_VALUES)[number];\nexport type SessionTerminationPhase =\n\t| \"completed\"\n\t| \"control\"\n\t| \"preflight\"\n\t| \"provider\"\n\t| \"tool\"\n\t| \"compaction\"\n\t| \"persistence\"\n\t| \"process\"\n\t| \"resume\";\nexport type SessionTerminationSource = \"observed\" | \"inferred_on_resume\";\nexport type SessionSideEffects = \"none\" | \"possible\" | \"confirmed\";\nexport type SessionProcessSignal = \"SIGINT\" | \"SIGTERM\" | \"SIGHUP\" | \"SIGQUIT\";\nexport type ProviderTerminationCauseCode =\n\t| \"abort\"\n\t| \"auth\"\n\t| \"rate_limit\"\n\t| \"network\"\n\t| \"protocol\"\n\t| \"refusal\"\n\t| \"context_overflow\";\nexport type ToolTerminationCauseCode = \"timeout\" | \"fatal\";\nexport type ResourceTerminationCauseCode = \"memory\" | \"disk\" | \"cpu\" | \"heap\" | \"probe_unavailable\" | \"queue_overflow\";\nexport type CompactionTerminationCauseCode = \"aborted\" | \"failed\" | \"stale\" | \"quota_exhausted\";\nexport type PersistenceTerminationCauseCode =\n\t| \"read_failed\"\n\t| \"append_failed\"\n\t| \"replace_failed\"\n\t| \"fsync_failed\"\n\t| \"lock_failed\";\nexport type TranscriptTerminationCauseCode =\n\t| \"missing_result\"\n\t| \"duplicate_result\"\n\t| \"orphan_result\"\n\t| \"duplicate_call_id\"\n\t| \"interleaved_non_result\"\n\t| \"invalid_jsonl\"\n\t| \"invalid_tree\"\n\t| \"unsupported_version\"\n\t| \"trailing_fragment\";\nexport type SessionTerminationCauseCode =\n\t| \"session.completed\"\n\t| \"session.user_abort\"\n\t| `provider.${ProviderTerminationCauseCode}`\n\t| `tool.${ToolTerminationCauseCode}`\n\t| `compaction.${CompactionTerminationCauseCode}`\n\t| `persistence.${PersistenceTerminationCauseCode}`\n\t| \"process.signal\"\n\t| \"process.crash\"\n\t| `transcript.${TranscriptTerminationCauseCode}`\n\t| \"configuration.invalid\"\n\t| \"internal.unclassified\"\n\t| `resource.${ResourceTerminationCauseCode}`\n\t| `budget.${RunBudgetStopCode}`;\n\nexport type SessionTerminationCause =\n\t| { readonly area: \"completed\" }\n\t| { readonly area: \"user\"; readonly code: \"abort\" }\n\t| { readonly area: \"provider\"; readonly code: ProviderTerminationCauseCode }\n\t| { readonly area: \"tool\"; readonly code: ToolTerminationCauseCode }\n\t| { readonly area: \"compaction\"; readonly code: CompactionTerminationCauseCode }\n\t| { readonly area: \"persistence\"; readonly code: PersistenceTerminationCauseCode }\n\t| { readonly area: \"process\"; readonly code: \"signal\"; readonly signal: SessionProcessSignal }\n\t| { readonly area: \"process\"; readonly code: \"crash\" }\n\t| { readonly area: \"transcript\"; readonly code: TranscriptTerminationCauseCode }\n\t| { readonly area: \"configuration\"; readonly code: \"invalid\" }\n\t| { readonly area: \"internal\"; readonly code: \"unclassified\" }\n\t| { readonly area: \"resource\"; readonly code: ResourceTerminationCauseCode }\n\t| { readonly area: \"budget\"; readonly code: RunBudgetStopCode };\n\nexport interface ClassifySessionTerminationInput {\n\treadonly sessionId: string;\n\treadonly runId: string;\n\t/** Deterministic caller-provided ISO-8601 timestamp. */\n\treadonly timestamp: string;\n\treadonly source: SessionTerminationSource;\n\t/** Caller-supplied, pre-redacted diagnostic text. */\n\treadonly message: string;\n\treadonly cause: SessionTerminationCause;\n\treadonly sideEffects: SessionSideEffects;\n\treadonly retryAfterMs?: number;\n\treadonly provider?: string;\n\treadonly model?: string;\n\treadonly toolCallId?: string;\n\treadonly toolName?: string;\n}\n\nexport interface SessionTermination {\n\treadonly schemaVersion: typeof SESSION_TERMINATION_SCHEMA_VERSION;\n\treadonly sessionId: string;\n\treadonly runId: string;\n\treadonly kind: SessionTerminationKind;\n\treadonly phase: SessionTerminationPhase;\n\treadonly source: SessionTerminationSource;\n\treadonly message: string;\n\treadonly causeCode: SessionTerminationCauseCode;\n\t/** Stable operator guidance suitable for print, JSON, RPC, and TUI surfaces. */\n\treadonly nextAction: string;\n\treadonly retryable: boolean;\n\treadonly safeToAutoRetry: boolean;\n\treadonly sideEffects: SessionSideEffects;\n\treadonly timestamp: string;\n\treadonly retryAfterMs?: number;\n\treadonly provider?: string;\n\treadonly model?: string;\n\treadonly toolCallId?: string;\n\treadonly toolName?: string;\n\treadonly processSignal?: SessionProcessSignal;\n\treadonly transcriptIssue?: TranscriptTerminationCauseCode;\n}\n"]}
@@ -0,0 +1,26 @@
1
+ export const SESSION_TERMINATION_SCHEMA_VERSION = 1;
2
+ export const MAX_SESSION_TERMINATION_MESSAGE_LENGTH = 512;
3
+ /** The journal validator derives its accepted kinds from this tuple. */
4
+ export const SESSION_TERMINATION_KIND_VALUES = [
5
+ "completed",
6
+ "user_abort",
7
+ "provider_abort",
8
+ "provider_auth",
9
+ "provider_rate_limit",
10
+ "provider_network",
11
+ "provider_protocol",
12
+ "provider_refusal",
13
+ "context_overflow",
14
+ "transcript_invalid",
15
+ "tool_timeout",
16
+ "tool_fatal",
17
+ "compaction",
18
+ "persistence",
19
+ "process_signal",
20
+ "process_crash",
21
+ "configuration",
22
+ "internal_error",
23
+ "resource_pressure",
24
+ "budget_exhausted",
25
+ ];
26
+ //# sourceMappingURL=session-termination-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-termination-types.js","sourceRoot":"","sources":["../../src/core/session-termination-types.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,kCAAkC,GAAG,CAAU,CAAC;AAC7D,MAAM,CAAC,MAAM,sCAAsC,GAAG,GAAG,CAAC;AAE1D,wEAAwE;AACxE,MAAM,CAAC,MAAM,+BAA+B,GAAG;IAC9C,WAAW;IACX,YAAY;IACZ,gBAAgB;IAChB,eAAe;IACf,qBAAqB;IACrB,kBAAkB;IAClB,mBAAmB;IACnB,kBAAkB;IAClB,kBAAkB;IAClB,oBAAoB;IACpB,cAAc;IACd,YAAY;IACZ,YAAY;IACZ,aAAa;IACb,gBAAgB;IAChB,eAAe;IACf,eAAe;IACf,gBAAgB;IAChB,mBAAmB;IACnB,kBAAkB;CACT,CAAC","sourcesContent":["import type { RunBudgetStopCode } from \"./run-budget-policy.ts\";\n\nexport const SESSION_TERMINATION_SCHEMA_VERSION = 1 as const;\nexport const MAX_SESSION_TERMINATION_MESSAGE_LENGTH = 512;\n\n/** The journal validator derives its accepted kinds from this tuple. */\nexport const SESSION_TERMINATION_KIND_VALUES = [\n\t\"completed\",\n\t\"user_abort\",\n\t\"provider_abort\",\n\t\"provider_auth\",\n\t\"provider_rate_limit\",\n\t\"provider_network\",\n\t\"provider_protocol\",\n\t\"provider_refusal\",\n\t\"context_overflow\",\n\t\"transcript_invalid\",\n\t\"tool_timeout\",\n\t\"tool_fatal\",\n\t\"compaction\",\n\t\"persistence\",\n\t\"process_signal\",\n\t\"process_crash\",\n\t\"configuration\",\n\t\"internal_error\",\n\t\"resource_pressure\",\n\t\"budget_exhausted\",\n] as const;\nexport type SessionTerminationKind = (typeof SESSION_TERMINATION_KIND_VALUES)[number];\nexport type SessionTerminationPhase =\n\t| \"completed\"\n\t| \"control\"\n\t| \"preflight\"\n\t| \"provider\"\n\t| \"tool\"\n\t| \"compaction\"\n\t| \"persistence\"\n\t| \"process\"\n\t| \"resume\";\nexport type SessionTerminationSource = \"observed\" | \"inferred_on_resume\";\nexport type SessionSideEffects = \"none\" | \"possible\" | \"confirmed\";\nexport type SessionProcessSignal = \"SIGINT\" | \"SIGTERM\" | \"SIGHUP\" | \"SIGQUIT\";\nexport type ProviderTerminationCauseCode =\n\t| \"abort\"\n\t| \"auth\"\n\t| \"rate_limit\"\n\t| \"network\"\n\t| \"protocol\"\n\t| \"refusal\"\n\t| \"context_overflow\";\nexport type ToolTerminationCauseCode = \"timeout\" | \"fatal\";\nexport type ResourceTerminationCauseCode = \"memory\" | \"disk\" | \"cpu\" | \"heap\" | \"probe_unavailable\" | \"queue_overflow\";\nexport type CompactionTerminationCauseCode = \"aborted\" | \"failed\" | \"stale\" | \"quota_exhausted\";\nexport type PersistenceTerminationCauseCode =\n\t| \"read_failed\"\n\t| \"append_failed\"\n\t| \"replace_failed\"\n\t| \"fsync_failed\"\n\t| \"lock_failed\";\nexport type TranscriptTerminationCauseCode =\n\t| \"missing_result\"\n\t| \"duplicate_result\"\n\t| \"orphan_result\"\n\t| \"duplicate_call_id\"\n\t| \"interleaved_non_result\"\n\t| \"invalid_jsonl\"\n\t| \"invalid_tree\"\n\t| \"unsupported_version\"\n\t| \"trailing_fragment\";\nexport type SessionTerminationCauseCode =\n\t| \"session.completed\"\n\t| \"session.user_abort\"\n\t| `provider.${ProviderTerminationCauseCode}`\n\t| `tool.${ToolTerminationCauseCode}`\n\t| `compaction.${CompactionTerminationCauseCode}`\n\t| `persistence.${PersistenceTerminationCauseCode}`\n\t| \"process.signal\"\n\t| \"process.crash\"\n\t| `transcript.${TranscriptTerminationCauseCode}`\n\t| \"configuration.invalid\"\n\t| \"internal.unclassified\"\n\t| `resource.${ResourceTerminationCauseCode}`\n\t| `budget.${RunBudgetStopCode}`;\n\nexport type SessionTerminationCause =\n\t| { readonly area: \"completed\" }\n\t| { readonly area: \"user\"; readonly code: \"abort\" }\n\t| { readonly area: \"provider\"; readonly code: ProviderTerminationCauseCode }\n\t| { readonly area: \"tool\"; readonly code: ToolTerminationCauseCode }\n\t| { readonly area: \"compaction\"; readonly code: CompactionTerminationCauseCode }\n\t| { readonly area: \"persistence\"; readonly code: PersistenceTerminationCauseCode }\n\t| { readonly area: \"process\"; readonly code: \"signal\"; readonly signal: SessionProcessSignal }\n\t| { readonly area: \"process\"; readonly code: \"crash\" }\n\t| { readonly area: \"transcript\"; readonly code: TranscriptTerminationCauseCode }\n\t| { readonly area: \"configuration\"; readonly code: \"invalid\" }\n\t| { readonly area: \"internal\"; readonly code: \"unclassified\" }\n\t| { readonly area: \"resource\"; readonly code: ResourceTerminationCauseCode }\n\t| { readonly area: \"budget\"; readonly code: RunBudgetStopCode };\n\nexport interface ClassifySessionTerminationInput {\n\treadonly sessionId: string;\n\treadonly runId: string;\n\t/** Deterministic caller-provided ISO-8601 timestamp. */\n\treadonly timestamp: string;\n\treadonly source: SessionTerminationSource;\n\t/** Caller-supplied, pre-redacted diagnostic text. */\n\treadonly message: string;\n\treadonly cause: SessionTerminationCause;\n\treadonly sideEffects: SessionSideEffects;\n\treadonly retryAfterMs?: number;\n\treadonly provider?: string;\n\treadonly model?: string;\n\treadonly toolCallId?: string;\n\treadonly toolName?: string;\n}\n\nexport interface SessionTermination {\n\treadonly schemaVersion: typeof SESSION_TERMINATION_SCHEMA_VERSION;\n\treadonly sessionId: string;\n\treadonly runId: string;\n\treadonly kind: SessionTerminationKind;\n\treadonly phase: SessionTerminationPhase;\n\treadonly source: SessionTerminationSource;\n\treadonly message: string;\n\treadonly causeCode: SessionTerminationCauseCode;\n\t/** Stable operator guidance suitable for print, JSON, RPC, and TUI surfaces. */\n\treadonly nextAction: string;\n\treadonly retryable: boolean;\n\treadonly safeToAutoRetry: boolean;\n\treadonly sideEffects: SessionSideEffects;\n\treadonly timestamp: string;\n\treadonly retryAfterMs?: number;\n\treadonly provider?: string;\n\treadonly model?: string;\n\treadonly toolCallId?: string;\n\treadonly toolName?: string;\n\treadonly processSignal?: SessionProcessSignal;\n\treadonly transcriptIssue?: TranscriptTerminationCauseCode;\n}\n"]}
@@ -1,104 +1,10 @@
1
- export declare const SESSION_TERMINATION_SCHEMA_VERSION: 1;
2
- export declare const MAX_SESSION_TERMINATION_MESSAGE_LENGTH = 512;
3
- /**
4
- * Canonical list of termination kinds. The run-journal validator derives its
5
- * runtime bounds from this tuple so a newly added kind can never crash
6
- * journaling with "termination kind is out of bounds" again.
7
- */
8
- export declare const SESSION_TERMINATION_KIND_VALUES: readonly ["completed", "user_abort", "provider_abort", "provider_auth", "provider_rate_limit", "provider_network", "provider_protocol", "provider_refusal", "context_overflow", "transcript_invalid", "tool_timeout", "tool_fatal", "compaction", "persistence", "process_signal", "process_crash", "configuration", "internal_error", "resource_pressure"];
9
- export type SessionTerminationKind = (typeof SESSION_TERMINATION_KIND_VALUES)[number];
10
- export type SessionTerminationPhase = "completed" | "control" | "preflight" | "provider" | "tool" | "compaction" | "persistence" | "process" | "resume";
11
- export type SessionTerminationSource = "observed" | "inferred_on_resume";
12
- export type SessionSideEffects = "none" | "possible" | "confirmed";
13
- export type SessionProcessSignal = "SIGINT" | "SIGTERM" | "SIGHUP" | "SIGQUIT";
14
- export type ProviderTerminationCauseCode = "abort" | "auth" | "rate_limit" | "network" | "protocol" | "refusal" | "context_overflow";
15
- export type ToolTerminationCauseCode = "timeout" | "fatal";
16
- /** §15.4 resource-aware runtime roadmap: host-pressure termination causes. */
17
- export type ResourceTerminationCauseCode = "memory" | "disk" | "cpu" | "heap" | "probe_unavailable" | "queue_overflow";
18
- export type CompactionTerminationCauseCode = "aborted" | "failed" | "stale" | "quota_exhausted";
19
- export type PersistenceTerminationCauseCode = "read_failed" | "append_failed" | "replace_failed" | "fsync_failed" | "lock_failed";
20
- export type TranscriptTerminationCauseCode = "missing_result" | "duplicate_result" | "orphan_result" | "duplicate_call_id" | "interleaved_non_result" | "invalid_jsonl" | "invalid_tree" | "unsupported_version" | "trailing_fragment";
21
- export type SessionTerminationCauseCode = "session.completed" | "session.user_abort" | `provider.${ProviderTerminationCauseCode}` | `tool.${ToolTerminationCauseCode}` | `compaction.${CompactionTerminationCauseCode}` | `persistence.${PersistenceTerminationCauseCode}` | "process.signal" | "process.crash" | `transcript.${TranscriptTerminationCauseCode}` | "configuration.invalid" | "internal.unclassified" | `resource.${ResourceTerminationCauseCode}`;
22
- export type SessionTerminationCause = {
23
- readonly area: "completed";
24
- } | {
25
- readonly area: "user";
26
- readonly code: "abort";
27
- } | {
28
- readonly area: "provider";
29
- readonly code: ProviderTerminationCauseCode;
30
- } | {
31
- readonly area: "tool";
32
- readonly code: ToolTerminationCauseCode;
33
- } | {
34
- readonly area: "compaction";
35
- readonly code: CompactionTerminationCauseCode;
36
- } | {
37
- readonly area: "persistence";
38
- readonly code: PersistenceTerminationCauseCode;
39
- } | {
40
- readonly area: "process";
41
- readonly code: "signal";
42
- readonly signal: SessionProcessSignal;
43
- } | {
44
- readonly area: "process";
45
- readonly code: "crash";
46
- } | {
47
- readonly area: "transcript";
48
- readonly code: TranscriptTerminationCauseCode;
49
- } | {
50
- readonly area: "configuration";
51
- readonly code: "invalid";
52
- } | {
53
- readonly area: "internal";
54
- readonly code: "unclassified";
55
- } | {
56
- readonly area: "resource";
57
- readonly code: ResourceTerminationCauseCode;
58
- };
59
- export interface ClassifySessionTerminationInput {
60
- readonly sessionId: string;
61
- readonly runId: string;
62
- /** Deterministic caller-provided ISO-8601 timestamp. */
63
- readonly timestamp: string;
64
- readonly source: SessionTerminationSource;
65
- /** Caller-supplied, pre-redacted diagnostic text. */
66
- readonly message: string;
67
- readonly cause: SessionTerminationCause;
68
- readonly sideEffects: SessionSideEffects;
69
- readonly retryAfterMs?: number;
70
- readonly provider?: string;
71
- readonly model?: string;
72
- readonly toolCallId?: string;
73
- readonly toolName?: string;
74
- }
75
- export interface SessionTermination {
76
- readonly schemaVersion: typeof SESSION_TERMINATION_SCHEMA_VERSION;
77
- readonly sessionId: string;
78
- readonly runId: string;
79
- readonly kind: SessionTerminationKind;
80
- readonly phase: SessionTerminationPhase;
81
- readonly source: SessionTerminationSource;
82
- readonly message: string;
83
- readonly causeCode: SessionTerminationCauseCode;
84
- /** Stable operator guidance suitable for print, JSON, RPC, and TUI surfaces. */
85
- readonly nextAction: string;
86
- readonly retryable: boolean;
87
- readonly safeToAutoRetry: boolean;
88
- readonly sideEffects: SessionSideEffects;
89
- readonly timestamp: string;
90
- readonly retryAfterMs?: number;
91
- readonly provider?: string;
92
- readonly model?: string;
93
- readonly toolCallId?: string;
94
- readonly toolName?: string;
95
- readonly processSignal?: SessionProcessSignal;
96
- readonly transcriptIssue?: TranscriptTerminationCauseCode;
97
- }
1
+ import { type ClassifySessionTerminationInput, type SessionProcessSignal, type SessionTermination, type SessionTerminationCause } from "./session-termination-types.ts";
2
+ export * from "./session-termination-types.ts";
98
3
  export declare class SessionTerminationError extends Error {
99
4
  readonly termination: SessionTermination;
100
5
  constructor(message: string, termination: SessionTermination);
101
6
  }
7
+ export declare function parseSessionTerminationCauseCode(code: string, signal?: SessionProcessSignal): SessionTerminationCause;
102
8
  /** Validate text at the termination trust boundary without attempting redaction. */
103
9
  export declare function assertPreRedactedTerminationMessage(message: string): void;
104
10
  /** Concise actionable rendering shared by non-JSON and TUI surfaces. */
@@ -1 +1 @@
1
- {"version":3,"file":"session-termination.d.ts","sourceRoot":"","sources":["../../src/core/session-termination.ts"],"names":[],"mappings":"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","sourcesContent":["export const SESSION_TERMINATION_SCHEMA_VERSION = 1 as const;\nexport const MAX_SESSION_TERMINATION_MESSAGE_LENGTH = 512;\n\n/**\n * Canonical list of termination kinds. The run-journal validator derives its\n * runtime bounds from this tuple so a newly added kind can never crash\n * journaling with \"termination kind is out of bounds\" again.\n */\nexport const SESSION_TERMINATION_KIND_VALUES = [\n\t\"completed\",\n\t\"user_abort\",\n\t\"provider_abort\",\n\t\"provider_auth\",\n\t\"provider_rate_limit\",\n\t\"provider_network\",\n\t\"provider_protocol\",\n\t\"provider_refusal\",\n\t\"context_overflow\",\n\t\"transcript_invalid\",\n\t\"tool_timeout\",\n\t\"tool_fatal\",\n\t\"compaction\",\n\t\"persistence\",\n\t\"process_signal\",\n\t\"process_crash\",\n\t\"configuration\",\n\t\"internal_error\",\n\t\"resource_pressure\",\n] as const;\n\nexport type SessionTerminationKind = (typeof SESSION_TERMINATION_KIND_VALUES)[number];\n\nexport type SessionTerminationPhase =\n\t| \"completed\"\n\t| \"control\"\n\t| \"preflight\"\n\t| \"provider\"\n\t| \"tool\"\n\t| \"compaction\"\n\t| \"persistence\"\n\t| \"process\"\n\t| \"resume\";\n\nexport type SessionTerminationSource = \"observed\" | \"inferred_on_resume\";\nexport type SessionSideEffects = \"none\" | \"possible\" | \"confirmed\";\nexport type SessionProcessSignal = \"SIGINT\" | \"SIGTERM\" | \"SIGHUP\" | \"SIGQUIT\";\n\nexport type ProviderTerminationCauseCode =\n\t| \"abort\"\n\t| \"auth\"\n\t| \"rate_limit\"\n\t| \"network\"\n\t| \"protocol\"\n\t| \"refusal\"\n\t| \"context_overflow\";\nexport type ToolTerminationCauseCode = \"timeout\" | \"fatal\";\n/** §15.4 resource-aware runtime roadmap: host-pressure termination causes. */\nexport type ResourceTerminationCauseCode = \"memory\" | \"disk\" | \"cpu\" | \"heap\" | \"probe_unavailable\" | \"queue_overflow\";\nexport type CompactionTerminationCauseCode = \"aborted\" | \"failed\" | \"stale\" | \"quota_exhausted\";\nexport type PersistenceTerminationCauseCode =\n\t| \"read_failed\"\n\t| \"append_failed\"\n\t| \"replace_failed\"\n\t| \"fsync_failed\"\n\t| \"lock_failed\";\nexport type TranscriptTerminationCauseCode =\n\t| \"missing_result\"\n\t| \"duplicate_result\"\n\t| \"orphan_result\"\n\t| \"duplicate_call_id\"\n\t| \"interleaved_non_result\"\n\t| \"invalid_jsonl\"\n\t| \"invalid_tree\"\n\t| \"unsupported_version\"\n\t| \"trailing_fragment\";\nexport type SessionTerminationCauseCode =\n\t| \"session.completed\"\n\t| \"session.user_abort\"\n\t| `provider.${ProviderTerminationCauseCode}`\n\t| `tool.${ToolTerminationCauseCode}`\n\t| `compaction.${CompactionTerminationCauseCode}`\n\t| `persistence.${PersistenceTerminationCauseCode}`\n\t| \"process.signal\"\n\t| \"process.crash\"\n\t| `transcript.${TranscriptTerminationCauseCode}`\n\t| \"configuration.invalid\"\n\t| \"internal.unclassified\"\n\t| `resource.${ResourceTerminationCauseCode}`;\n\nexport type SessionTerminationCause =\n\t| { readonly area: \"completed\" }\n\t| { readonly area: \"user\"; readonly code: \"abort\" }\n\t| { readonly area: \"provider\"; readonly code: ProviderTerminationCauseCode }\n\t| { readonly area: \"tool\"; readonly code: ToolTerminationCauseCode }\n\t| { readonly area: \"compaction\"; readonly code: CompactionTerminationCauseCode }\n\t| { readonly area: \"persistence\"; readonly code: PersistenceTerminationCauseCode }\n\t| { readonly area: \"process\"; readonly code: \"signal\"; readonly signal: SessionProcessSignal }\n\t| { readonly area: \"process\"; readonly code: \"crash\" }\n\t| { readonly area: \"transcript\"; readonly code: TranscriptTerminationCauseCode }\n\t| { readonly area: \"configuration\"; readonly code: \"invalid\" }\n\t| { readonly area: \"internal\"; readonly code: \"unclassified\" }\n\t| { readonly area: \"resource\"; readonly code: ResourceTerminationCauseCode };\n\nexport interface ClassifySessionTerminationInput {\n\treadonly sessionId: string;\n\treadonly runId: string;\n\t/** Deterministic caller-provided ISO-8601 timestamp. */\n\treadonly timestamp: string;\n\treadonly source: SessionTerminationSource;\n\t/** Caller-supplied, pre-redacted diagnostic text. */\n\treadonly message: string;\n\treadonly cause: SessionTerminationCause;\n\treadonly sideEffects: SessionSideEffects;\n\treadonly retryAfterMs?: number;\n\treadonly provider?: string;\n\treadonly model?: string;\n\treadonly toolCallId?: string;\n\treadonly toolName?: string;\n}\n\nexport interface SessionTermination {\n\treadonly schemaVersion: typeof SESSION_TERMINATION_SCHEMA_VERSION;\n\treadonly sessionId: string;\n\treadonly runId: string;\n\treadonly kind: SessionTerminationKind;\n\treadonly phase: SessionTerminationPhase;\n\treadonly source: SessionTerminationSource;\n\treadonly message: string;\n\treadonly causeCode: SessionTerminationCauseCode;\n\t/** Stable operator guidance suitable for print, JSON, RPC, and TUI surfaces. */\n\treadonly nextAction: string;\n\treadonly retryable: boolean;\n\treadonly safeToAutoRetry: boolean;\n\treadonly sideEffects: SessionSideEffects;\n\treadonly timestamp: string;\n\treadonly retryAfterMs?: number;\n\treadonly provider?: string;\n\treadonly model?: string;\n\treadonly toolCallId?: string;\n\treadonly toolName?: string;\n\treadonly processSignal?: SessionProcessSignal;\n\treadonly transcriptIssue?: TranscriptTerminationCauseCode;\n}\n\nexport class SessionTerminationError extends Error {\n\treadonly termination: SessionTermination;\n\n\tconstructor(message: string, termination: SessionTermination) {\n\t\tsuper(message);\n\t\tthis.name = \"SessionTerminationError\";\n\t\tthis.termination = termination;\n\t}\n}\n\ninterface Classification {\n\treadonly kind: SessionTerminationKind;\n\treadonly phase: SessionTerminationPhase;\n\treadonly causeCode: SessionTerminationCauseCode;\n\treadonly retryable: boolean;\n\treadonly processSignal?: SessionProcessSignal;\n\treadonly transcriptIssue?: TranscriptTerminationCauseCode;\n}\n\nconst CREDENTIAL_SHAPES = [\n\t/-----BEGIN [A-Z ]*PRIVATE KEY-----/i,\n\t/\\b(?:sk-[A-Za-z0-9_-]{16,}|github_pat_[A-Za-z0-9_]{16,}|gh[pousr]_[A-Za-z0-9]{16,}|xox[baprs]-[A-Za-z0-9-]{16,}|AKIA[A-Z0-9]{16})\\b/,\n\t/\\bBearer\\s+[A-Za-z0-9._~+/-]{8,}={0,2}\\b/i,\n\t/\\beyJ[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}\\b/,\n\t/(?:^|[^A-Za-z0-9])(?:[A-Za-z0-9]+[_-])*(?:authorization|api[-_ ]?key|access[-_ ]?token|token|password|secret(?:[-_ ]?key)?|private[-_ ]?key|cookie)[\"']?\\s*[:=]/i,\n] as const;\n\nconst TOP_LEVEL_KEYS = new Set([\n\t\"sessionId\",\n\t\"runId\",\n\t\"timestamp\",\n\t\"source\",\n\t\"message\",\n\t\"cause\",\n\t\"sideEffects\",\n\t\"retryAfterMs\",\n\t\"provider\",\n\t\"model\",\n\t\"toolCallId\",\n\t\"toolName\",\n]);\nconst PROVIDER_CAUSE_CODES = new Set<ProviderTerminationCauseCode>([\n\t\"abort\",\n\t\"auth\",\n\t\"rate_limit\",\n\t\"network\",\n\t\"protocol\",\n\t\"refusal\",\n\t\"context_overflow\",\n]);\nconst TOOL_CAUSE_CODES = new Set<ToolTerminationCauseCode>([\"timeout\", \"fatal\"]);\nconst RESOURCE_CAUSE_CODES = new Set<ResourceTerminationCauseCode>([\n\t\"memory\",\n\t\"disk\",\n\t\"cpu\",\n\t\"heap\",\n\t\"probe_unavailable\",\n\t\"queue_overflow\",\n]);\nconst COMPACTION_CAUSE_CODES = new Set<CompactionTerminationCauseCode>([\n\t\"aborted\",\n\t\"failed\",\n\t\"stale\",\n\t\"quota_exhausted\",\n]);\nconst PERSISTENCE_CAUSE_CODES = new Set<PersistenceTerminationCauseCode>([\n\t\"read_failed\",\n\t\"append_failed\",\n\t\"replace_failed\",\n\t\"fsync_failed\",\n\t\"lock_failed\",\n]);\nconst TRANSCRIPT_CAUSE_CODES = new Set<TranscriptTerminationCauseCode>([\n\t\"missing_result\",\n\t\"duplicate_result\",\n\t\"orphan_result\",\n\t\"duplicate_call_id\",\n\t\"interleaved_non_result\",\n\t\"invalid_jsonl\",\n\t\"invalid_tree\",\n\t\"unsupported_version\",\n\t\"trailing_fragment\",\n]);\nconst PROCESS_SIGNALS = new Set<SessionProcessSignal>([\"SIGINT\", \"SIGTERM\", \"SIGHUP\", \"SIGQUIT\"]);\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction hasOnlyKeys(value: Record<string, unknown>, keys: readonly string[]): boolean {\n\tconst allowed = new Set(keys);\n\treturn Object.keys(value).every((key) => allowed.has(key));\n}\n\nfunction assertCause(cause: unknown): asserts cause is SessionTerminationCause {\n\tif (!isRecord(cause) || typeof cause.area !== \"string\") {\n\t\tthrow new TypeError(\"cause must be a bounded structured termination cause\");\n\t}\n\tconst code = cause.code;\n\tlet valid = false;\n\tswitch (cause.area) {\n\t\tcase \"completed\":\n\t\t\tvalid = hasOnlyKeys(cause, [\"area\"]);\n\t\t\tbreak;\n\t\tcase \"user\":\n\t\t\tvalid = code === \"abort\" && hasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"provider\":\n\t\t\tvalid =\n\t\t\t\ttypeof code === \"string\" &&\n\t\t\t\tPROVIDER_CAUSE_CODES.has(code as ProviderTerminationCauseCode) &&\n\t\t\t\thasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"tool\":\n\t\t\tvalid =\n\t\t\t\ttypeof code === \"string\" &&\n\t\t\t\tTOOL_CAUSE_CODES.has(code as ToolTerminationCauseCode) &&\n\t\t\t\thasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"compaction\":\n\t\t\tvalid =\n\t\t\t\ttypeof code === \"string\" &&\n\t\t\t\tCOMPACTION_CAUSE_CODES.has(code as CompactionTerminationCauseCode) &&\n\t\t\t\thasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"persistence\":\n\t\t\tvalid =\n\t\t\t\ttypeof code === \"string\" &&\n\t\t\t\tPERSISTENCE_CAUSE_CODES.has(code as PersistenceTerminationCauseCode) &&\n\t\t\t\thasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"process\":\n\t\t\tvalid =\n\t\t\t\t(code === \"crash\" && hasOnlyKeys(cause, [\"area\", \"code\"])) ||\n\t\t\t\t(code === \"signal\" &&\n\t\t\t\t\ttypeof cause.signal === \"string\" &&\n\t\t\t\t\tPROCESS_SIGNALS.has(cause.signal as SessionProcessSignal) &&\n\t\t\t\t\thasOnlyKeys(cause, [\"area\", \"code\", \"signal\"]));\n\t\t\tbreak;\n\t\tcase \"transcript\":\n\t\t\tvalid =\n\t\t\t\ttypeof code === \"string\" &&\n\t\t\t\tTRANSCRIPT_CAUSE_CODES.has(code as TranscriptTerminationCauseCode) &&\n\t\t\t\thasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"configuration\":\n\t\t\tvalid = code === \"invalid\" && hasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"internal\":\n\t\t\tvalid = code === \"unclassified\" && hasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"resource\":\n\t\t\tvalid =\n\t\t\t\ttypeof code === \"string\" &&\n\t\t\t\tRESOURCE_CAUSE_CODES.has(code as ResourceTerminationCauseCode) &&\n\t\t\t\thasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t}\n\tif (!valid) throw new TypeError(\"cause must be a bounded structured termination cause\");\n}\n\nfunction assertClassifierInput(input: unknown): asserts input is ClassifySessionTerminationInput {\n\tif (!isRecord(input) || Object.keys(input).some((key) => !TOP_LEVEL_KEYS.has(key))) {\n\t\tthrow new TypeError(\"input must contain only bounded structured termination fields\");\n\t}\n\tif (\n\t\ttypeof input.sessionId !== \"string\" ||\n\t\ttypeof input.runId !== \"string\" ||\n\t\ttypeof input.timestamp !== \"string\" ||\n\t\ttypeof input.message !== \"string\" ||\n\t\t(input.source !== \"observed\" && input.source !== \"inferred_on_resume\") ||\n\t\t(input.sideEffects !== \"none\" && input.sideEffects !== \"possible\" && input.sideEffects !== \"confirmed\") ||\n\t\t(input.retryAfterMs !== undefined && typeof input.retryAfterMs !== \"number\") ||\n\t\t(input.provider !== undefined && typeof input.provider !== \"string\") ||\n\t\t(input.model !== undefined && typeof input.model !== \"string\") ||\n\t\t(input.toolCallId !== undefined && typeof input.toolCallId !== \"string\") ||\n\t\t(input.toolName !== undefined && typeof input.toolName !== \"string\")\n\t) {\n\t\tthrow new TypeError(\"input must contain only bounded structured termination fields\");\n\t}\n\tassertCause(input.cause);\n}\n\nfunction assertIdentifier(value: string, name: string, maxLength: number): void {\n\tif (value.length === 0 || value.length > maxLength || /[\\u0000-\\u001f\\u007f]/.test(value)) {\n\t\tthrow new TypeError(`${name} must be non-empty bounded text without C0 or DEL control characters`);\n\t}\n}\n\n/** Validate text at the termination trust boundary without attempting redaction. */\nexport function assertPreRedactedTerminationMessage(message: string): void {\n\tif (message.length === 0 || message.length > MAX_SESSION_TERMINATION_MESSAGE_LENGTH) {\n\t\tthrow new TypeError(\n\t\t\t`message must contain 1-${MAX_SESSION_TERMINATION_MESSAGE_LENGTH} characters of pre-redacted text`,\n\t\t);\n\t}\n\tif (message.includes(\"\\0\")) {\n\t\tthrow new TypeError(\"message must not contain NUL\");\n\t}\n\tif (CREDENTIAL_SHAPES.some((pattern) => pattern.test(message))) {\n\t\tthrow new TypeError(\"message contains a credential-shaped literal; redact it before classification\");\n\t}\n}\n\nfunction assertTimestamp(timestamp: string): void {\n\tconst parsed = new Date(timestamp);\n\tif (!Number.isFinite(parsed.getTime()) || parsed.toISOString() !== timestamp) {\n\t\tthrow new TypeError(\"timestamp must be a canonical ISO-8601 UTC instant\");\n\t}\n}\n\nfunction classifyProvider(code: ProviderTerminationCauseCode): Classification {\n\tswitch (code) {\n\t\tcase \"abort\":\n\t\t\treturn {\n\t\t\t\tkind: \"provider_abort\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.abort\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"auth\":\n\t\t\treturn {\n\t\t\t\tkind: \"provider_auth\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.auth\",\n\t\t\t\tretryable: false,\n\t\t\t};\n\t\tcase \"rate_limit\":\n\t\t\treturn {\n\t\t\t\tkind: \"provider_rate_limit\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.rate_limit\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"network\":\n\t\t\treturn {\n\t\t\t\tkind: \"provider_network\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.network\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"protocol\":\n\t\t\t// Many \"protocol\" stops are sticky transcript shape bugs (orphan tool_call_id)\n\t\t\t// that succeed after transform-messages sanitizes and the turn is retried.\n\t\t\t// Mark retryable so auto-retry can heal; safeToAutoRetry stays false (needs sanitize path).\n\t\t\treturn {\n\t\t\t\tkind: \"provider_protocol\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.protocol\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"context_overflow\":\n\t\t\treturn {\n\t\t\t\tkind: \"context_overflow\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.context_overflow\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"refusal\":\n\t\t\treturn {\n\t\t\t\tkind: \"provider_refusal\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.refusal\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t}\n}\n\nfunction classifyCause(cause: SessionTerminationCause, source: SessionTerminationSource): Classification {\n\tswitch (cause.area) {\n\t\tcase \"completed\":\n\t\t\treturn {\n\t\t\t\tkind: \"completed\",\n\t\t\t\tphase: \"completed\",\n\t\t\t\tcauseCode: \"session.completed\",\n\t\t\t\tretryable: false,\n\t\t\t};\n\t\tcase \"user\":\n\t\t\treturn {\n\t\t\t\tkind: \"user_abort\",\n\t\t\t\tphase: \"control\",\n\t\t\t\tcauseCode: \"session.user_abort\",\n\t\t\t\tretryable: false,\n\t\t\t};\n\t\tcase \"provider\":\n\t\t\treturn classifyProvider(cause.code);\n\t\tcase \"tool\":\n\t\t\treturn cause.code === \"timeout\"\n\t\t\t\t? { kind: \"tool_timeout\", phase: \"tool\", causeCode: \"tool.timeout\", retryable: true }\n\t\t\t\t: { kind: \"tool_fatal\", phase: \"tool\", causeCode: \"tool.fatal\", retryable: false };\n\t\tcase \"compaction\":\n\t\t\treturn {\n\t\t\t\tkind: \"compaction\",\n\t\t\t\tphase: \"compaction\",\n\t\t\t\tcauseCode: `compaction.${cause.code}`,\n\t\t\t\t// Quota exhaustion does not heal by retrying: same-model retries\n\t\t\t\t// keep failing until the provider cycle resets or the model changes.\n\t\t\t\tretryable: cause.code !== \"quota_exhausted\",\n\t\t\t};\n\t\tcase \"persistence\":\n\t\t\treturn {\n\t\t\t\tkind: \"persistence\",\n\t\t\t\tphase: \"persistence\",\n\t\t\t\tcauseCode: `persistence.${cause.code}`,\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"process\":\n\t\t\tif (cause.code === \"signal\") {\n\t\t\t\treturn {\n\t\t\t\t\tkind: \"process_signal\",\n\t\t\t\t\tphase: \"process\",\n\t\t\t\t\tcauseCode: \"process.signal\",\n\t\t\t\t\tretryable: false,\n\t\t\t\t\tprocessSignal: cause.signal,\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tkind: \"process_crash\",\n\t\t\t\tphase: \"resume\",\n\t\t\t\tcauseCode: \"process.crash\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"transcript\":\n\t\t\treturn {\n\t\t\t\tkind: \"transcript_invalid\",\n\t\t\t\tphase: source === \"inferred_on_resume\" ? \"resume\" : \"preflight\",\n\t\t\t\tcauseCode: `transcript.${cause.code}`,\n\t\t\t\tretryable: false,\n\t\t\t\ttranscriptIssue: cause.code,\n\t\t\t};\n\t\tcase \"configuration\":\n\t\t\treturn {\n\t\t\t\tkind: \"configuration\",\n\t\t\t\tphase: \"preflight\",\n\t\t\t\tcauseCode: \"configuration.invalid\",\n\t\t\t\tretryable: false,\n\t\t\t};\n\t\tcase \"internal\":\n\t\t\treturn {\n\t\t\t\tkind: \"internal_error\",\n\t\t\t\tphase: \"preflight\",\n\t\t\t\tcauseCode: \"internal.unclassified\",\n\t\t\t\tretryable: false,\n\t\t\t};\n\t\tcase \"resource\":\n\t\t\t// §15.4: every resource cause is retryable; queue overflow surfaces at\n\t\t\t// the tool boundary, everything else at preflight admission.\n\t\t\treturn {\n\t\t\t\tkind: \"resource_pressure\",\n\t\t\t\tphase: cause.code === \"queue_overflow\" ? \"tool\" : \"preflight\",\n\t\t\t\tcauseCode: `resource.${cause.code}`,\n\t\t\t\tretryable: true,\n\t\t\t};\n\t}\n}\n\nfunction isSafeToAutoRetry(classification: Classification, input: ClassifySessionTerminationInput): boolean {\n\t// provider_refusal: Fable/Claude often false-positive on benign turns. Safe to auto-retry once\n\t// when no tool side effects occurred (same class of recovery as rate_limit/network).\n\treturn (\n\t\tclassification.retryable &&\n\t\tinput.source === \"observed\" &&\n\t\tinput.sideEffects === \"none\" &&\n\t\t(classification.kind === \"provider_rate_limit\" ||\n\t\t\tclassification.kind === \"provider_network\" ||\n\t\t\tclassification.kind === \"provider_refusal\" ||\n\t\t\t// §15.4 mapping: only cpu pressure is safe to auto-retry (with delay).\n\t\t\tclassification.causeCode === \"resource.cpu\")\n\t);\n}\n\nfunction nextActionFor(classification: Classification, input: ClassifySessionTerminationInput): string {\n\tswitch (classification.kind) {\n\t\tcase \"completed\":\n\t\t\treturn \"No recovery action is required; continue with the next prompt.\";\n\t\tcase \"user_abort\":\n\t\t\treturn \"Review possible partial side effects, then retry only if intended.\";\n\t\tcase \"resource_pressure\":\n\t\t\treturn \"Host resources are constrained; reduce load or wait for recovery, then retry.\";\n\t\tcase \"provider_abort\":\n\t\t\treturn \"Confirm provider availability, then retry the request.\";\n\t\tcase \"provider_auth\":\n\t\t\t// A credential-less install resolves a placeholder model whose provider is\n\t\t\t// literally \"unknown\"; never echo that back as a login target.\n\t\t\treturn `Run /login${input.provider && input.provider !== \"unknown\" ? ` ${input.provider}` : \"\"} in an interactive session, or set the provider's API key environment variable, then retry.`;\n\t\tcase \"provider_rate_limit\":\n\t\t\treturn \"Wait for the provider retry window or choose another model, then retry.\";\n\t\tcase \"provider_network\":\n\t\t\treturn \"Check network and provider connectivity, then retry.\";\n\t\tcase \"provider_protocol\":\n\t\t\treturn \"Often an orphan tool_call_id / sticky transcript after a dropped error turn — auto-retry after sanitize, or /new session if it persists.\";\n\t\tcase \"provider_refusal\":\n\t\t\treturn \"Model declined this turn (content/safety stop). Usually a false positive on Fable/Claude — auto-retry once, or switch model (k3/qwen3.8-max/grok-4.5/deepseek) / rephrase as a pure coding task.\";\n\t\tcase \"context_overflow\":\n\t\t\treturn \"Compact or reduce context, or switch to a larger-context model.\";\n\t\tcase \"tool_timeout\":\n\t\t\treturn \"Inspect possible tool side effects and increase the tool timeout only if safe.\";\n\t\tcase \"tool_fatal\":\n\t\t\treturn \"Inspect the failed tool result and repair its configuration before retrying.\";\n\t\tcase \"compaction\":\n\t\t\tswitch (classification.causeCode) {\n\t\t\t\tcase \"compaction.aborted\":\n\t\t\t\t\treturn \"Retry /compact if cancellation was unintended; avoid Escape while compaction is running.\";\n\t\t\t\tcase \"compaction.stale\":\n\t\t\t\t\treturn \"Retry /compact after pending session changes settle.\";\n\t\t\t\tcase \"compaction.quota_exhausted\":\n\t\t\t\t\treturn \"The summarization model's quota is exhausted — retrying cannot help yet. Switch model (/model), set compaction.model in settings, or wait for the quota reset, then retry /compact. OMK already tried the failover chain automatically.\";\n\t\t\t\tdefault:\n\t\t\t\t\treturn \"Resolve the reported compaction error, then retry /compact.\";\n\t\t\t}\n\t\tcase \"persistence\":\n\t\t\treturn `Run omk session doctor --session ${input.sessionId} before resuming.`;\n\t\tcase \"process_signal\":\n\t\t\treturn \"Review possible partial side effects before resuming the session.\";\n\t\tcase \"process_crash\":\n\t\t\treturn `Run omk session doctor --session ${input.sessionId} and review partial side effects.`;\n\t\tcase \"transcript_invalid\":\n\t\t\treturn `Run omk session doctor --session ${input.sessionId}; do not resume until integrity passes.`;\n\t\tcase \"configuration\":\n\t\t\treturn \"This model or client is not valid for the current login. Switch with /model or fix provider/client settings; /new session will not grant access.\";\n\t\tcase \"internal_error\":\n\t\t\treturn `Inspect run ${input.runId} diagnostics and the run journal before retrying.`;\n\t}\n}\n\n/** Concise actionable rendering shared by non-JSON and TUI surfaces. */\nexport function formatSessionTermination(termination: SessionTermination): string {\n\tconst route =\n\t\ttermination.provider || termination.model\n\t\t\t? `${termination.provider ?? \"unknown\"}/${termination.model ?? \"unknown\"}`\n\t\t\t: \"n/a\";\n\treturn [\n\t\t`kind=${termination.kind}`,\n\t\t`provider/model=${route}`,\n\t\t`retryable=${termination.retryable}`,\n\t\t`cause=${termination.causeCode}`,\n\t\t`message=${termination.message}`,\n\t\t`run=${termination.runId}`,\n\t\t`next=${termination.nextAction}`,\n\t].join(\" \");\n}\n\n/**\n * Classify a bounded, structured termination cause. This intentionally accepts\n * no raw Error value, stack, provider body, or arbitrary cause code.\n */\nexport function classifySessionTermination(input: ClassifySessionTerminationInput): SessionTermination {\n\tassertClassifierInput(input);\n\tassertIdentifier(input.sessionId, \"sessionId\", 128);\n\tassertIdentifier(input.runId, \"runId\", 128);\n\tassertTimestamp(input.timestamp);\n\tassertPreRedactedTerminationMessage(input.message);\n\tif (input.provider !== undefined) assertIdentifier(input.provider, \"provider\", 128);\n\tif (input.model !== undefined) assertIdentifier(input.model, \"model\", 256);\n\tif (input.toolCallId !== undefined) assertIdentifier(input.toolCallId, \"toolCallId\", 512);\n\tif (input.toolName !== undefined) assertIdentifier(input.toolName, \"toolName\", 128);\n\tif (input.retryAfterMs !== undefined && (!Number.isSafeInteger(input.retryAfterMs) || input.retryAfterMs < 0)) {\n\t\tthrow new TypeError(\"retryAfterMs must be a non-negative safe integer\");\n\t}\n\tif (input.cause.area === \"process\" && input.cause.code === \"crash\" && input.source !== \"inferred_on_resume\") {\n\t\tthrow new TypeError(\"process crashes may only be classified as inferred_on_resume\");\n\t}\n\tif (input.cause.area === \"process\" && input.cause.code === \"signal\" && input.source !== \"observed\") {\n\t\tthrow new TypeError(\"process signals must be observed\");\n\t}\n\n\tconst classification = classifyCause(input.cause, input.source);\n\treturn Object.freeze({\n\t\tschemaVersion: SESSION_TERMINATION_SCHEMA_VERSION,\n\t\tsessionId: input.sessionId,\n\t\trunId: input.runId,\n\t\tkind: classification.kind,\n\t\tphase: classification.phase,\n\t\tsource: input.source,\n\t\tmessage: input.message,\n\t\tcauseCode: classification.causeCode,\n\t\tnextAction: nextActionFor(classification, input),\n\t\tretryable: classification.retryable,\n\t\tsafeToAutoRetry: isSafeToAutoRetry(classification, input),\n\t\tsideEffects: input.sideEffects,\n\t\ttimestamp: input.timestamp,\n\t\t...(input.retryAfterMs === undefined ? {} : { retryAfterMs: input.retryAfterMs }),\n\t\t...(input.provider === undefined ? {} : { provider: input.provider }),\n\t\t...(input.model === undefined ? {} : { model: input.model }),\n\t\t...(input.toolCallId === undefined ? {} : { toolCallId: input.toolCallId }),\n\t\t...(input.toolName === undefined ? {} : { toolName: input.toolName }),\n\t\t...(classification.processSignal === undefined ? {} : { processSignal: classification.processSignal }),\n\t\t...(classification.transcriptIssue === undefined ? {} : { transcriptIssue: classification.transcriptIssue }),\n\t});\n}\n"]}
1
+ {"version":3,"file":"session-termination.d.ts","sourceRoot":"","sources":["../../src/core/session-termination.ts"],"names":[],"mappings":"AACA,OAAO,EACN,KAAK,+BAA+B,EAOpC,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAO5B,MAAM,gCAAgC,CAAC;AAExC,cAAc,gCAAgC,CAAC;AAE/C,qBAAa,uBAAwB,SAAQ,KAAK;IACjD,QAAQ,CAAC,WAAW,EAAE,kBAAkB,CAAC;IAEzC,YAAY,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,kBAAkB,EAI3D;CACD;AA4JD,wBAAgB,gCAAgC,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,oBAAoB,GAAG,uBAAuB,CAWrH;AA8BD,oFAAoF;AACpF,wBAAgB,mCAAmC,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAYzE;AAmOD,wEAAwE;AACxE,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,kBAAkB,GAAG,MAAM,CAchF;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,+BAA+B,GAAG,kBAAkB,CA2CrG","sourcesContent":["import { RUN_BUDGET_STOP_CODES } from \"./run-budget-policy.ts\";\nimport {\n\ttype ClassifySessionTerminationInput,\n\ttype CompactionTerminationCauseCode,\n\tMAX_SESSION_TERMINATION_MESSAGE_LENGTH,\n\ttype PersistenceTerminationCauseCode,\n\ttype ProviderTerminationCauseCode,\n\ttype ResourceTerminationCauseCode,\n\tSESSION_TERMINATION_SCHEMA_VERSION,\n\ttype SessionProcessSignal,\n\ttype SessionTermination,\n\ttype SessionTerminationCause,\n\ttype SessionTerminationCauseCode,\n\ttype SessionTerminationKind,\n\ttype SessionTerminationPhase,\n\ttype SessionTerminationSource,\n\ttype ToolTerminationCauseCode,\n\ttype TranscriptTerminationCauseCode,\n} from \"./session-termination-types.ts\";\n\nexport * from \"./session-termination-types.ts\";\n\nexport class SessionTerminationError extends Error {\n\treadonly termination: SessionTermination;\n\n\tconstructor(message: string, termination: SessionTermination) {\n\t\tsuper(message);\n\t\tthis.name = \"SessionTerminationError\";\n\t\tthis.termination = termination;\n\t}\n}\n\ninterface Classification {\n\treadonly kind: SessionTerminationKind;\n\treadonly phase: SessionTerminationPhase;\n\treadonly causeCode: SessionTerminationCauseCode;\n\treadonly retryable: boolean;\n\treadonly processSignal?: SessionProcessSignal;\n\treadonly transcriptIssue?: TranscriptTerminationCauseCode;\n}\n\nconst CREDENTIAL_SHAPES = [\n\t/-----BEGIN [A-Z ]*PRIVATE KEY-----/i,\n\t/\\b(?:sk-[A-Za-z0-9_-]{16,}|github_pat_[A-Za-z0-9_]{16,}|gh[pousr]_[A-Za-z0-9]{16,}|xox[baprs]-[A-Za-z0-9-]{16,}|AKIA[A-Z0-9]{16})\\b/,\n\t/\\bBearer\\s+[A-Za-z0-9._~+/-]{8,}={0,2}\\b/i,\n\t/\\beyJ[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}\\b/,\n\t/(?:^|[^A-Za-z0-9])(?:[A-Za-z0-9]+[_-])*(?:authorization|api[-_ ]?key|access[-_ ]?token|token|password|secret(?:[-_ ]?key)?|private[-_ ]?key|cookie)[\"']?\\s*[:=]/i,\n] as const;\n\nconst TOP_LEVEL_KEYS = new Set([\n\t\"sessionId\",\n\t\"runId\",\n\t\"timestamp\",\n\t\"source\",\n\t\"message\",\n\t\"cause\",\n\t\"sideEffects\",\n\t\"retryAfterMs\",\n\t\"provider\",\n\t\"model\",\n\t\"toolCallId\",\n\t\"toolName\",\n]);\nconst PROVIDER_CAUSE_CODES = new Set<ProviderTerminationCauseCode>([\n\t\"abort\",\n\t\"auth\",\n\t\"rate_limit\",\n\t\"network\",\n\t\"protocol\",\n\t\"refusal\",\n\t\"context_overflow\",\n]);\nconst TOOL_CAUSE_CODES = new Set<ToolTerminationCauseCode>([\"timeout\", \"fatal\"]);\nconst RESOURCE_CAUSE_CODES = new Set<ResourceTerminationCauseCode>([\n\t\"memory\",\n\t\"disk\",\n\t\"cpu\",\n\t\"heap\",\n\t\"probe_unavailable\",\n\t\"queue_overflow\",\n]);\nconst COMPACTION_CAUSE_CODES = new Set<CompactionTerminationCauseCode>([\n\t\"aborted\",\n\t\"failed\",\n\t\"stale\",\n\t\"quota_exhausted\",\n]);\nconst PERSISTENCE_CAUSE_CODES = new Set<PersistenceTerminationCauseCode>([\n\t\"read_failed\",\n\t\"append_failed\",\n\t\"replace_failed\",\n\t\"fsync_failed\",\n\t\"lock_failed\",\n]);\nconst TRANSCRIPT_CAUSE_CODES = new Set<TranscriptTerminationCauseCode>([\n\t\"missing_result\",\n\t\"duplicate_result\",\n\t\"orphan_result\",\n\t\"duplicate_call_id\",\n\t\"interleaved_non_result\",\n\t\"invalid_jsonl\",\n\t\"invalid_tree\",\n\t\"unsupported_version\",\n\t\"trailing_fragment\",\n]);\nconst PROCESS_SIGNALS = new Set<SessionProcessSignal>([\"SIGINT\", \"SIGTERM\", \"SIGHUP\", \"SIGQUIT\"]);\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction hasOnlyKeys(value: Record<string, unknown>, keys: readonly string[]): boolean {\n\tconst allowed = new Set(keys);\n\treturn Object.keys(value).every((key) => allowed.has(key));\n}\n\nfunction assertCause(cause: unknown): asserts cause is SessionTerminationCause {\n\tif (!isRecord(cause) || typeof cause.area !== \"string\") {\n\t\tthrow new TypeError(\"cause must be a bounded structured termination cause\");\n\t}\n\tconst code = cause.code;\n\tlet valid = false;\n\tswitch (cause.area) {\n\t\tcase \"completed\":\n\t\t\tvalid = hasOnlyKeys(cause, [\"area\"]);\n\t\t\tbreak;\n\t\tcase \"user\":\n\t\t\tvalid = code === \"abort\" && hasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"provider\":\n\t\t\tvalid =\n\t\t\t\ttypeof code === \"string\" &&\n\t\t\t\tPROVIDER_CAUSE_CODES.has(code as ProviderTerminationCauseCode) &&\n\t\t\t\thasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"tool\":\n\t\t\tvalid =\n\t\t\t\ttypeof code === \"string\" &&\n\t\t\t\tTOOL_CAUSE_CODES.has(code as ToolTerminationCauseCode) &&\n\t\t\t\thasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"compaction\":\n\t\t\tvalid =\n\t\t\t\ttypeof code === \"string\" &&\n\t\t\t\tCOMPACTION_CAUSE_CODES.has(code as CompactionTerminationCauseCode) &&\n\t\t\t\thasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"persistence\":\n\t\t\tvalid =\n\t\t\t\ttypeof code === \"string\" &&\n\t\t\t\tPERSISTENCE_CAUSE_CODES.has(code as PersistenceTerminationCauseCode) &&\n\t\t\t\thasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"process\":\n\t\t\tvalid =\n\t\t\t\t(code === \"crash\" && hasOnlyKeys(cause, [\"area\", \"code\"])) ||\n\t\t\t\t(code === \"signal\" &&\n\t\t\t\t\ttypeof cause.signal === \"string\" &&\n\t\t\t\t\tPROCESS_SIGNALS.has(cause.signal as SessionProcessSignal) &&\n\t\t\t\t\thasOnlyKeys(cause, [\"area\", \"code\", \"signal\"]));\n\t\t\tbreak;\n\t\tcase \"transcript\":\n\t\t\tvalid =\n\t\t\t\ttypeof code === \"string\" &&\n\t\t\t\tTRANSCRIPT_CAUSE_CODES.has(code as TranscriptTerminationCauseCode) &&\n\t\t\t\thasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"configuration\":\n\t\t\tvalid = code === \"invalid\" && hasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"internal\":\n\t\t\tvalid = code === \"unclassified\" && hasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"budget\":\n\t\t\tvalid = RUN_BUDGET_STOP_CODES.some((allowed) => allowed === code) && hasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t\tcase \"resource\":\n\t\t\tvalid =\n\t\t\t\ttypeof code === \"string\" &&\n\t\t\t\tRESOURCE_CAUSE_CODES.has(code as ResourceTerminationCauseCode) &&\n\t\t\t\thasOnlyKeys(cause, [\"area\", \"code\"]);\n\t\t\tbreak;\n\t}\n\tif (!valid) throw new TypeError(\"cause must be a bounded structured termination cause\");\n}\n\nexport function parseSessionTerminationCauseCode(code: string, signal?: SessionProcessSignal): SessionTerminationCause {\n\tif (code === \"session.completed\") return { area: \"completed\" };\n\tif (code === \"session.user_abort\") return { area: \"user\", code: \"abort\" };\n\tconst dot = code.indexOf(\".\");\n\tconst cause = {\n\t\tarea: code.slice(0, dot),\n\t\tcode: code.slice(dot + 1),\n\t\t...(code === \"process.signal\" ? { signal } : {}),\n\t};\n\tassertCause(cause);\n\treturn cause;\n}\n\nfunction assertClassifierInput(input: unknown): asserts input is ClassifySessionTerminationInput {\n\tif (!isRecord(input) || Object.keys(input).some((key) => !TOP_LEVEL_KEYS.has(key))) {\n\t\tthrow new TypeError(\"input must contain only bounded structured termination fields\");\n\t}\n\tif (\n\t\ttypeof input.sessionId !== \"string\" ||\n\t\ttypeof input.runId !== \"string\" ||\n\t\ttypeof input.timestamp !== \"string\" ||\n\t\ttypeof input.message !== \"string\" ||\n\t\t(input.source !== \"observed\" && input.source !== \"inferred_on_resume\") ||\n\t\t(input.sideEffects !== \"none\" && input.sideEffects !== \"possible\" && input.sideEffects !== \"confirmed\") ||\n\t\t(input.retryAfterMs !== undefined && typeof input.retryAfterMs !== \"number\") ||\n\t\t(input.provider !== undefined && typeof input.provider !== \"string\") ||\n\t\t(input.model !== undefined && typeof input.model !== \"string\") ||\n\t\t(input.toolCallId !== undefined && typeof input.toolCallId !== \"string\") ||\n\t\t(input.toolName !== undefined && typeof input.toolName !== \"string\")\n\t) {\n\t\tthrow new TypeError(\"input must contain only bounded structured termination fields\");\n\t}\n\tassertCause(input.cause);\n}\n\nfunction assertIdentifier(value: string, name: string, maxLength: number): void {\n\tif (value.length === 0 || value.length > maxLength || /[\\u0000-\\u001f\\u007f]/.test(value)) {\n\t\tthrow new TypeError(`${name} must be non-empty bounded text without C0 or DEL control characters`);\n\t}\n}\n\n/** Validate text at the termination trust boundary without attempting redaction. */\nexport function assertPreRedactedTerminationMessage(message: string): void {\n\tif (message.length === 0 || message.length > MAX_SESSION_TERMINATION_MESSAGE_LENGTH) {\n\t\tthrow new TypeError(\n\t\t\t`message must contain 1-${MAX_SESSION_TERMINATION_MESSAGE_LENGTH} characters of pre-redacted text`,\n\t\t);\n\t}\n\tif (message.includes(\"\\0\")) {\n\t\tthrow new TypeError(\"message must not contain NUL\");\n\t}\n\tif (CREDENTIAL_SHAPES.some((pattern) => pattern.test(message))) {\n\t\tthrow new TypeError(\"message contains a credential-shaped literal; redact it before classification\");\n\t}\n}\n\nfunction assertTimestamp(timestamp: string): void {\n\tconst parsed = new Date(timestamp);\n\tif (!Number.isFinite(parsed.getTime()) || parsed.toISOString() !== timestamp) {\n\t\tthrow new TypeError(\"timestamp must be a canonical ISO-8601 UTC instant\");\n\t}\n}\n\nfunction classifyProvider(code: ProviderTerminationCauseCode): Classification {\n\tswitch (code) {\n\t\tcase \"abort\":\n\t\t\treturn {\n\t\t\t\tkind: \"provider_abort\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.abort\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"auth\":\n\t\t\treturn {\n\t\t\t\tkind: \"provider_auth\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.auth\",\n\t\t\t\tretryable: false,\n\t\t\t};\n\t\tcase \"rate_limit\":\n\t\t\treturn {\n\t\t\t\tkind: \"provider_rate_limit\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.rate_limit\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"network\":\n\t\t\treturn {\n\t\t\t\tkind: \"provider_network\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.network\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"protocol\":\n\t\t\t// Many \"protocol\" stops are sticky transcript shape bugs (orphan tool_call_id)\n\t\t\t// that succeed after transform-messages sanitizes and the turn is retried.\n\t\t\t// Mark retryable so auto-retry can heal; safeToAutoRetry stays false (needs sanitize path).\n\t\t\treturn {\n\t\t\t\tkind: \"provider_protocol\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.protocol\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"context_overflow\":\n\t\t\treturn {\n\t\t\t\tkind: \"context_overflow\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.context_overflow\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"refusal\":\n\t\t\treturn {\n\t\t\t\tkind: \"provider_refusal\",\n\t\t\t\tphase: \"provider\",\n\t\t\t\tcauseCode: \"provider.refusal\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t}\n}\n\nfunction classifyCause(cause: SessionTerminationCause, source: SessionTerminationSource): Classification {\n\tswitch (cause.area) {\n\t\tcase \"completed\":\n\t\t\treturn {\n\t\t\t\tkind: \"completed\",\n\t\t\t\tphase: \"completed\",\n\t\t\t\tcauseCode: \"session.completed\",\n\t\t\t\tretryable: false,\n\t\t\t};\n\t\tcase \"user\":\n\t\t\treturn {\n\t\t\t\tkind: \"user_abort\",\n\t\t\t\tphase: \"control\",\n\t\t\t\tcauseCode: \"session.user_abort\",\n\t\t\t\tretryable: false,\n\t\t\t};\n\t\tcase \"provider\":\n\t\t\treturn classifyProvider(cause.code);\n\t\tcase \"tool\":\n\t\t\treturn cause.code === \"timeout\"\n\t\t\t\t? { kind: \"tool_timeout\", phase: \"tool\", causeCode: \"tool.timeout\", retryable: true }\n\t\t\t\t: { kind: \"tool_fatal\", phase: \"tool\", causeCode: \"tool.fatal\", retryable: false };\n\t\tcase \"compaction\":\n\t\t\treturn {\n\t\t\t\tkind: \"compaction\",\n\t\t\t\tphase: \"compaction\",\n\t\t\t\tcauseCode: `compaction.${cause.code}`,\n\t\t\t\t// Quota exhaustion does not heal by retrying: same-model retries\n\t\t\t\t// keep failing until the provider cycle resets or the model changes.\n\t\t\t\tretryable: cause.code !== \"quota_exhausted\",\n\t\t\t};\n\t\tcase \"persistence\":\n\t\t\treturn {\n\t\t\t\tkind: \"persistence\",\n\t\t\t\tphase: \"persistence\",\n\t\t\t\tcauseCode: `persistence.${cause.code}`,\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"process\":\n\t\t\tif (cause.code === \"signal\") {\n\t\t\t\treturn {\n\t\t\t\t\tkind: \"process_signal\",\n\t\t\t\t\tphase: \"process\",\n\t\t\t\t\tcauseCode: \"process.signal\",\n\t\t\t\t\tretryable: false,\n\t\t\t\t\tprocessSignal: cause.signal,\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tkind: \"process_crash\",\n\t\t\t\tphase: \"resume\",\n\t\t\t\tcauseCode: \"process.crash\",\n\t\t\t\tretryable: true,\n\t\t\t};\n\t\tcase \"transcript\":\n\t\t\treturn {\n\t\t\t\tkind: \"transcript_invalid\",\n\t\t\t\tphase: source === \"inferred_on_resume\" ? \"resume\" : \"preflight\",\n\t\t\t\tcauseCode: `transcript.${cause.code}`,\n\t\t\t\tretryable: false,\n\t\t\t\ttranscriptIssue: cause.code,\n\t\t\t};\n\t\tcase \"configuration\":\n\t\t\treturn {\n\t\t\t\tkind: \"configuration\",\n\t\t\t\tphase: \"preflight\",\n\t\t\t\tcauseCode: \"configuration.invalid\",\n\t\t\t\tretryable: false,\n\t\t\t};\n\t\tcase \"internal\":\n\t\t\treturn {\n\t\t\t\tkind: \"internal_error\",\n\t\t\t\tphase: \"preflight\",\n\t\t\t\tcauseCode: \"internal.unclassified\",\n\t\t\t\tretryable: false,\n\t\t\t};\n\t\tcase \"budget\":\n\t\t\treturn { kind: \"budget_exhausted\", phase: \"control\", causeCode: `budget.${cause.code}`, retryable: false };\n\t\tcase \"resource\":\n\t\t\t// §15.4: every resource cause is retryable; queue overflow surfaces at\n\t\t\t// the tool boundary, everything else at preflight admission.\n\t\t\treturn {\n\t\t\t\tkind: \"resource_pressure\",\n\t\t\t\tphase: cause.code === \"queue_overflow\" ? \"tool\" : \"preflight\",\n\t\t\t\tcauseCode: `resource.${cause.code}`,\n\t\t\t\tretryable: true,\n\t\t\t};\n\t}\n}\n\nfunction isSafeToAutoRetry(classification: Classification, input: ClassifySessionTerminationInput): boolean {\n\t// provider_refusal: Fable/Claude often false-positive on benign turns. Safe to auto-retry once\n\t// when no tool side effects occurred (same class of recovery as rate_limit/network).\n\treturn (\n\t\tclassification.retryable &&\n\t\tinput.source === \"observed\" &&\n\t\tinput.sideEffects === \"none\" &&\n\t\t(classification.kind === \"provider_rate_limit\" ||\n\t\t\tclassification.kind === \"provider_network\" ||\n\t\t\tclassification.kind === \"provider_refusal\" ||\n\t\t\t// §15.4 mapping: only cpu pressure is safe to auto-retry (with delay).\n\t\t\tclassification.causeCode === \"resource.cpu\")\n\t);\n}\n\nfunction nextActionFor(classification: Classification, input: ClassifySessionTerminationInput): string {\n\tswitch (classification.kind) {\n\t\tcase \"completed\":\n\t\t\treturn \"No recovery action is required; continue with the next prompt.\";\n\t\tcase \"user_abort\":\n\t\t\treturn \"Review possible partial side effects, then retry only if intended.\";\n\t\tcase \"budget_exhausted\":\n\t\t\treturn \"Review partial work and remaining requests; start a new run only with an explicitly approved budget.\";\n\t\tcase \"resource_pressure\":\n\t\t\treturn \"Host resources are constrained; reduce load or wait for recovery, then retry.\";\n\t\tcase \"provider_abort\":\n\t\t\treturn \"Confirm provider availability, then retry the request.\";\n\t\tcase \"provider_auth\":\n\t\t\t// A credential-less install resolves a placeholder model whose provider is\n\t\t\t// literally \"unknown\"; never echo that back as a login target.\n\t\t\treturn `Run /login${input.provider && input.provider !== \"unknown\" ? ` ${input.provider}` : \"\"} in an interactive session, or set the provider's API key environment variable, then retry.`;\n\t\tcase \"provider_rate_limit\":\n\t\t\treturn \"Wait for the provider retry window or choose another model, then retry.\";\n\t\tcase \"provider_network\":\n\t\t\treturn \"Check network and provider connectivity, then retry.\";\n\t\tcase \"provider_protocol\":\n\t\t\treturn \"Often an orphan tool_call_id / sticky transcript after a dropped error turn — auto-retry after sanitize, or /new session if it persists.\";\n\t\tcase \"provider_refusal\":\n\t\t\treturn \"Model declined this turn (content/safety stop). Usually a false positive on Fable/Claude — auto-retry once, or switch model (k3/qwen3.8-max/grok-4.5/deepseek) / rephrase as a pure coding task.\";\n\t\tcase \"context_overflow\":\n\t\t\treturn \"Compact or reduce context, or switch to a larger-context model.\";\n\t\tcase \"tool_timeout\":\n\t\t\treturn \"Inspect possible tool side effects and increase the tool timeout only if safe.\";\n\t\tcase \"tool_fatal\":\n\t\t\treturn \"Inspect the failed tool result and repair its configuration before retrying.\";\n\t\tcase \"compaction\":\n\t\t\tswitch (classification.causeCode) {\n\t\t\t\tcase \"compaction.aborted\":\n\t\t\t\t\treturn \"Retry /compact if cancellation was unintended; avoid Escape while compaction is running.\";\n\t\t\t\tcase \"compaction.stale\":\n\t\t\t\t\treturn \"Retry /compact after pending session changes settle.\";\n\t\t\t\tcase \"compaction.quota_exhausted\":\n\t\t\t\t\treturn \"The summarization model's quota is exhausted — retrying cannot help yet. Switch model (/model), set compaction.model in settings, or wait for the quota reset, then retry /compact. OMK already tried the failover chain automatically.\";\n\t\t\t\tdefault:\n\t\t\t\t\treturn \"Resolve the reported compaction error, then retry /compact.\";\n\t\t\t}\n\t\tcase \"persistence\":\n\t\t\treturn `Run omk session doctor --session ${input.sessionId} before resuming.`;\n\t\tcase \"process_signal\":\n\t\t\treturn \"Review possible partial side effects before resuming the session.\";\n\t\tcase \"process_crash\":\n\t\t\treturn `Run omk session doctor --session ${input.sessionId} and review partial side effects.`;\n\t\tcase \"transcript_invalid\":\n\t\t\treturn `Run omk session doctor --session ${input.sessionId}; do not resume until integrity passes.`;\n\t\tcase \"configuration\":\n\t\t\treturn \"This model or client is not valid for the current login. Switch with /model or fix provider/client settings; /new session will not grant access.\";\n\t\tcase \"internal_error\":\n\t\t\treturn `Inspect run ${input.runId} diagnostics and the run journal before retrying.`;\n\t}\n}\n\n/** Concise actionable rendering shared by non-JSON and TUI surfaces. */\nexport function formatSessionTermination(termination: SessionTermination): string {\n\tconst route =\n\t\ttermination.provider || termination.model\n\t\t\t? `${termination.provider ?? \"unknown\"}/${termination.model ?? \"unknown\"}`\n\t\t\t: \"n/a\";\n\treturn [\n\t\t`kind=${termination.kind}`,\n\t\t`provider/model=${route}`,\n\t\t`retryable=${termination.retryable}`,\n\t\t`cause=${termination.causeCode}`,\n\t\t`message=${termination.message}`,\n\t\t`run=${termination.runId}`,\n\t\t`next=${termination.nextAction}`,\n\t].join(\" \");\n}\n\n/**\n * Classify a bounded, structured termination cause. This intentionally accepts\n * no raw Error value, stack, provider body, or arbitrary cause code.\n */\nexport function classifySessionTermination(input: ClassifySessionTerminationInput): SessionTermination {\n\tassertClassifierInput(input);\n\tassertIdentifier(input.sessionId, \"sessionId\", 128);\n\tassertIdentifier(input.runId, \"runId\", 128);\n\tassertTimestamp(input.timestamp);\n\tassertPreRedactedTerminationMessage(input.message);\n\tif (input.provider !== undefined) assertIdentifier(input.provider, \"provider\", 128);\n\tif (input.model !== undefined) assertIdentifier(input.model, \"model\", 256);\n\tif (input.toolCallId !== undefined) assertIdentifier(input.toolCallId, \"toolCallId\", 512);\n\tif (input.toolName !== undefined) assertIdentifier(input.toolName, \"toolName\", 128);\n\tif (input.retryAfterMs !== undefined && (!Number.isSafeInteger(input.retryAfterMs) || input.retryAfterMs < 0)) {\n\t\tthrow new TypeError(\"retryAfterMs must be a non-negative safe integer\");\n\t}\n\tif (input.cause.area === \"process\" && input.cause.code === \"crash\" && input.source !== \"inferred_on_resume\") {\n\t\tthrow new TypeError(\"process crashes may only be classified as inferred_on_resume\");\n\t}\n\tif (input.cause.area === \"process\" && input.cause.code === \"signal\" && input.source !== \"observed\") {\n\t\tthrow new TypeError(\"process signals must be observed\");\n\t}\n\n\tconst classification = classifyCause(input.cause, input.source);\n\treturn Object.freeze({\n\t\tschemaVersion: SESSION_TERMINATION_SCHEMA_VERSION,\n\t\tsessionId: input.sessionId,\n\t\trunId: input.runId,\n\t\tkind: classification.kind,\n\t\tphase: classification.phase,\n\t\tsource: input.source,\n\t\tmessage: input.message,\n\t\tcauseCode: classification.causeCode,\n\t\tnextAction: nextActionFor(classification, input),\n\t\tretryable: classification.retryable,\n\t\tsafeToAutoRetry: isSafeToAutoRetry(classification, input),\n\t\tsideEffects: input.sideEffects,\n\t\ttimestamp: input.timestamp,\n\t\t...(input.retryAfterMs === undefined ? {} : { retryAfterMs: input.retryAfterMs }),\n\t\t...(input.provider === undefined ? {} : { provider: input.provider }),\n\t\t...(input.model === undefined ? {} : { model: input.model }),\n\t\t...(input.toolCallId === undefined ? {} : { toolCallId: input.toolCallId }),\n\t\t...(input.toolName === undefined ? {} : { toolName: input.toolName }),\n\t\t...(classification.processSignal === undefined ? {} : { processSignal: classification.processSignal }),\n\t\t...(classification.transcriptIssue === undefined ? {} : { transcriptIssue: classification.transcriptIssue }),\n\t});\n}\n"]}
@@ -1,31 +1,6 @@
1
- export const SESSION_TERMINATION_SCHEMA_VERSION = 1;
2
- export const MAX_SESSION_TERMINATION_MESSAGE_LENGTH = 512;
3
- /**
4
- * Canonical list of termination kinds. The run-journal validator derives its
5
- * runtime bounds from this tuple so a newly added kind can never crash
6
- * journaling with "termination kind is out of bounds" again.
7
- */
8
- export const SESSION_TERMINATION_KIND_VALUES = [
9
- "completed",
10
- "user_abort",
11
- "provider_abort",
12
- "provider_auth",
13
- "provider_rate_limit",
14
- "provider_network",
15
- "provider_protocol",
16
- "provider_refusal",
17
- "context_overflow",
18
- "transcript_invalid",
19
- "tool_timeout",
20
- "tool_fatal",
21
- "compaction",
22
- "persistence",
23
- "process_signal",
24
- "process_crash",
25
- "configuration",
26
- "internal_error",
27
- "resource_pressure",
28
- ];
1
+ import { RUN_BUDGET_STOP_CODES } from "./run-budget-policy.js";
2
+ import { MAX_SESSION_TERMINATION_MESSAGE_LENGTH, SESSION_TERMINATION_SCHEMA_VERSION, } from "./session-termination-types.js";
3
+ export * from "./session-termination-types.js";
29
4
  export class SessionTerminationError extends Error {
30
5
  termination;
31
6
  constructor(message, termination) {
@@ -162,6 +137,9 @@ function assertCause(cause) {
162
137
  case "internal":
163
138
  valid = code === "unclassified" && hasOnlyKeys(cause, ["area", "code"]);
164
139
  break;
140
+ case "budget":
141
+ valid = RUN_BUDGET_STOP_CODES.some((allowed) => allowed === code) && hasOnlyKeys(cause, ["area", "code"]);
142
+ break;
165
143
  case "resource":
166
144
  valid =
167
145
  typeof code === "string" &&
@@ -172,6 +150,20 @@ function assertCause(cause) {
172
150
  if (!valid)
173
151
  throw new TypeError("cause must be a bounded structured termination cause");
174
152
  }
153
+ export function parseSessionTerminationCauseCode(code, signal) {
154
+ if (code === "session.completed")
155
+ return { area: "completed" };
156
+ if (code === "session.user_abort")
157
+ return { area: "user", code: "abort" };
158
+ const dot = code.indexOf(".");
159
+ const cause = {
160
+ area: code.slice(0, dot),
161
+ code: code.slice(dot + 1),
162
+ ...(code === "process.signal" ? { signal } : {}),
163
+ };
164
+ assertCause(cause);
165
+ return cause;
166
+ }
175
167
  function assertClassifierInput(input) {
176
168
  if (!isRecord(input) || Object.keys(input).some((key) => !TOP_LEVEL_KEYS.has(key))) {
177
169
  throw new TypeError("input must contain only bounded structured termination fields");
@@ -346,6 +338,8 @@ function classifyCause(cause, source) {
346
338
  causeCode: "internal.unclassified",
347
339
  retryable: false,
348
340
  };
341
+ case "budget":
342
+ return { kind: "budget_exhausted", phase: "control", causeCode: `budget.${cause.code}`, retryable: false };
349
343
  case "resource":
350
344
  // §15.4: every resource cause is retryable; queue overflow surfaces at
351
345
  // the tool boundary, everything else at preflight admission.
@@ -375,6 +369,8 @@ function nextActionFor(classification, input) {
375
369
  return "No recovery action is required; continue with the next prompt.";
376
370
  case "user_abort":
377
371
  return "Review possible partial side effects, then retry only if intended.";
372
+ case "budget_exhausted":
373
+ return "Review partial work and remaining requests; start a new run only with an explicitly approved budget.";
378
374
  case "resource_pressure":
379
375
  return "Host resources are constrained; reduce load or wait for recovery, then retry.";
380
376
  case "provider_abort":