@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,6 @@
1
+ export { createRequestHandler, type GatewayHandlerOptions } from "./http/handler.js";
2
+ export type { GatewayPlatform, OperationalErrorContext, PendingLeaseWrite, PrefixStateWrite, ProviderCredentialRequest, RequestErrorContext, RequestRecord, RequestSummary, RequestTags, ResolveRouterRequest, SubscriptionHold, } from "./platform/platform.js";
3
+ export { createAutoRoutingSelectorBackend } from "./strategies/auto_routing_selector.js";
4
+ export { createPrioritySelectorBackend } from "./strategies/priority_selector.js";
5
+ export { createLlmSelectorBackend, type SelectorBackend } from "./strategies/routing.js";
6
+ export type { ProviderCredential, ResolvedRouter } from "./types.js";
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ // Public entry points. Every module is also importable by path
2
+ // (`@mupt-ai/dari-gateway/<dir>/<module>`) for deployments that compose the
3
+ // gateway with their own platform. This entry needs no Bun APIs; the Bun
4
+ // server and the SQLite-backed self-hosted gateway live in `./bun`.
5
+ export { createRequestHandler } from "./http/handler.js";
6
+ export { createAutoRoutingSelectorBackend } from "./strategies/auto_routing_selector.js";
7
+ export { createPrioritySelectorBackend } from "./strategies/priority_selector.js";
8
+ export { createLlmSelectorBackend } from "./strategies/routing.js";
@@ -0,0 +1,3 @@
1
+ import type { SelectorBackend } from "../strategies/routing.js";
2
+ export declare function handleAnthropicMessages(request: Request, routerId: string, selectorBackend: SelectorBackend): Promise<Response>;
3
+ export declare function anthropicErrorResponse(error: unknown): Response;
@@ -0,0 +1,122 @@
1
+ import { isRecord } from "@mupt-ai/dari-router/policy-engine";
2
+ import { anthropicMessagesResponse } from "../protocol/output/anthropic_messages.js";
3
+ import { anthropicMessagesSseStream } from "../protocol/output/anthropic_messages_stream.js";
4
+ import { anthropicToken } from "../http/auth.js";
5
+ import { errorResponseHeaders, normalizeError } from "../http/errors.js";
6
+ import { captureRequestError } from "../observability/errors.js";
7
+ import { anthropicMessagesToInteraction } from "../protocol/input/anthropic_messages.js";
8
+ import { handleRoutedCompletion } from "../runtime/routed_completion.js";
9
+ import { claudeCodeRequestContext } from "./claude_code/request_context.js";
10
+ import { claudeCodeConversationIdentity, } from "../runtime/harness_identity/index.js";
11
+ import { parseJsonRequest } from "./json.js";
12
+ const LEGACY_CLAUDE_CODE_BETA = "claude-code-20250219";
13
+ const SAFEGUARDS_BETA_PREFIX = "dangerous-tool-use-";
14
+ export async function handleAnthropicMessages(request, routerId, selectorBackend) {
15
+ try {
16
+ const apiKey = anthropicToken(request.headers);
17
+ const rawPayload = await parseJsonRequest(request);
18
+ const interaction = anthropicMessagesToInteraction(rawPayload);
19
+ const isClaudeCode = isClaudeCodeRequest(request.headers);
20
+ const anthropicSafeguards = safeguardsFrom(rawPayload, request.headers);
21
+ const forwarded = anthropicSafeguards === undefined
22
+ ? interaction
23
+ : { ...interaction, anthropicSafeguards };
24
+ const payload = isClaudeCode
25
+ ? {
26
+ ...forwarded,
27
+ agentContext: claudeCodeRequestContext(request.headers),
28
+ // Native tool results may be followed by harness-injected text.
29
+ // Preserve their structural continuation semantics, not prompt inference.
30
+ ...(latestMessageHasToolResult(rawPayload.messages)
31
+ ? { requestPurpose: "tool_continuation" } : {}),
32
+ claudeCodeUserAgent: request.headers.get("user-agent").trim(),
33
+ }
34
+ : forwarded;
35
+ return await handleRoutedCompletion({
36
+ request,
37
+ routerId,
38
+ apiKey,
39
+ payload,
40
+ responseBody: anthropicMessagesResponse,
41
+ streamBody: anthropicMessagesSseStream,
42
+ errorResponse: anthropicErrorResponse,
43
+ selectorBackend,
44
+ clientHarness: isClaudeCode ? "claude_code" : undefined,
45
+ harnessConversationIdentity: isClaudeCode
46
+ ? claudeCodeConversationIdentity(request.headers, payload.promptCacheKey)
47
+ : undefined,
48
+ });
49
+ }
50
+ catch (error) {
51
+ const response = anthropicErrorResponse(error);
52
+ captureRequestError(error, {
53
+ request,
54
+ routerId,
55
+ sourceProtocol: "anthropic_messages",
56
+ status: response.status,
57
+ });
58
+ return response;
59
+ }
60
+ }
61
+ function latestMessageHasToolResult(messages) {
62
+ if (!Array.isArray(messages))
63
+ return false;
64
+ const message = messages.at(-1);
65
+ return isRecord(message) && message.role === "user" && Array.isArray(message.content)
66
+ && message.content.some((block) => isRecord(block) && block.type === "tool_result");
67
+ }
68
+ // A safeguards body field only works with its paired beta, so forward the two
69
+ // together or not at all.
70
+ function safeguardsFrom(payload, headers) {
71
+ if (!Array.isArray(payload.safeguards) || payload.safeguards.length === 0) {
72
+ return undefined;
73
+ }
74
+ const betas = [...anthropicBetas(headers)].filter((beta) => beta.startsWith(SAFEGUARDS_BETA_PREFIX));
75
+ return betas.length === 0 ? undefined : { safeguards: payload.safeguards, betas };
76
+ }
77
+ function anthropicBetas(headers) {
78
+ return new Set((headers.get("anthropic-beta") ?? "")
79
+ .split(",")
80
+ .map((value) => value.trim().toLowerCase())
81
+ .filter(Boolean));
82
+ }
83
+ function isClaudeCodeRequest(headers) {
84
+ const userAgent = headers.get("user-agent")?.trim().toLowerCase() ?? "";
85
+ const app = headers.get("x-app")?.trim().toLowerCase();
86
+ const betas = anthropicBetas(headers);
87
+ return (userAgent.startsWith("claude-cli/") &&
88
+ (app === "cli" || app === "cli-bg") &&
89
+ (Boolean(headers.get("x-claude-code-session-id")?.trim()) ||
90
+ betas.has(LEGACY_CLAUDE_CODE_BETA)));
91
+ }
92
+ // Dari-specific codes clients act on; every other code stays internal.
93
+ const CLIENT_VISIBLE_ERROR_CODES = new Set([
94
+ "personal_subscription_unavailable",
95
+ "subscription_switched",
96
+ "subscription_usage_limit",
97
+ ]);
98
+ export function anthropicErrorResponse(error) {
99
+ const { status, message, code } = normalizeError(error);
100
+ return Response.json({
101
+ type: "error",
102
+ error: {
103
+ type: anthropicErrorType(status),
104
+ message,
105
+ ...(CLIENT_VISIBLE_ERROR_CODES.has(code) ? { code } : {}),
106
+ },
107
+ }, { status, headers: errorResponseHeaders(error) });
108
+ }
109
+ function anthropicErrorType(status) {
110
+ switch (status) {
111
+ case 401:
112
+ return "authentication_error";
113
+ case 403:
114
+ return "permission_error";
115
+ case 404:
116
+ return "not_found_error";
117
+ case 429:
118
+ return "rate_limit_error";
119
+ default:
120
+ return status >= 500 ? "api_error" : "invalid_request_error";
121
+ }
122
+ }
@@ -0,0 +1 @@
1
+ export declare function anthropicModelsResponse(): Record<string, unknown>;
@@ -0,0 +1,23 @@
1
+ /* Anthropic-compatible model discovery. Claude Desktop, Cowork, and other
2
+ Anthropic-SDK gateway clients list models before first use and parse the
3
+ Anthropic list shape ({data: [{type: "model", ...}]}), not the Codex
4
+ catalog shape. Discovery advertises the tier synonyms from router_model.ts —
5
+ the only ids such clients accept as usable (verified in-app: `dari/routing`
6
+ is rejected, bare tier names classify). Fixed created_at keeps the response
7
+ byte-stable. */
8
+ import { ANTHROPIC_ROUTER_MODEL_TIERS } from "../protocol/input/router_model.js";
9
+ const ROUTER_MODEL_CREATED_AT = "2026-01-01T00:00:00Z";
10
+ const tierLabel = (tier) => `Dari Routing (${tier[0].toUpperCase()}${tier.slice(1)} tier)`;
11
+ export function anthropicModelsResponse() {
12
+ return {
13
+ data: ANTHROPIC_ROUTER_MODEL_TIERS.map((tier) => ({
14
+ type: "model",
15
+ id: tier,
16
+ display_name: tierLabel(tier),
17
+ created_at: ROUTER_MODEL_CREATED_AT,
18
+ })),
19
+ first_id: ANTHROPIC_ROUTER_MODEL_TIERS[0],
20
+ last_id: ANTHROPIC_ROUTER_MODEL_TIERS[ANTHROPIC_ROUTER_MODEL_TIERS.length - 1],
21
+ has_more: false,
22
+ };
23
+ }
@@ -0,0 +1,2 @@
1
+ import type { SelectorBackend } from "../strategies/routing.js";
2
+ export declare function handleChatCompletions(request: Request, routerId: string, selectorBackend: SelectorBackend): Promise<Response>;
@@ -0,0 +1,37 @@
1
+ import { bearerToken } from "../http/auth.js";
2
+ import { errorResponse } from "../http/errors.js";
3
+ import { captureRequestError } from "../observability/errors.js";
4
+ import { chatCompletionResponse, chatCompletionsSseStream } from "../protocol/output/chat_completions.js";
5
+ import { chatCompletionsToInteraction } from "../protocol/input/chat_completions.js";
6
+ import { handleRoutedCompletion } from "../runtime/routed_completion.js";
7
+ import { chatCompletionsConversationIdentity, openCodeRequestContext, } from "../runtime/harness_identity/index.js";
8
+ import { parseJsonRequest } from "./json.js";
9
+ export async function handleChatCompletions(request, routerId, selectorBackend) {
10
+ try {
11
+ const apiKey = bearerToken(request.headers);
12
+ const payload = await parseJsonRequest(request);
13
+ const interaction = chatCompletionsToInteraction({ ...payload, source_protocol: "openai_chat" });
14
+ const agentContext = openCodeRequestContext(request.headers);
15
+ return await handleRoutedCompletion({
16
+ request,
17
+ routerId,
18
+ apiKey,
19
+ payload: agentContext === undefined ? interaction : { ...interaction, agentContext },
20
+ responseBody: chatCompletionResponse,
21
+ streamBody: chatCompletionsSseStream,
22
+ errorResponse,
23
+ selectorBackend,
24
+ harnessConversationIdentity: chatCompletionsConversationIdentity(request.headers, payload.prompt_cache_key),
25
+ });
26
+ }
27
+ catch (error) {
28
+ const response = errorResponse(error);
29
+ captureRequestError(error, {
30
+ request,
31
+ routerId,
32
+ sourceProtocol: "openai_chat",
33
+ status: response.status,
34
+ });
35
+ return response;
36
+ }
37
+ }
@@ -0,0 +1,2 @@
1
+ import type { AgentRequestContext } from "../../interaction/types.js";
2
+ export declare function claudeCodeRequestContext(headers: Headers): AgentRequestContext;
@@ -0,0 +1,31 @@
1
+ import { HttpError } from "../../http/errors.js";
2
+ const REQUEST_CLASSES = new Set([
3
+ "main", "subagent", "workflow", "auxiliary", "compaction", "side_reply",
4
+ ]);
5
+ // These are client-supplied routing hints, not authentication claims. Never
6
+ // infer them from prompt text: a user can legitimately paste any such prompt.
7
+ export function claudeCodeRequestContext(headers) {
8
+ const value = headers.get("x-claude-code-request-class")?.trim();
9
+ const requestClass = REQUEST_CLASSES.has(value)
10
+ ? value
11
+ : "unknown";
12
+ const agentId = identifier(headers, "x-claude-code-agent-id");
13
+ if ((requestClass === "subagent" || requestClass === "workflow") && !agentId) {
14
+ throw new HttpError(400, "Agent requests require x-claude-code-agent-id.", "invalid_request_error", "x-claude-code-agent-id");
15
+ }
16
+ return {
17
+ requestClass,
18
+ ...(agentId === undefined ? {} : { agentId }),
19
+ parentAgentId: identifier(headers, "x-claude-code-parent-agent-id"),
20
+ agentType: identifier(headers, "x-claude-code-agent-type"),
21
+ };
22
+ }
23
+ function identifier(headers, name) {
24
+ const value = headers.get(name)?.trim();
25
+ if (!value)
26
+ return undefined;
27
+ if (value.length > 200) {
28
+ throw new HttpError(400, `${name} must not exceed 200 characters.`, "invalid_request_error", name);
29
+ }
30
+ return value;
31
+ }
@@ -0,0 +1,3 @@
1
+ import type { SelectorBackend } from "../strategies/routing.js";
2
+ export declare function handleResponses(request: Request, routerId: string, selectorBackend: SelectorBackend): Promise<Response>;
3
+ export declare function handleResponsesWebSocketFallback(): Response;
@@ -0,0 +1,65 @@
1
+ import { bearerToken } from "../http/auth.js";
2
+ import { errorResponse } from "../http/errors.js";
3
+ import { captureRequestError } from "../observability/errors.js";
4
+ import { openAIResponsesResponse } from "../protocol/output/openai_responses.js";
5
+ import { openAIResponsesSseStream } from "../protocol/output/openai_responses_stream.js";
6
+ import { openAIResponsesToInteraction } from "../protocol/input/openai_responses.js";
7
+ import { parseJsonRequest } from "./json.js";
8
+ import { handleRoutedCompletion } from "../runtime/routed_completion.js";
9
+ import { codexConversationIdentity, codexRequestPurpose, codexRequestContext, } from "../runtime/harness_identity/index.js";
10
+ export async function handleResponses(request, routerId, selectorBackend) {
11
+ try {
12
+ const apiKey = bearerToken(request.headers);
13
+ const rawPayload = await parseJsonRequest(request);
14
+ const interaction = openAIResponsesToInteraction(rawPayload);
15
+ const requestPurpose = codexRequestPurpose(request.headers, rawPayload);
16
+ const agentContext = codexRequestContext(request.headers, rawPayload);
17
+ const payload = {
18
+ ...interaction,
19
+ ...(requestPurpose === undefined ? {} : { requestPurpose }),
20
+ ...(agentContext === undefined ? {} : { agentContext }),
21
+ };
22
+ const harnessConversationIdentity = codexConversationIdentity(request.headers, rawPayload);
23
+ // Codex applies its global model_reasoning_effort setting to custom model
24
+ // providers. That preference describes a direct model, not a heterogeneous
25
+ // router, so let Dari select the reasoning effort for verified Codex turns.
26
+ // Parsing above still validates malformed Responses reasoning controls.
27
+ if (harnessConversationIdentity !== undefined)
28
+ payload.reasoning = undefined;
29
+ return await handleRoutedCompletion({
30
+ request,
31
+ routerId,
32
+ apiKey,
33
+ payload,
34
+ responseBody: openAIResponsesResponse,
35
+ streamBody: openAIResponsesSseStream,
36
+ errorResponse,
37
+ selectorBackend,
38
+ harnessConversationIdentity,
39
+ });
40
+ }
41
+ catch (error) {
42
+ const response = errorResponse(error);
43
+ captureRequestError(error, {
44
+ request,
45
+ routerId,
46
+ sourceProtocol: "openai_responses",
47
+ status: response.status,
48
+ });
49
+ return response;
50
+ }
51
+ }
52
+ export function handleResponsesWebSocketFallback() {
53
+ return Response.json({
54
+ error: {
55
+ message: "Responses WebSocket is not supported by this router endpoint; use HTTP Responses.",
56
+ type: "unsupported_transport",
57
+ code: "unsupported_transport",
58
+ },
59
+ }, {
60
+ status: 426,
61
+ headers: {
62
+ "Cache-Control": "no-store",
63
+ },
64
+ });
65
+ }
@@ -0,0 +1,2 @@
1
+ import type { ResolvedRouter } from "../types.js";
2
+ export declare function codexModelsResponse(router: Pick<ResolvedRouter, "enabled_models" | "model_configs" | "allow_long_context">, imageInputFor: (model: string) => boolean): Record<string, unknown>;
@@ -0,0 +1,89 @@
1
+ import { CANONICAL_ROUTER_MODEL, explicitModelSlug } from "../protocol/input/router_model.js";
2
+ import { effectiveContextWindow } from "../models/context_limits.js";
3
+ import { modelSupportsHostedWebSearch } from "../providers/model_capabilities.js";
4
+ const DEFAULT_CODEX_CONTEXT_WINDOW = 128_000;
5
+ function codexRouterContextWindow(router) {
6
+ const windows = router.enabled_models.map((model) => {
7
+ const configured = effectiveContextWindow(router.model_configs?.[model], router.allow_long_context === true);
8
+ return typeof configured === "number" && Number.isFinite(configured) && configured > 0
9
+ ? Math.floor(configured)
10
+ : DEFAULT_CODEX_CONTEXT_WINDOW;
11
+ });
12
+ return windows.length > 0 ? Math.max(...windows) : DEFAULT_CODEX_CONTEXT_WINDOW;
13
+ }
14
+ function codexRouterSupportsHostedWebSearch(router) {
15
+ return router.enabled_models.some((model) => {
16
+ const config = router.model_configs?.[model];
17
+ return config ? modelSupportsHostedWebSearch({ model: config }) : false;
18
+ });
19
+ }
20
+ function codexCatalogEntry(args) {
21
+ return {
22
+ slug: args.slug,
23
+ display_name: args.displayName,
24
+ description: args.description,
25
+ default_reasoning_level: null,
26
+ supported_reasoning_levels: [],
27
+ shell_type: "shell_command",
28
+ visibility: "list",
29
+ supported_in_api: true,
30
+ priority: args.priority,
31
+ additional_speed_tiers: [],
32
+ service_tiers: [],
33
+ default_service_tier: null,
34
+ availability_nux: null,
35
+ upgrade: null,
36
+ base_instructions: "You are Codex, a coding agent. You and the user share one workspace, and your job is to collaborate with them until their goal is genuinely handled.",
37
+ model_messages: null,
38
+ include_skills_usage_instructions: false,
39
+ // Codex 0.144 requires the legacy field; current main reads the renamed field below.
40
+ supports_reasoning_summaries: false,
41
+ supports_reasoning_summary_parameter: false,
42
+ default_reasoning_summary: "none",
43
+ support_verbosity: false,
44
+ default_verbosity: null,
45
+ apply_patch_tool_type: "freeform",
46
+ web_search_tool_type: args.hostedWebSearch ? "text" : null,
47
+ truncation_policy: { mode: "tokens", limit: 10_000 },
48
+ supports_parallel_tool_calls: true,
49
+ supports_image_detail_original: false,
50
+ context_window: args.contextWindow,
51
+ max_context_window: args.contextWindow,
52
+ auto_compact_token_limit: null,
53
+ comp_hash: null,
54
+ effective_context_window_percent: 95,
55
+ experimental_supported_tools: [],
56
+ input_modalities: args.imageInput ? ["text", "image"] : ["text"],
57
+ supports_search_tool: false,
58
+ use_responses_lite: false,
59
+ auto_review_model_override: args.slug,
60
+ tool_mode: null,
61
+ multi_agent_version: null,
62
+ };
63
+ }
64
+ /* `dari/routing` stays first (the Codex launcher patches it); each enabled
65
+ model follows as `dari/model/<id>` so Codex's /model menu can switch to it. */
66
+ export function codexModelsResponse(router, imageInputFor) {
67
+ return {
68
+ models: [
69
+ codexCatalogEntry({
70
+ slug: CANONICAL_ROUTER_MODEL,
71
+ displayName: "Dari Routing",
72
+ description: "Routes Codex HTTP Responses requests through the configured Dari model router.",
73
+ priority: 0,
74
+ contextWindow: codexRouterContextWindow(router),
75
+ hostedWebSearch: codexRouterSupportsHostedWebSearch(router),
76
+ imageInput: router.enabled_models.some(imageInputFor),
77
+ }),
78
+ ...router.enabled_models.map((model, index) => codexCatalogEntry({
79
+ slug: explicitModelSlug(model),
80
+ displayName: model,
81
+ description: `Serves ${model} directly, without routing.`,
82
+ priority: index + 1,
83
+ contextWindow: codexRouterContextWindow({ ...router, enabled_models: [model] }),
84
+ hostedWebSearch: codexRouterSupportsHostedWebSearch({ ...router, enabled_models: [model] }),
85
+ imageInput: imageInputFor(model),
86
+ })),
87
+ ],
88
+ };
89
+ }
@@ -0,0 +1 @@
1
+ export declare function parseJsonRequest<T extends Record<string, unknown>>(request: Request): Promise<T>;
@@ -0,0 +1,95 @@
1
+ import { Readable } from "node:stream";
2
+ import { createBrotliDecompress, createGunzip, createInflate, createZstdDecompress, } from "node:zlib";
3
+ import { HttpError } from "../http/errors.js";
4
+ const MAX_ENCODED_JSON_REQUEST_BYTES = 64 * 1024 * 1024;
5
+ const MAX_DECODED_JSON_REQUEST_BYTES = 64 * 1024 * 1024;
6
+ const MAX_CONTENT_ENCODING_LAYERS = 3;
7
+ export async function parseJsonRequest(request) {
8
+ let payload;
9
+ try {
10
+ payload = JSON.parse(await requestText(request));
11
+ }
12
+ catch (error) {
13
+ if (error instanceof HttpError)
14
+ throw error;
15
+ throw new HttpError(400, "Request body must be valid JSON.", "invalid_request_error");
16
+ }
17
+ if (typeof payload !== "object" || payload === null || Array.isArray(payload)) {
18
+ throw new HttpError(400, "Request body must be a JSON object.", "invalid_request_error");
19
+ }
20
+ return payload;
21
+ }
22
+ async function requestText(request) {
23
+ const contentLength = request.headers.get("content-length");
24
+ if (contentLength !== null) {
25
+ const parsed = Number(contentLength);
26
+ if (Number.isFinite(parsed) && parsed > MAX_ENCODED_JSON_REQUEST_BYTES) {
27
+ throw requestTooLarge();
28
+ }
29
+ }
30
+ const encodings = contentEncodings(request.headers.get("content-encoding"));
31
+ if (encodings.length > MAX_CONTENT_ENCODING_LAYERS) {
32
+ throw new HttpError(415, "Too many Content-Encoding layers.", "unsupported_content_encoding", "content-encoding");
33
+ }
34
+ let stream = boundedChunks(request.body ?? emptyByteStream(), MAX_ENCODED_JSON_REQUEST_BYTES);
35
+ for (const encoding of encodings.reverse()) {
36
+ stream = boundedChunks(decodedChunks(stream, encoding), MAX_DECODED_JSON_REQUEST_BYTES);
37
+ }
38
+ return await readText(stream);
39
+ }
40
+ function contentEncodings(header) {
41
+ if (!header)
42
+ return [];
43
+ return header
44
+ .split(",")
45
+ .map((value) => value.trim().toLowerCase())
46
+ .filter((value) => value && value !== "identity");
47
+ }
48
+ async function* boundedChunks(stream, maxBytes) {
49
+ let bytesRead = 0;
50
+ for await (const chunk of stream) {
51
+ bytesRead += chunk.byteLength;
52
+ if (bytesRead > maxBytes)
53
+ throw requestTooLarge();
54
+ yield chunk;
55
+ }
56
+ }
57
+ async function* decodedChunks(stream, encoding) {
58
+ const decoded = Readable.from(stream).pipe(decompressor(encoding));
59
+ try {
60
+ for await (const chunk of decoded) {
61
+ if (!(chunk instanceof Uint8Array))
62
+ throw new Error("Decompressor emitted a non-byte chunk.");
63
+ yield chunk;
64
+ }
65
+ }
66
+ finally {
67
+ decoded.destroy();
68
+ }
69
+ }
70
+ function decompressor(encoding) {
71
+ if (encoding === "zstd")
72
+ return createZstdDecompress();
73
+ if (encoding === "gzip" || encoding === "x-gzip")
74
+ return createGunzip();
75
+ if (encoding === "deflate")
76
+ return createInflate();
77
+ if (encoding === "br")
78
+ return createBrotliDecompress();
79
+ throw new HttpError(415, `Unsupported Content-Encoding '${encoding}'.`, "unsupported_content_encoding", "content-encoding");
80
+ }
81
+ async function readText(stream) {
82
+ const decoder = new TextDecoder();
83
+ const parts = [];
84
+ for await (const chunk of stream) {
85
+ parts.push(decoder.decode(chunk, { stream: true }));
86
+ }
87
+ parts.push(decoder.decode());
88
+ return parts.join("");
89
+ }
90
+ async function* emptyByteStream() {
91
+ return;
92
+ }
93
+ function requestTooLarge() {
94
+ return new HttpError(413, "Request body is too large.", "request_entity_too_large");
95
+ }
@@ -0,0 +1 @@
1
+ export declare function handleModels(request: Request, routerId: string): Promise<Response>;
@@ -0,0 +1,53 @@
1
+ /* Shared GET /models discovery route. One URL serves two client protocols:
2
+ Codex reads the Codex catalog; Anthropic-SDK clients (Claude Desktop /
3
+ Cowork gateway probes, Claude Code) read the Anthropic list shape. The
4
+ handler detects the caller, authenticates in that protocol's auth shape,
5
+ and selects the matching catalog adapter. */
6
+ import { anthropicToken, bearerToken } from "../http/auth.js";
7
+ import { errorResponse } from "../http/errors.js";
8
+ import { captureRequestError } from "../observability/errors.js";
9
+ import { anthropicErrorResponse } from "./anthropic_messages.js";
10
+ import { modelSupportsImageInput } from "../providers/model_capabilities.js";
11
+ import { modelMetadataLookup } from "../providers/pi.js";
12
+ import { resolveRouter } from "../strategies/routing.js";
13
+ import { anthropicModelsResponse } from "./anthropic_models.js";
14
+ import { codexModelsResponse } from "./codex_models.js";
15
+ export async function handleModels(request, routerId) {
16
+ // Anthropic SDK clients always send anthropic-version, and API-key probes
17
+ // authenticate via x-api-key instead of a bearer Authorization header.
18
+ // Codex sends neither.
19
+ const anthropicClient = request.headers.has("anthropic-version") ||
20
+ (!request.headers.get("authorization") && request.headers.has("x-api-key"));
21
+ try {
22
+ const apiKey = anthropicClient ? anthropicToken(request.headers) : bearerToken(request.headers);
23
+ // Resolution authenticates the key and confirms the router exists even
24
+ // when the response body (Anthropic shape) does not depend on it.
25
+ const router = await resolveRouter({ routerId, apiKey });
26
+ if (anthropicClient) {
27
+ return Response.json(anthropicModelsResponse(), {
28
+ headers: {
29
+ "Cache-Control": "no-store",
30
+ },
31
+ });
32
+ }
33
+ const metadataLookup = modelMetadataLookup(router.model_configs);
34
+ const imageInputFor = (model) => modelSupportsImageInput(metadataLookup(model));
35
+ return Response.json(codexModelsResponse(router, imageInputFor), {
36
+ headers: {
37
+ "Cache-Control": "no-store",
38
+ },
39
+ });
40
+ }
41
+ catch (error) {
42
+ // Each protocol's clients parse their own error envelope: Anthropic's
43
+ // {type:"error",error:{type,message}} vs the OpenAI {error:{...}} shape.
44
+ const response = anthropicClient ? anthropicErrorResponse(error) : errorResponse(error);
45
+ captureRequestError(error, {
46
+ request,
47
+ routerId,
48
+ sourceProtocol: anthropicClient ? "anthropic_models" : "openai_models",
49
+ status: response.status,
50
+ });
51
+ return response;
52
+ }
53
+ }
@@ -0,0 +1,3 @@
1
+ import type { HardCapability } from "@mupt-ai/dari-router/policy-engine";
2
+ import type { InteractionRequest } from "./types.js";
3
+ export declare function requiredCapabilitiesFor(request: Pick<InteractionRequest, "items" | "responseFormat" | "toolChoice" | "tools">): HardCapability[];
@@ -0,0 +1,24 @@
1
+ export function requiredCapabilitiesFor(request) {
2
+ const capabilities = new Set();
3
+ if (request.items.some(itemHasImage))
4
+ capabilities.add("image_input");
5
+ if (request.items.some((item) => item.type === "reasoning_configuration")) {
6
+ capabilities.add("reasoning_configuration_update");
7
+ }
8
+ if (request.responseFormat !== undefined && request.responseFormat.type !== "text")
9
+ capabilities.add("structured_output");
10
+ if (request.tools.some((tool) => tool.kind === "hosted")
11
+ || request.items.some(requiresWebSearch)
12
+ || (typeof request.toolChoice === "object" && request.toolChoice.kind === "hosted")) {
13
+ capabilities.add("openai_hosted_web_search");
14
+ }
15
+ return [...capabilities];
16
+ }
17
+ function requiresWebSearch(item) {
18
+ return item.type === "hosted_tool_call" && item.tool === "web_search";
19
+ }
20
+ function itemHasImage(item) {
21
+ if (item.type === "message")
22
+ return item.content.some((part) => part.type === "image");
23
+ return item.type === "tool_result" && Array.isArray(item.output) && item.output.some((part) => part.type === "image");
24
+ }
@@ -0,0 +1,4 @@
1
+ export declare function parseDataImageUrl(url: string): {
2
+ mimeType: string;
3
+ data: string;
4
+ } | undefined;
@@ -0,0 +1,13 @@
1
+ export function parseDataImageUrl(url) {
2
+ const commaIndex = url.indexOf(",");
3
+ if (!url.startsWith("data:") || commaIndex === -1)
4
+ return undefined;
5
+ const header = url.slice(5, commaIndex);
6
+ const segments = header.split(";");
7
+ const mimeType = segments.shift();
8
+ const data = url.slice(commaIndex + 1);
9
+ if (!mimeType?.toLowerCase().startsWith("image/") || segments.at(-1)?.toLowerCase() !== "base64" || !data) {
10
+ return undefined;
11
+ }
12
+ return { mimeType, data };
13
+ }
@@ -0,0 +1,4 @@
1
+ import { type PortableReasoningState } from "@mupt-ai/dari-router/protocols";
2
+ export type { PortableReasoningState } from "@mupt-ai/dari-router/protocols";
3
+ export declare function encodePortableReasoningState(state: PortableReasoningState): string;
4
+ export declare function decodeUntrustedPortableReasoningState(value: string): PortableReasoningState | null;
@@ -0,0 +1,18 @@
1
+ import { decodeUntrustedPortableReasoningState as coreDecode, encodePortableReasoningState as coreEncode, } from "@mupt-ai/dari-router/protocols";
2
+ import { rethrowFrameworkErrorAsHttp } from "../http/errors.js";
3
+ export function encodePortableReasoningState(state) {
4
+ try {
5
+ return coreEncode(state);
6
+ }
7
+ catch (error) {
8
+ rethrowFrameworkErrorAsHttp(error, 500);
9
+ }
10
+ }
11
+ export function decodeUntrustedPortableReasoningState(value) {
12
+ try {
13
+ return coreDecode(value);
14
+ }
15
+ catch (error) {
16
+ rethrowFrameworkErrorAsHttp(error, 400);
17
+ }
18
+ }
@@ -0,0 +1,6 @@
1
+ import { type ProviderContinuationState, type ProviderIdentity } from "@mupt-ai/dari-router/protocols";
2
+ export type { ProviderContinuationState, ProviderIdentity } from "@mupt-ai/dari-router/protocols";
3
+ export { compatibleProviderContinuation, isAnthropicEffort, sameProviderIdentity } from "@mupt-ai/dari-router/protocols";
4
+ export declare function encodeProviderContinuationState(value: ProviderContinuationState): string;
5
+ export declare function decodeUntrustedProviderContinuationState(value: string): ProviderContinuationState | null;
6
+ export declare function providerIdentityFromModel(model: Record<string, unknown>): ProviderIdentity;