@mupt-ai/dari-gateway 0.2.0 → 0.2.1

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 (366) hide show
  1. package/dist/bun.d.ts +2 -0
  2. package/dist/bun.js +4 -0
  3. package/dist/context/eval_catalog.d.ts +3 -0
  4. package/dist/context/eval_catalog.js +7 -0
  5. package/dist/context/interaction_fingerprint.d.ts +27 -0
  6. package/dist/context/interaction_fingerprint.js +519 -0
  7. package/dist/context/interaction_fingerprint_format.d.ts +42 -0
  8. package/dist/context/interaction_fingerprint_format.js +113 -0
  9. package/dist/context/interaction_lease_depth.d.ts +2 -0
  10. package/dist/context/interaction_lease_depth.js +110 -0
  11. package/dist/context/lease_history.d.ts +7 -0
  12. package/dist/context/lease_history.js +158 -0
  13. package/dist/context/pricing.d.ts +4 -0
  14. package/dist/context/pricing.js +23 -0
  15. package/dist/context/provider_prompt_accounting.d.ts +14 -0
  16. package/dist/context/provider_prompt_accounting.js +187 -0
  17. package/dist/context/routing_context.d.ts +40 -0
  18. package/dist/context/routing_context.js +211 -0
  19. package/dist/http/auth.d.ts +2 -0
  20. package/dist/http/auth.js +35 -0
  21. package/dist/http/errors.d.ts +19 -0
  22. package/dist/http/errors.js +89 -0
  23. package/dist/http/handler.d.ts +12 -0
  24. package/dist/http/handler.js +81 -0
  25. package/dist/http/http2_server.d.ts +6 -0
  26. package/dist/http/http2_server.js +103 -0
  27. package/dist/http/serve.d.ts +20 -0
  28. package/dist/http/serve.js +78 -0
  29. package/dist/index.d.ts +6 -0
  30. package/dist/index.js +8 -0
  31. package/dist/ingress/anthropic_messages.d.ts +3 -0
  32. package/dist/ingress/anthropic_messages.js +122 -0
  33. package/dist/ingress/anthropic_models.d.ts +1 -0
  34. package/dist/ingress/anthropic_models.js +23 -0
  35. package/dist/ingress/chat_completions.d.ts +2 -0
  36. package/dist/ingress/chat_completions.js +37 -0
  37. package/dist/ingress/claude_code/request_context.d.ts +2 -0
  38. package/dist/ingress/claude_code/request_context.js +31 -0
  39. package/dist/ingress/codex.d.ts +3 -0
  40. package/dist/ingress/codex.js +65 -0
  41. package/dist/ingress/codex_models.d.ts +2 -0
  42. package/dist/ingress/codex_models.js +89 -0
  43. package/dist/ingress/json.d.ts +1 -0
  44. package/dist/ingress/json.js +95 -0
  45. package/dist/ingress/models.d.ts +1 -0
  46. package/dist/ingress/models.js +53 -0
  47. package/dist/interaction/capabilities.d.ts +3 -0
  48. package/dist/interaction/capabilities.js +24 -0
  49. package/dist/interaction/image.d.ts +4 -0
  50. package/dist/interaction/image.js +13 -0
  51. package/dist/interaction/portable_reasoning_state.d.ts +4 -0
  52. package/dist/interaction/portable_reasoning_state.js +18 -0
  53. package/dist/interaction/provider_continuation_state.d.ts +6 -0
  54. package/dist/interaction/provider_continuation_state.js +27 -0
  55. package/dist/interaction/tool_identity.d.ts +10 -0
  56. package/dist/interaction/tool_identity.js +41 -0
  57. package/dist/interaction/types.d.ts +203 -0
  58. package/dist/interaction/types.js +5 -0
  59. package/dist/models/context_limits.d.ts +2 -0
  60. package/dist/models/context_limits.js +7 -0
  61. package/dist/models/execution_provider.d.ts +8 -0
  62. package/dist/models/execution_provider.js +13 -0
  63. package/dist/models/gateways.d.ts +11 -0
  64. package/dist/models/gateways.js +45 -0
  65. package/dist/models/ids.d.ts +1 -0
  66. package/dist/models/ids.js +15 -0
  67. package/dist/models/provider_defaults.d.ts +4 -0
  68. package/dist/models/provider_defaults.js +41 -0
  69. package/dist/models/runtime_overrides.d.ts +4 -0
  70. package/dist/models/runtime_overrides.js +209 -0
  71. package/dist/observability/errors.d.ts +8 -0
  72. package/dist/observability/errors.js +11 -0
  73. package/dist/platform/platform.d.ts +152 -0
  74. package/dist/platform/platform.js +11 -0
  75. package/dist/platform/routing_contract.d.ts +2 -0
  76. package/dist/platform/routing_contract.js +5 -0
  77. package/dist/protocol/input/anthropic_messages.d.ts +2 -0
  78. package/dist/protocol/input/anthropic_messages.js +494 -0
  79. package/dist/protocol/input/chat_completions.d.ts +4 -0
  80. package/dist/protocol/input/chat_completions.js +212 -0
  81. package/dist/protocol/input/chat_completions_validation.d.ts +2 -0
  82. package/dist/protocol/input/chat_completions_validation.js +257 -0
  83. package/dist/protocol/input/openai_responses.d.ts +2 -0
  84. package/dist/protocol/input/openai_responses.js +666 -0
  85. package/dist/protocol/input/router_model.d.ts +7 -0
  86. package/dist/protocol/input/router_model.js +43 -0
  87. package/dist/protocol/output/anthropic_messages.d.ts +10 -0
  88. package/dist/protocol/output/anthropic_messages.js +15 -0
  89. package/dist/protocol/output/anthropic_messages_output.d.ts +10 -0
  90. package/dist/protocol/output/anthropic_messages_output.js +124 -0
  91. package/dist/protocol/output/anthropic_messages_stream.d.ts +16 -0
  92. package/dist/protocol/output/anthropic_messages_stream.js +267 -0
  93. package/dist/protocol/output/chat_completions.d.ts +29 -0
  94. package/dist/protocol/output/chat_completions.js +406 -0
  95. package/dist/protocol/output/chat_reasoning_detail.d.ts +2 -0
  96. package/dist/protocol/output/chat_reasoning_detail.js +13 -0
  97. package/dist/protocol/output/delivered_stream_snapshot.d.ts +10 -0
  98. package/dist/protocol/output/delivered_stream_snapshot.js +31 -0
  99. package/dist/protocol/output/openai_responses.d.ts +10 -0
  100. package/dist/protocol/output/openai_responses.js +14 -0
  101. package/dist/protocol/output/openai_responses_output.d.ts +14 -0
  102. package/dist/protocol/output/openai_responses_output.js +125 -0
  103. package/dist/protocol/output/openai_responses_stream.d.ts +18 -0
  104. package/dist/protocol/output/openai_responses_stream.js +546 -0
  105. package/dist/protocol/output/sse_stream.d.ts +31 -0
  106. package/dist/protocol/output/sse_stream.js +67 -0
  107. package/dist/providers/anthropic_safeguards.d.ts +11 -0
  108. package/dist/providers/anthropic_safeguards.js +81 -0
  109. package/dist/providers/aws_assume_role.d.ts +17 -0
  110. package/dist/providers/aws_assume_role.js +107 -0
  111. package/dist/providers/cancel_estimate.d.ts +43 -0
  112. package/dist/providers/cancel_estimate.js +89 -0
  113. package/dist/providers/execution.d.ts +72 -0
  114. package/dist/providers/execution.js +491 -0
  115. package/dist/providers/model_capabilities.d.ts +11 -0
  116. package/dist/providers/model_capabilities.js +29 -0
  117. package/dist/providers/pi.d.ts +65 -0
  118. package/dist/providers/pi.js +319 -0
  119. package/dist/providers/pi_context.d.ts +7 -0
  120. package/dist/providers/pi_context.js +405 -0
  121. package/dist/providers/pi_options.d.ts +11 -0
  122. package/dist/providers/pi_options.js +398 -0
  123. package/dist/providers/pi_output.d.ts +2 -0
  124. package/dist/providers/pi_output.js +453 -0
  125. package/dist/providers/provider_attempt_runner.d.ts +55 -0
  126. package/dist/providers/provider_attempt_runner.js +90 -0
  127. package/dist/providers/provider_call.d.ts +77 -0
  128. package/dist/providers/provider_call.js +292 -0
  129. package/dist/providers/provider_reported_cost.d.ts +10 -0
  130. package/dist/providers/provider_reported_cost.js +123 -0
  131. package/dist/providers/reasoning.d.ts +12 -0
  132. package/dist/providers/reasoning.js +30 -0
  133. package/dist/providers/response_capture.d.ts +23 -0
  134. package/dist/providers/response_capture.js +47 -0
  135. package/dist/providers/stream_finalization.d.ts +46 -0
  136. package/dist/providers/stream_finalization.js +165 -0
  137. package/dist/providers/subscription_limits.d.ts +31 -0
  138. package/dist/providers/subscription_limits.js +163 -0
  139. package/dist/providers/subscription_usage.d.ts +10 -0
  140. package/dist/providers/subscription_usage.js +79 -0
  141. package/dist/runtime/claude_code/auxiliary_routing.d.ts +3 -0
  142. package/dist/runtime/claude_code/auxiliary_routing.js +60 -0
  143. package/dist/runtime/customer_disconnect.d.ts +20 -0
  144. package/dist/runtime/customer_disconnect.js +49 -0
  145. package/dist/runtime/explicit_model.d.ts +4 -0
  146. package/dist/runtime/explicit_model.js +53 -0
  147. package/dist/runtime/harness_identity/conversation.d.ts +33 -0
  148. package/dist/runtime/harness_identity/conversation.js +39 -0
  149. package/dist/runtime/harness_identity/extract.d.ts +8 -0
  150. package/dist/runtime/harness_identity/extract.js +214 -0
  151. package/dist/runtime/harness_identity/index.d.ts +2 -0
  152. package/dist/runtime/harness_identity/index.js +2 -0
  153. package/dist/runtime/prepare_routed_completion.d.ts +33 -0
  154. package/dist/runtime/prepare_routed_completion.js +167 -0
  155. package/dist/runtime/provider_stream_lifecycle.d.ts +31 -0
  156. package/dist/runtime/provider_stream_lifecycle.js +88 -0
  157. package/dist/runtime/provider_stream_outcome.d.ts +23 -0
  158. package/dist/runtime/provider_stream_outcome.js +55 -0
  159. package/dist/runtime/request_tags.d.ts +7 -0
  160. package/dist/runtime/request_tags.js +33 -0
  161. package/dist/runtime/routed_completion.d.ts +17 -0
  162. package/dist/runtime/routed_completion.js +80 -0
  163. package/dist/runtime/routed_protocol.d.ts +30 -0
  164. package/dist/runtime/routed_protocol.js +1 -0
  165. package/dist/runtime/routed_runtime.d.ts +40 -0
  166. package/dist/runtime/routed_runtime.js +535 -0
  167. package/dist/runtime/routing_lease.d.ts +26 -0
  168. package/dist/runtime/routing_lease.js +210 -0
  169. package/dist/runtime/runtime_reporter.d.ts +71 -0
  170. package/dist/runtime/runtime_reporter.js +35 -0
  171. package/dist/self_host/config.d.ts +46 -0
  172. package/dist/self_host/config.js +105 -0
  173. package/dist/self_host/main.d.ts +16 -0
  174. package/dist/self_host/main.js +95 -0
  175. package/dist/self_host/platform.d.ts +13 -0
  176. package/dist/self_host/platform.js +50 -0
  177. package/dist/self_host/prefix_store.d.ts +46 -0
  178. package/dist/self_host/prefix_store.js +261 -0
  179. package/dist/self_host/resolve.d.ts +28 -0
  180. package/dist/self_host/resolve.js +171 -0
  181. package/dist/self_host/subscriptions/access.d.ts +10 -0
  182. package/dist/self_host/subscriptions/access.js +37 -0
  183. package/dist/self_host/subscriptions/http.d.ts +15 -0
  184. package/dist/self_host/subscriptions/http.js +187 -0
  185. package/dist/self_host/subscriptions/index.d.ts +24 -0
  186. package/dist/self_host/subscriptions/index.js +24 -0
  187. package/dist/self_host/subscriptions/oauth.d.ts +55 -0
  188. package/dist/self_host/subscriptions/oauth.js +281 -0
  189. package/dist/self_host/subscriptions/store.d.ts +78 -0
  190. package/dist/self_host/subscriptions/store.js +235 -0
  191. package/dist/strategies/auto_routing_selector.d.ts +12 -0
  192. package/dist/strategies/auto_routing_selector.js +61 -0
  193. package/dist/strategies/eval_relevance.d.ts +17 -0
  194. package/dist/strategies/eval_relevance.js +32 -0
  195. package/dist/strategies/fallback_decision.d.ts +8 -0
  196. package/dist/strategies/fallback_decision.js +17 -0
  197. package/dist/strategies/priority_selector.d.ts +7 -0
  198. package/dist/strategies/priority_selector.js +37 -0
  199. package/dist/strategies/route_decision.d.ts +22 -0
  200. package/dist/strategies/route_decision.js +65 -0
  201. package/dist/strategies/routing.d.ts +74 -0
  202. package/dist/strategies/routing.js +280 -0
  203. package/dist/strategies/selector_projection.d.ts +15 -0
  204. package/dist/strategies/selector_projection.js +161 -0
  205. package/dist/telemetry/background.d.ts +7 -0
  206. package/dist/telemetry/background.js +33 -0
  207. package/dist/telemetry/benchmark_replay.d.ts +37 -0
  208. package/dist/telemetry/benchmark_replay.js +108 -0
  209. package/dist/telemetry/billing_finalization.d.ts +64 -0
  210. package/dist/telemetry/billing_finalization.js +96 -0
  211. package/dist/telemetry/ingest_values.d.ts +4 -0
  212. package/dist/telemetry/ingest_values.js +12 -0
  213. package/dist/telemetry/model_cost.d.ts +3 -0
  214. package/dist/telemetry/model_cost.js +15 -0
  215. package/dist/telemetry/prefix_state.d.ts +47 -0
  216. package/dist/telemetry/prefix_state.js +116 -0
  217. package/dist/telemetry/report.d.ts +88 -0
  218. package/dist/telemetry/report.js +621 -0
  219. package/dist/telemetry/requests/interaction_observability.d.ts +45 -0
  220. package/dist/telemetry/requests/interaction_observability.js +180 -0
  221. package/dist/telemetry/requests/retained_interaction_request.d.ts +8 -0
  222. package/dist/telemetry/requests/retained_interaction_request.js +10 -0
  223. package/dist/telemetry/scrub.d.ts +2 -0
  224. package/dist/telemetry/scrub.js +31 -0
  225. package/dist/telemetry/skills/claude/catalog.d.ts +6 -0
  226. package/dist/telemetry/skills/claude/catalog.js +99 -0
  227. package/dist/telemetry/skills/claude/file_reads.d.ts +4 -0
  228. package/dist/telemetry/skills/claude/file_reads.js +110 -0
  229. package/dist/telemetry/skills/claude/observations.d.ts +3 -0
  230. package/dist/telemetry/skills/claude/observations.js +366 -0
  231. package/dist/telemetry/skills/codex/catalog.d.ts +11 -0
  232. package/dist/telemetry/skills/codex/catalog.js +138 -0
  233. package/dist/telemetry/skills/codex/exec_file_reads.d.ts +9 -0
  234. package/dist/telemetry/skills/codex/exec_file_reads.js +36 -0
  235. package/dist/telemetry/skills/codex/explicit.d.ts +3 -0
  236. package/dist/telemetry/skills/codex/explicit.js +90 -0
  237. package/dist/telemetry/skills/codex/file_reads.d.ts +4 -0
  238. package/dist/telemetry/skills/codex/file_reads.js +37 -0
  239. package/dist/telemetry/skills/codex/identity.d.ts +2 -0
  240. package/dist/telemetry/skills/codex/identity.js +20 -0
  241. package/dist/telemetry/skills/observations.d.ts +21 -0
  242. package/dist/telemetry/skills/observations.js +41 -0
  243. package/dist/telemetry/skills/paths.d.ts +11 -0
  244. package/dist/telemetry/skills/paths.js +61 -0
  245. package/dist/telemetry/skills/pi.d.ts +6 -0
  246. package/dist/telemetry/skills/pi.js +223 -0
  247. package/dist/telemetry/skills/shell_file_reads.d.ts +7 -0
  248. package/dist/telemetry/skills/shell_file_reads.js +226 -0
  249. package/dist/telemetry/skills/shell_words.d.ts +13 -0
  250. package/dist/telemetry/skills/shell_words.js +189 -0
  251. package/dist/telemetry/tools/input.d.ts +2 -0
  252. package/dist/telemetry/tools/input.js +14 -0
  253. package/dist/telemetry/tools/observations.d.ts +29 -0
  254. package/dist/telemetry/tools/observations.js +247 -0
  255. package/dist/telemetry/usage.d.ts +57 -0
  256. package/dist/telemetry/usage.js +136 -0
  257. package/dist/types.d.ts +94 -0
  258. package/dist/types.js +1 -0
  259. package/package.json +21 -6
  260. package/src/bun.ts +2 -2
  261. package/src/context/eval_catalog.ts +1 -1
  262. package/src/context/interaction_fingerprint.ts +9 -9
  263. package/src/context/interaction_fingerprint_format.ts +1 -1
  264. package/src/context/interaction_lease_depth.ts +1 -1
  265. package/src/context/pricing.ts +1 -1
  266. package/src/context/provider_prompt_accounting.ts +5 -5
  267. package/src/context/routing_context.ts +16 -16
  268. package/src/http/auth.ts +1 -1
  269. package/src/http/handler.ts +8 -8
  270. package/src/http/serve.ts +3 -3
  271. package/src/index.ts +6 -6
  272. package/src/ingress/anthropic_messages.ts +12 -12
  273. package/src/ingress/anthropic_models.ts +1 -1
  274. package/src/ingress/chat_completions.ts +9 -9
  275. package/src/ingress/claude_code/request_context.ts +2 -2
  276. package/src/ingress/codex.ts +10 -10
  277. package/src/ingress/codex_models.ts +4 -4
  278. package/src/ingress/json.ts +1 -1
  279. package/src/ingress/models.ts +9 -9
  280. package/src/interaction/capabilities.ts +1 -1
  281. package/src/interaction/portable_reasoning_state.ts +1 -1
  282. package/src/interaction/provider_continuation_state.ts +1 -1
  283. package/src/interaction/tool_identity.ts +2 -2
  284. package/src/models/context_limits.ts +1 -1
  285. package/src/models/execution_provider.ts +1 -1
  286. package/src/models/ids.ts +1 -1
  287. package/src/models/provider_defaults.ts +1 -1
  288. package/src/models/runtime_overrides.ts +1 -1
  289. package/src/observability/errors.ts +2 -2
  290. package/src/platform/platform.ts +4 -4
  291. package/src/protocol/input/anthropic_messages.ts +7 -7
  292. package/src/protocol/input/chat_completions.ts +5 -5
  293. package/src/protocol/input/chat_completions_validation.ts +4 -4
  294. package/src/protocol/input/openai_responses.ts +6 -6
  295. package/src/protocol/output/anthropic_messages.ts +3 -3
  296. package/src/protocol/output/anthropic_messages_output.ts +6 -4
  297. package/src/protocol/output/anthropic_messages_stream.ts +7 -7
  298. package/src/protocol/output/chat_completions.ts +13 -13
  299. package/src/protocol/output/chat_reasoning_detail.ts +1 -1
  300. package/src/protocol/output/openai_responses.ts +3 -3
  301. package/src/protocol/output/openai_responses_output.ts +4 -2
  302. package/src/protocol/output/openai_responses_stream.ts +6 -6
  303. package/src/protocol/output/sse_stream.ts +3 -3
  304. package/src/providers/anthropic_safeguards.ts +2 -2
  305. package/src/providers/aws_assume_role.ts +2 -2
  306. package/src/providers/cancel_estimate.ts +1 -1
  307. package/src/providers/execution.ts +17 -17
  308. package/src/providers/pi.ts +14 -14
  309. package/src/providers/pi_context.ts +6 -6
  310. package/src/providers/pi_options.ts +10 -10
  311. package/src/providers/pi_output.ts +5 -5
  312. package/src/providers/provider_attempt_runner.ts +1 -1
  313. package/src/providers/provider_call.ts +14 -14
  314. package/src/providers/provider_reported_cost.ts +3 -3
  315. package/src/providers/reasoning.ts +2 -2
  316. package/src/providers/stream_finalization.ts +9 -9
  317. package/src/providers/subscription_limits.ts +3 -3
  318. package/src/runtime/claude_code/auxiliary_routing.ts +5 -5
  319. package/src/runtime/customer_disconnect.ts +1 -1
  320. package/src/runtime/explicit_model.ts +4 -4
  321. package/src/runtime/harness_identity/conversation.ts +1 -1
  322. package/src/runtime/harness_identity/extract.ts +3 -3
  323. package/src/runtime/harness_identity/index.ts +2 -2
  324. package/src/runtime/prepare_routed_completion.ts +13 -13
  325. package/src/runtime/provider_stream_lifecycle.ts +1 -1
  326. package/src/runtime/provider_stream_outcome.ts +2 -2
  327. package/src/runtime/request_tags.ts +2 -2
  328. package/src/runtime/routed_completion.ts +11 -11
  329. package/src/runtime/routed_protocol.ts +2 -2
  330. package/src/runtime/routed_runtime.ts +20 -19
  331. package/src/runtime/routing_lease.ts +7 -7
  332. package/src/runtime/runtime_reporter.ts +3 -3
  333. package/src/self_host/main.ts +12 -12
  334. package/src/self_host/platform.ts +5 -5
  335. package/src/self_host/prefix_store.ts +2 -2
  336. package/src/self_host/resolve.ts +6 -6
  337. package/src/self_host/subscriptions/access.ts +2 -2
  338. package/src/self_host/subscriptions/http.ts +2 -2
  339. package/src/self_host/subscriptions/index.ts +4 -4
  340. package/src/self_host/subscriptions/store.ts +1 -1
  341. package/src/strategies/auto_routing_selector.ts +2 -2
  342. package/src/strategies/eval_relevance.ts +3 -3
  343. package/src/strategies/priority_selector.ts +1 -1
  344. package/src/strategies/route_decision.ts +7 -7
  345. package/src/strategies/routing.ts +10 -10
  346. package/src/strategies/selector_projection.ts +2 -2
  347. package/src/telemetry/billing_finalization.ts +3 -3
  348. package/src/telemetry/model_cost.ts +1 -1
  349. package/src/telemetry/prefix_state.ts +4 -4
  350. package/src/telemetry/report.ts +21 -21
  351. package/src/telemetry/requests/interaction_observability.ts +1 -1
  352. package/src/telemetry/requests/retained_interaction_request.ts +1 -1
  353. package/src/telemetry/skills/claude/catalog.ts +1 -1
  354. package/src/telemetry/skills/claude/file_reads.ts +6 -6
  355. package/src/telemetry/skills/claude/observations.ts +3 -3
  356. package/src/telemetry/skills/codex/catalog.ts +3 -3
  357. package/src/telemetry/skills/codex/exec_file_reads.ts +4 -4
  358. package/src/telemetry/skills/codex/explicit.ts +3 -3
  359. package/src/telemetry/skills/codex/file_reads.ts +5 -5
  360. package/src/telemetry/skills/observations.ts +7 -7
  361. package/src/telemetry/skills/pi.ts +3 -3
  362. package/src/telemetry/skills/shell_file_reads.ts +2 -2
  363. package/src/telemetry/skills/shell_words.ts +1 -1
  364. package/src/telemetry/tools/input.ts +1 -1
  365. package/src/telemetry/tools/observations.ts +9 -9
  366. package/src/telemetry/usage.ts +5 -5
@@ -0,0 +1,33 @@
1
+ import type { SourceProtocol } from "../../interaction/types.js";
2
+ export type HarnessConversationIdentity = {
3
+ kind: "codex_thread";
4
+ value: string;
5
+ parentThreadId?: string;
6
+ qualifiers?: string[];
7
+ userTurnId?: string;
8
+ } | {
9
+ kind: "claude_code_session";
10
+ value: string;
11
+ qualifiers?: string[];
12
+ } | {
13
+ kind: "openai_chat_session";
14
+ value: string;
15
+ qualifiers?: string[];
16
+ };
17
+ export type HarnessConversationScope = {
18
+ organizationId: string;
19
+ routerId: string;
20
+ apiKeyId: string | null;
21
+ attributedUserId: string | null;
22
+ };
23
+ export declare function scopedHarnessSessionId(args: {
24
+ identity: HarnessConversationIdentity;
25
+ sourceProtocol: SourceProtocol;
26
+ scope: HarnessConversationScope;
27
+ }): string;
28
+ export declare function scopedHarnessConversationId(args: {
29
+ identity: HarnessConversationIdentity;
30
+ sourceProtocol: SourceProtocol;
31
+ scope: HarnessConversationScope;
32
+ conversationPrefix: string;
33
+ }): string;
@@ -0,0 +1,39 @@
1
+ import { createHash } from "node:crypto";
2
+ const PREFIX = "hconv_";
3
+ // The conversation id is the fallback provider prompt_cache_key for callers
4
+ // that send none (Codex sends thread metadata, not a cache key). OpenAI rejects
5
+ // a prompt_cache_key longer than 64 characters, so the id must fit that budget.
6
+ const MAX_CONVERSATION_ID_CHARS = 64;
7
+ const DIGEST_CHARS = MAX_CONVERSATION_ID_CHARS - PREFIX.length;
8
+ export function scopedHarnessSessionId(args) {
9
+ const identity = args.identity.kind === "codex_thread" && args.identity.parentThreadId
10
+ ? { ...args.identity, value: args.identity.parentThreadId }
11
+ : args.identity;
12
+ return scopedHarnessId({ ...args, identity });
13
+ }
14
+ export function scopedHarnessConversationId(args) {
15
+ return scopedHarnessId(args, args.conversationPrefix);
16
+ }
17
+ function scopedHarnessId(args, conversationPrefix) {
18
+ const subject = args.scope.apiKeyId !== null
19
+ ? ["api_key", args.scope.apiKeyId]
20
+ : args.scope.attributedUserId !== null
21
+ ? ["user", args.scope.attributedUserId]
22
+ : ["organization_runtime", args.scope.organizationId];
23
+ const identity = [
24
+ args.identity.kind,
25
+ args.identity.value,
26
+ ...(args.identity.qualifiers ?? []),
27
+ ];
28
+ const digest = createHash("sha256")
29
+ .update(JSON.stringify([
30
+ args.scope.organizationId,
31
+ args.scope.routerId,
32
+ subject,
33
+ args.sourceProtocol,
34
+ ...identity,
35
+ ...(conversationPrefix === undefined ? [] : [conversationPrefix]),
36
+ ]))
37
+ .digest("hex");
38
+ return `${PREFIX}${digest.slice(0, DIGEST_CHARS)}`;
39
+ }
@@ -0,0 +1,8 @@
1
+ import type { AgentRequestContext, InteractionRequestPurpose } from "../../interaction/types.js";
2
+ import type { HarnessConversationIdentity } from "./conversation.js";
3
+ export declare function chatCompletionsConversationIdentity(headers: Headers, promptCacheKey?: string): HarnessConversationIdentity | undefined;
4
+ export declare function openCodeRequestContext(headers: Headers): AgentRequestContext | undefined;
5
+ export declare function codexConversationIdentity(headers: Headers, payload: Record<string, unknown>): HarnessConversationIdentity | undefined;
6
+ export declare function codexRequestPurpose(headers: Headers, payload: Record<string, unknown>): InteractionRequestPurpose | undefined;
7
+ export declare function codexRequestContext(headers: Headers, payload: Record<string, unknown>): AgentRequestContext | undefined;
8
+ export declare function claudeCodeConversationIdentity(headers: Headers, metadataSessionId?: string): HarnessConversationIdentity | undefined;
@@ -0,0 +1,214 @@
1
+ import { isRecord } from "@mupt-ai/dari-router/policy-engine";
2
+ import { HttpError } from "../../http/errors.js";
3
+ const MAX_ID_CHARS = 200;
4
+ export function chatCompletionsConversationIdentity(headers, promptCacheKey) {
5
+ // x-session-affinity is the authoritative Chat Completions identity.
6
+ // Fall back to prompt_cache_key from the request body for callers that
7
+ // send a stable cache key without the affinity header, so append-only
8
+ // sessions (growing message history) stay grouped under one conversation.
9
+ const sessionId = boundedIdentity(headers.get("x-session-affinity"), "x-session-affinity") ?? boundedIdentity(promptCacheKey, "prompt_cache_key");
10
+ if (sessionId === undefined)
11
+ return undefined;
12
+ // OpenCode sends a subagent's parent session as its affinity, so subagents
13
+ // share the parent's session. Scope each one to its own composite identity,
14
+ // as Claude Code subagents are, so it keeps its own conversation and lease.
15
+ const subagentId = openCodeSubagentId(headers);
16
+ return {
17
+ kind: "openai_chat_session",
18
+ value: sessionId,
19
+ ...(subagentId === undefined ? {} : { qualifiers: [subagentId] }),
20
+ };
21
+ }
22
+ // OpenCode names the session behind every request, and a subagent's parent
23
+ // session too. The `dari opencode` plugin adds the request kind and agent,
24
+ // which OpenCode does not send itself. Like Claude Code's headers, these are
25
+ // client-supplied routing hints, never inferred from prompt text.
26
+ export function openCodeRequestContext(headers) {
27
+ if (boundedIdentity(headers.get("x-opencode-session-id"), "x-opencode-session-id") === undefined) {
28
+ return undefined;
29
+ }
30
+ const kind = headers.get("x-opencode-request-kind")?.trim();
31
+ const subagentId = openCodeSubagentId(headers);
32
+ const requestClass = kind === "compaction" ? "compaction"
33
+ : kind === "title" || kind === "generate" ? "auxiliary"
34
+ : subagentId === undefined ? "main" : "subagent";
35
+ return {
36
+ requestClass,
37
+ ...(subagentId === undefined ? {} : {
38
+ agentId: subagentId,
39
+ parentAgentId: boundedIdentity(headers.get("x-opencode-parent-session-id"), "x-opencode-parent-session-id"),
40
+ }),
41
+ agentType: boundedIdentity(headers.get("x-opencode-agent"), "x-opencode-agent"),
42
+ };
43
+ }
44
+ function openCodeSubagentId(headers) {
45
+ const parent = boundedIdentity(headers.get("x-opencode-parent-session-id"), "x-opencode-parent-session-id");
46
+ return parent === undefined
47
+ ? undefined
48
+ : boundedIdentity(headers.get("x-opencode-session-id"), "x-opencode-session-id");
49
+ }
50
+ export function codexConversationIdentity(headers, payload) {
51
+ const clientMetadata = isRecord(payload.client_metadata)
52
+ ? payload.client_metadata
53
+ : undefined;
54
+ const turnMetadata = codexTurnMetadataCollection(headers, payload);
55
+ if (turnMetadata.length === 0) {
56
+ return undefined;
57
+ }
58
+ const candidates = [
59
+ ...turnMetadata.map((metadata) => uuidIdentity(metadata.thread_id, "x-codex-turn-metadata.thread_id")),
60
+ uuidIdentity(headers.get("thread-id"), "thread-id"),
61
+ uuidIdentity(clientMetadata?.thread_id, "client_metadata.thread_id"),
62
+ ].filter((value) => value !== undefined);
63
+ if (candidates.length === 0) {
64
+ return undefined;
65
+ }
66
+ const [threadId] = candidates;
67
+ if (candidates.some((candidate) => candidate !== threadId)) {
68
+ throw new HttpError(400, "Codex thread identity fields must agree.", "invalid_request_error", "thread-id");
69
+ }
70
+ const userTurnIds = turnMetadata
71
+ .map((metadata) => uuidIdentity(metadata.turn_id, "x-codex-turn-metadata.turn_id"))
72
+ .filter((value) => value !== undefined);
73
+ const [userTurnId] = userTurnIds;
74
+ if (userTurnIds.some((candidate) => candidate !== userTurnId)) {
75
+ throw new HttpError(400, "Codex turn identity fields must agree.", "invalid_request_error", "x-codex-turn-metadata.turn_id");
76
+ }
77
+ const parentThreadIds = turnMetadata
78
+ .map((metadata) => uuidIdentity(metadata.parent_thread_id, "x-codex-turn-metadata.parent_thread_id"))
79
+ .filter((value) => value !== undefined);
80
+ const [parentThreadId] = parentThreadIds;
81
+ if (parentThreadIds.some((candidate) => candidate !== parentThreadId)) {
82
+ throw new HttpError(400, "Codex parent thread identity fields must agree.", "invalid_request_error", "x-codex-turn-metadata.parent_thread_id");
83
+ }
84
+ return {
85
+ kind: "codex_thread",
86
+ value: threadId,
87
+ ...(parentThreadId === undefined ? {} : { parentThreadId }),
88
+ ...(userTurnId === undefined ? {} : { userTurnId }),
89
+ };
90
+ }
91
+ export function codexRequestPurpose(headers, payload) {
92
+ const turnMetadata = codexTurnMetadataCollection(headers, payload);
93
+ return turnMetadata.length > 0 && turnMetadata.every(isCodexMemoryExtraction)
94
+ ? "memory_extraction"
95
+ : undefined;
96
+ }
97
+ export function codexRequestContext(headers, payload) {
98
+ const metadata = codexTurnMetadataCollection(headers, payload);
99
+ if (metadata.length === 0)
100
+ return undefined;
101
+ // HTTP and body projections must agree before either can classify a turn.
102
+ const kinds = new Set(metadata.map((entry) => entry.request_kind));
103
+ const agents = new Set(metadata.map((entry) => entry.subagent_kind));
104
+ if (kinds.size > 1 || agents.size > 1) {
105
+ throw new HttpError(400, "Codex request classification fields must agree.", "invalid_request_error", "x-codex-turn-metadata");
106
+ }
107
+ const [kind] = kinds;
108
+ const [agentKind] = agents;
109
+ const entry = metadata[0];
110
+ const agentId = uuidIdentity(entry.thread_id, "x-codex-turn-metadata.thread_id");
111
+ const requestClass = kind === "compaction" ? "compaction"
112
+ : kind === "memory" || kind === "prewarm" ? "auxiliary"
113
+ : kind === "turn" && agentKind === "memory_consolidation" ? "auxiliary"
114
+ : kind === "turn" && agentKind === "compact" ? "compaction"
115
+ : kind === "turn" && agentKind !== undefined ? "subagent"
116
+ : kind === "turn" ? "main" : "unknown";
117
+ return {
118
+ requestClass,
119
+ ...(requestClass === "subagent" && agentId !== undefined ? { agentId } : {}),
120
+ parentAgentId: uuidIdentity(entry.parent_thread_id, "x-codex-turn-metadata.parent_thread_id"),
121
+ agentType: boundedIdentity(agentKind, "x-codex-turn-metadata.subagent_kind"),
122
+ };
123
+ }
124
+ export function claudeCodeConversationIdentity(headers, metadataSessionId) {
125
+ const candidates = [
126
+ uuidIdentity(headers.get("x-claude-code-session-id"), "x-claude-code-session-id"),
127
+ uuidIdentity(metadataSessionId, "metadata.user_id.session_id"),
128
+ ].filter((value) => value !== undefined);
129
+ if (candidates.length === 0)
130
+ return undefined;
131
+ const [sessionId] = candidates;
132
+ if (candidates.some((candidate) => candidate !== sessionId)) {
133
+ throw new HttpError(400, "Claude Code session identity fields must agree.", "invalid_request_error", "x-claude-code-session-id");
134
+ }
135
+ // Claude Code reuses the parent session UUID for every subagent, but gives
136
+ // each subagent a stable agent header. Keep the parent thread on the bare
137
+ // session identity and scope each subagent to its own composite identity.
138
+ // Treat this as an opaque Claude identifier. Besides ordinary subagent IDs,
139
+ // Claude may send labeled agents or Agent Teams identities such as
140
+ // `reviewer@backend`; Dari only needs a stable, bounded value to hash.
141
+ const agentId = boundedIdentity(headers.get("x-claude-code-agent-id"), "x-claude-code-agent-id");
142
+ return {
143
+ kind: "claude_code_session",
144
+ value: sessionId,
145
+ ...(agentId === undefined ? {} : { qualifiers: [agentId] }),
146
+ };
147
+ }
148
+ function isCodexMemoryExtraction(metadata) {
149
+ if (metadata.request_kind !== "memory" ||
150
+ metadata.thread_source !== "memory_consolidation") {
151
+ return false;
152
+ }
153
+ // Codex deliberately omits canonical turn identity for detached phase-1
154
+ // memory jobs, while compatibility projections still carry the live root
155
+ // thread UUID. Phase-2 consolidation agents use ordinary turn metadata and
156
+ // their own thread identities, so they do not match this shape.
157
+ return [
158
+ "session_id",
159
+ "thread_id",
160
+ "turn_id",
161
+ "root_turn_id",
162
+ "window_id",
163
+ "forked_from_thread_id",
164
+ ].every((field) => metadata[field] === undefined);
165
+ }
166
+ function codexTurnMetadataCollection(headers, payload) {
167
+ const clientMetadata = isRecord(payload.client_metadata)
168
+ ? payload.client_metadata
169
+ : undefined;
170
+ return [
171
+ codexTurnMetadata(headers.get("x-codex-turn-metadata"), "x-codex-turn-metadata"),
172
+ codexTurnMetadata(clientMetadata?.["x-codex-turn-metadata"], "client_metadata.x-codex-turn-metadata"),
173
+ ].filter((value) => value !== undefined);
174
+ }
175
+ function boundedIdentity(value, field) {
176
+ if (value === undefined || value === null)
177
+ return undefined;
178
+ if (typeof value !== "string") {
179
+ throw new HttpError(400, `${field} must be a string.`, "invalid_request_error", field);
180
+ }
181
+ const normalized = value.trim();
182
+ if (!normalized)
183
+ return undefined;
184
+ if (normalized.length > MAX_ID_CHARS) {
185
+ throw new HttpError(400, `${field} must not exceed ${MAX_ID_CHARS} characters.`, "invalid_request_error", field);
186
+ }
187
+ return normalized;
188
+ }
189
+ function uuidIdentity(value, field) {
190
+ const normalized = boundedIdentity(value, field);
191
+ if (normalized === undefined)
192
+ return undefined;
193
+ const canonical = normalized.toLowerCase();
194
+ if (!/^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$/.test(canonical)) {
195
+ throw new HttpError(400, `${field} must be a UUID.`, "invalid_request_error", field);
196
+ }
197
+ return canonical;
198
+ }
199
+ function codexTurnMetadata(raw, field) {
200
+ if (raw === undefined || raw === null)
201
+ return undefined;
202
+ if (typeof raw !== "string") {
203
+ throw new HttpError(400, `${field} must be a JSON string.`, "invalid_request_error", field);
204
+ }
205
+ try {
206
+ const parsed = JSON.parse(raw);
207
+ if (!isRecord(parsed))
208
+ throw new Error("not an object");
209
+ return parsed;
210
+ }
211
+ catch {
212
+ throw new HttpError(400, `${field} must contain a JSON object.`, "invalid_request_error", field);
213
+ }
214
+ }
@@ -0,0 +1,2 @@
1
+ export { scopedHarnessConversationId, scopedHarnessSessionId, type HarnessConversationIdentity, type HarnessConversationScope, } from "./conversation.js";
2
+ export { chatCompletionsConversationIdentity, claudeCodeConversationIdentity, codexConversationIdentity, codexRequestPurpose, codexRequestContext, openCodeRequestContext, } from "./extract.js";
@@ -0,0 +1,2 @@
1
+ export { scopedHarnessConversationId, scopedHarnessSessionId, } from "./conversation.js";
2
+ export { chatCompletionsConversationIdentity, claudeCodeConversationIdentity, codexConversationIdentity, codexRequestPurpose, codexRequestContext, openCodeRequestContext, } from "./extract.js";
@@ -0,0 +1,33 @@
1
+ import { type RoutingContext } from "../context/routing_context.js";
2
+ import { type InteractionRequest } from "../interaction/types.js";
3
+ import { type RequestTags } from "../platform/platform.js";
4
+ import type { ClientHarness, ResolvedRouter } from "../types.js";
5
+ import type { RoutedRuntimeReporter } from "./runtime_reporter.js";
6
+ import type { RoutedProtocol } from "./routed_protocol.js";
7
+ import { type HarnessConversationIdentity } from "./harness_identity/index.js";
8
+ export type PreparedRoutedCompletion = {
9
+ requestId: string;
10
+ routerId: string;
11
+ receivedAt: Date;
12
+ interaction: InteractionRequest;
13
+ protocol: RoutedProtocol;
14
+ credentials: ResolvedRouter;
15
+ billable: boolean;
16
+ tags: RequestTags;
17
+ harnessConversationIdentity?: HarnessConversationIdentity;
18
+ routing: RoutingContext;
19
+ reporter: RoutedRuntimeReporter;
20
+ };
21
+ export declare function prepareRoutedCompletion(args: {
22
+ routerId: string;
23
+ apiKey: string;
24
+ interaction: InteractionRequest;
25
+ protocol: RoutedProtocol;
26
+ receivedAt: Date;
27
+ startedMs: number;
28
+ requestId: string;
29
+ clientRequestId: string | null;
30
+ tagsHeader: string | null;
31
+ clientHarness?: ClientHarness;
32
+ harnessConversationIdentity?: HarnessConversationIdentity;
33
+ }): Promise<PreparedRoutedCompletion>;
@@ -0,0 +1,167 @@
1
+ import { interactionConversationPrefix } from "../context/interaction_fingerprint.js";
2
+ import { buildRoutingContext, derivePrefixLookupHashes, } from "../context/routing_context.js";
3
+ import { isBackgroundRequest } from "../interaction/types.js";
4
+ import { executionProviderForModel } from "../models/execution_provider.js";
5
+ import { gatewayPlatform } from "../platform/platform.js";
6
+ import { resolveRouter } from "../strategies/routing.js";
7
+ import { RequestReporter } from "../telemetry/report.js";
8
+ import { RoutingBillingFinalization } from "../telemetry/billing_finalization.js";
9
+ import { requestTags } from "./request_tags.js";
10
+ import { scopedHarnessConversationId, scopedHarnessSessionId, } from "./harness_identity/index.js";
11
+ export async function prepareRoutedCompletion(args) {
12
+ const tags = requestTags(args.tagsHeader);
13
+ // Eval relevance draws from the public catalog, which resolve only returns
14
+ // on request.
15
+ const resolveRequest = {
16
+ routerId: args.routerId,
17
+ apiKey: args.apiKey,
18
+ includePublicEvalCatalog: true,
19
+ };
20
+ // Direct /v1 callers are authenticated by API key, so their canonical
21
+ // organization router is not known until this resolve completes. Fingerprint
22
+ // the stable public alias here; prefix lookup remains tenant-safe because the
23
+ // platform scopes every hash query to the resolved canonical router.
24
+ const prefixFingerprintRouterId = args.routerId;
25
+ const background = isBackgroundRequest(args.interaction);
26
+ const prefixHashes = background ? [] : derivePrefixLookupHashes(prefixFingerprintRouterId, args.interaction);
27
+ let credentials = await resolveRouter({
28
+ ...resolveRequest,
29
+ prefixHashes,
30
+ clientHarness: args.clientHarness,
31
+ });
32
+ const canonicalRouterId = credentials.router_id;
33
+ const organizationId = credentials.organization_id;
34
+ const billingFinalization = new RoutingBillingFinalization({
35
+ requestId: args.requestId,
36
+ organizationId,
37
+ });
38
+ const harnessScope = {
39
+ organizationId: credentials.organization_id,
40
+ routerId: credentials.router_id,
41
+ apiKeyId: credentials.api_key_id,
42
+ attributedUserId: credentials.attributed_user_id,
43
+ };
44
+ const agentSessionId = args.harnessConversationIdentity === undefined
45
+ ? undefined
46
+ : scopedHarnessSessionId({
47
+ // Subagent qualifiers scope a conversation, not the session it belongs to.
48
+ identity: { ...args.harnessConversationIdentity, qualifiers: undefined },
49
+ sourceProtocol: args.interaction.sourceProtocol,
50
+ scope: harnessScope,
51
+ });
52
+ const harnessConversationId = args.harnessConversationIdentity === undefined
53
+ ? undefined
54
+ : scopedHarnessConversationId({
55
+ identity: args.harnessConversationIdentity,
56
+ sourceProtocol: args.interaction.sourceProtocol,
57
+ scope: harnessScope,
58
+ conversationPrefix: args.interaction.agentContext === undefined
59
+ ? interactionConversationPrefix(args.interaction)
60
+ : JSON.stringify([
61
+ args.interaction.agentContext.requestClass,
62
+ interactionConversationPrefix(args.interaction),
63
+ ]),
64
+ });
65
+ if (!background && harnessConversationId !== undefined) {
66
+ // Hash matches may contain only older history after a client rewrites its
67
+ // tail. Always resolve the trusted conversation too so lease recovery sees
68
+ // its latest serving row, not just whichever old prefixes still match.
69
+ // Unrelated work under the same harness session has a different id.
70
+ const conversationCredentials = await resolveRouter({
71
+ ...resolveRequest,
72
+ prefixHashes,
73
+ conversationId: harnessConversationId,
74
+ clientHarness: args.clientHarness,
75
+ });
76
+ if (conversationCredentials.organization_id !== organizationId ||
77
+ conversationCredentials.router_id !== canonicalRouterId) {
78
+ throw new Error("Repeated router resolution changed request ownership.");
79
+ }
80
+ credentials = conversationCredentials;
81
+ }
82
+ credentials = await withProviderCredentials(credentials, args.apiKey);
83
+ const billable = true;
84
+ const routing = await buildRoutingContext({
85
+ routerId: prefixFingerprintRouterId,
86
+ interaction: args.interaction,
87
+ credentials,
88
+ explicitConversationId: harnessConversationId,
89
+ receivedAt: args.receivedAt,
90
+ });
91
+ const candidateResolution = routing.candidateResolution;
92
+ const reporter = new RequestReporter({
93
+ requestId: args.requestId,
94
+ clientRequestId: args.clientRequestId,
95
+ tags,
96
+ credentials,
97
+ routerId: canonicalRouterId,
98
+ interaction: args.interaction,
99
+ harnessConversationIdentity: args.harnessConversationIdentity,
100
+ leaseDepth: routing.leaseDepth,
101
+ providerBlockDepthFor: routing.providerBlockDepthFor,
102
+ zdr: routing.zdr,
103
+ strategy: candidateResolution.strategy,
104
+ receivedAt: args.receivedAt,
105
+ startedMs: args.startedMs,
106
+ conversationId: routing.conversationId,
107
+ isNewConversation: routing.isNewConversation,
108
+ agentSessionId,
109
+ identityMatchDepth: routing.identityMatchDepth,
110
+ identityHit: routing.identityHit,
111
+ hits: routing.hits,
112
+ costEstimates: routing.reportingCostEstimates,
113
+ pruning: reportedPruning(candidateResolution.pruning, routing.imageCapabilityPrunedModels),
114
+ pricing: routing.pricing,
115
+ chainByModel: routing.prefix.chainByModel,
116
+ looseChain: routing.prefix.looseChain,
117
+ targetsByModel: routing.targetsByModel,
118
+ fingerprints: routing.prefix.fingerprints,
119
+ billingFinalization,
120
+ });
121
+ return {
122
+ requestId: args.requestId,
123
+ routerId: canonicalRouterId,
124
+ receivedAt: args.receivedAt,
125
+ interaction: args.interaction,
126
+ protocol: args.protocol,
127
+ credentials,
128
+ billable,
129
+ tags,
130
+ harnessConversationIdentity: args.harnessConversationIdentity,
131
+ routing,
132
+ reporter,
133
+ };
134
+ }
135
+ // Ask the platform for each enabled model's credential up front, so provider
136
+ // execution and fallback stay synchronous.
137
+ async function withProviderCredentials(credentials, apiKey) {
138
+ const platform = gatewayPlatform();
139
+ if (platform.resolveProviderCredential === undefined)
140
+ return credentials;
141
+ const resolved = await Promise.all(credentials.enabled_models.map(async (model) => [
142
+ model,
143
+ await platform.resolveProviderCredential({
144
+ provider: executionProviderForModel(credentials, model),
145
+ model,
146
+ routerId: credentials.router_id,
147
+ organizationId: credentials.organization_id,
148
+ apiKey,
149
+ }),
150
+ ]));
151
+ const provider_credentials = {};
152
+ for (const [model, credential] of resolved) {
153
+ if (credential?.apiKey.trim())
154
+ provider_credentials[model] = credential;
155
+ }
156
+ return { ...credentials, provider_credentials };
157
+ }
158
+ // Core's cache-aware pruning audit, extended with the context layer's image
159
+ // capability exclusions. The exclusions survive on their own when custom
160
+ // routing produced no core audit (missing config), so the error path keeps
161
+ // its candidate_pruning trail.
162
+ function reportedPruning(core, imagePruned) {
163
+ if (imagePruned === undefined)
164
+ return core;
165
+ const capability = { capability_pruned_models: imagePruned };
166
+ return core === null ? capability : { ...core, ...capability };
167
+ }
@@ -0,0 +1,31 @@
1
+ import type { ProviderStreamOutcome } from "./provider_stream_outcome.js";
2
+ type LifecycleArgs = {
3
+ partialResponse: () => Record<string, unknown>;
4
+ onFinal?: (outcome: ProviderStreamOutcome) => void;
5
+ onAbort?: () => void;
6
+ cancelSignal?: AbortSignal;
7
+ terminalOutcome?: () => ProviderStreamOutcome | null;
8
+ };
9
+ /**
10
+ * Owns the cancel/terminal race shared by every hosted streaming protocol.
11
+ * A provider terminal already observed always wins. Otherwise a client cancel
12
+ * aborts the provider and finalizes the delivered partial as aborted.
13
+ */
14
+ export declare class ProviderStreamLifecycle {
15
+ private readonly args;
16
+ private clientCanceled;
17
+ private bodyCanceled;
18
+ private finalized;
19
+ private detachCancelSignal;
20
+ constructor(args: LifecycleArgs);
21
+ get canWrite(): boolean;
22
+ get shouldStopConsuming(): boolean;
23
+ cancel(terminalOutcome: ProviderStreamOutcome | null, bodyCanceled?: boolean): void;
24
+ finish(args: {
25
+ outcome: ProviderStreamOutcome;
26
+ beforeClose?: (outcome: ProviderStreamOutcome) => Promise<void> | void;
27
+ close: () => void;
28
+ }): Promise<void>;
29
+ private finalize;
30
+ }
31
+ export {};
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Owns the cancel/terminal race shared by every hosted streaming protocol.
3
+ * A provider terminal already observed always wins. Otherwise a client cancel
4
+ * aborts the provider and finalizes the delivered partial as aborted.
5
+ */
6
+ export class ProviderStreamLifecycle {
7
+ args;
8
+ clientCanceled = false;
9
+ bodyCanceled = false;
10
+ finalized = false;
11
+ detachCancelSignal = () => { };
12
+ constructor(args) {
13
+ this.args = args;
14
+ const cancelSignal = args.cancelSignal;
15
+ if (cancelSignal !== undefined) {
16
+ const cancelFromSignal = () => {
17
+ this.cancel(args.terminalOutcome?.() ?? null, false);
18
+ };
19
+ if (cancelSignal.aborted) {
20
+ cancelFromSignal();
21
+ }
22
+ else {
23
+ cancelSignal.addEventListener("abort", cancelFromSignal, { once: true });
24
+ this.detachCancelSignal = () => {
25
+ cancelSignal.removeEventListener("abort", cancelFromSignal);
26
+ };
27
+ }
28
+ }
29
+ }
30
+ get canWrite() {
31
+ return !this.clientCanceled;
32
+ }
33
+ get shouldStopConsuming() {
34
+ return this.clientCanceled;
35
+ }
36
+ cancel(terminalOutcome, bodyCanceled = true) {
37
+ if (this.clientCanceled) {
38
+ this.bodyCanceled ||= bodyCanceled;
39
+ return;
40
+ }
41
+ this.clientCanceled = true;
42
+ this.bodyCanceled = bodyCanceled;
43
+ if (terminalOutcome !== null) {
44
+ this.finalize(terminalOutcome);
45
+ return;
46
+ }
47
+ this.args.onAbort?.();
48
+ this.finalize({
49
+ status: "aborted",
50
+ message: null,
51
+ responseBody: this.args.partialResponse(),
52
+ });
53
+ }
54
+ async finish(args) {
55
+ if (this.clientCanceled) {
56
+ if (!this.bodyCanceled) {
57
+ try {
58
+ args.close();
59
+ }
60
+ catch {
61
+ // Bun may also cancel the body while dispatching request abort.
62
+ }
63
+ }
64
+ return;
65
+ }
66
+ if (!this.finalized) {
67
+ try {
68
+ await args.beforeClose?.(args.outcome);
69
+ }
70
+ catch (error) {
71
+ console.error("stream finalization barrier failed", error);
72
+ }
73
+ }
74
+ // The client can cancel while beforeClose is awaiting persistence. In that
75
+ // race cancel() has already finalized the provider terminal outcome.
76
+ if (this.finalized)
77
+ return;
78
+ args.close();
79
+ this.finalize(args.outcome);
80
+ }
81
+ finalize(outcome) {
82
+ if (this.finalized)
83
+ return;
84
+ this.finalized = true;
85
+ this.detachCancelSignal();
86
+ this.args.onFinal?.(outcome);
87
+ }
88
+ }
@@ -0,0 +1,23 @@
1
+ import type { InteractionOutput } from "../interaction/types.js";
2
+ export type ProviderStreamOutcome = {
3
+ status: "completed";
4
+ message: Record<string, unknown>;
5
+ output: InteractionOutput;
6
+ } | {
7
+ status: "provider_error";
8
+ message: Record<string, unknown>;
9
+ } | {
10
+ status: "aborted";
11
+ message: null;
12
+ responseBody: Record<string, unknown>;
13
+ };
14
+ export declare function isProviderFailureMessage(message: Record<string, unknown>): boolean;
15
+ export declare function providerFailureFromEvent(event: Record<string, unknown>): Record<string, unknown>;
16
+ export declare function providerFailureFromCaught(error: unknown): Record<string, unknown>;
17
+ /**
18
+ * A terminal provider message remains the source of truth for exact usage even
19
+ * when translating that message into a client protocol response fails.
20
+ */
21
+ export declare function providerFailureFromTerminal(error: unknown, terminalMessage: Record<string, unknown>): Record<string, unknown>;
22
+ export declare function providerFailure(message: string): Record<string, unknown>;
23
+ export declare function providerFailureMessage(message: Record<string, unknown>): string;