@mupt-ai/dari-gateway 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (385) hide show
  1. package/README.md +8 -4
  2. package/dist/bun.d.ts +2 -0
  3. package/dist/bun.js +4 -0
  4. package/dist/context/eval_catalog.d.ts +3 -0
  5. package/dist/context/eval_catalog.js +7 -0
  6. package/dist/context/interaction_fingerprint.d.ts +27 -0
  7. package/dist/context/interaction_fingerprint.js +519 -0
  8. package/dist/context/interaction_fingerprint_format.d.ts +42 -0
  9. package/dist/context/interaction_fingerprint_format.js +113 -0
  10. package/dist/context/interaction_lease_depth.d.ts +2 -0
  11. package/dist/context/interaction_lease_depth.js +110 -0
  12. package/dist/context/lease_history.d.ts +7 -0
  13. package/dist/context/lease_history.js +158 -0
  14. package/dist/context/pricing.d.ts +4 -0
  15. package/dist/context/pricing.js +27 -0
  16. package/dist/context/provider_prompt_accounting.d.ts +14 -0
  17. package/dist/context/provider_prompt_accounting.js +187 -0
  18. package/dist/context/routing_context.d.ts +40 -0
  19. package/dist/context/routing_context.js +211 -0
  20. package/dist/http/auth.d.ts +2 -0
  21. package/dist/http/auth.js +35 -0
  22. package/dist/http/errors.d.ts +19 -0
  23. package/dist/http/errors.js +89 -0
  24. package/dist/http/handler.d.ts +12 -0
  25. package/dist/http/handler.js +88 -0
  26. package/dist/http/http2_server.d.ts +6 -0
  27. package/dist/http/http2_server.js +103 -0
  28. package/dist/http/serve.d.ts +20 -0
  29. package/dist/http/serve.js +78 -0
  30. package/dist/index.d.ts +7 -0
  31. package/dist/index.js +9 -0
  32. package/dist/ingress/anthropic_messages.d.ts +3 -0
  33. package/dist/ingress/anthropic_messages.js +122 -0
  34. package/dist/ingress/anthropic_models.d.ts +1 -0
  35. package/dist/ingress/anthropic_models.js +23 -0
  36. package/dist/ingress/chat_completions.d.ts +2 -0
  37. package/dist/ingress/chat_completions.js +44 -0
  38. package/dist/ingress/claude_code/request_context.d.ts +2 -0
  39. package/dist/ingress/claude_code/request_context.js +31 -0
  40. package/dist/ingress/codex.d.ts +3 -0
  41. package/dist/ingress/codex.js +69 -0
  42. package/dist/ingress/codex_models.d.ts +2 -0
  43. package/dist/ingress/codex_models.js +89 -0
  44. package/dist/ingress/json.d.ts +1 -0
  45. package/dist/ingress/json.js +95 -0
  46. package/dist/ingress/models.d.ts +1 -0
  47. package/dist/ingress/models.js +65 -0
  48. package/dist/ingress/muse_code.d.ts +2 -0
  49. package/dist/ingress/muse_code.js +8 -0
  50. package/dist/ingress/muse_models.d.ts +9 -0
  51. package/dist/ingress/muse_models.js +32 -0
  52. package/dist/interaction/capabilities.d.ts +3 -0
  53. package/dist/interaction/capabilities.js +24 -0
  54. package/dist/interaction/image.d.ts +4 -0
  55. package/dist/interaction/image.js +13 -0
  56. package/dist/interaction/portable_reasoning_state.d.ts +4 -0
  57. package/dist/interaction/portable_reasoning_state.js +18 -0
  58. package/dist/interaction/provider_continuation_state.d.ts +6 -0
  59. package/dist/interaction/provider_continuation_state.js +27 -0
  60. package/dist/interaction/tool_identity.d.ts +10 -0
  61. package/dist/interaction/tool_identity.js +41 -0
  62. package/dist/interaction/types.d.ts +204 -0
  63. package/dist/interaction/types.js +5 -0
  64. package/dist/models/catalog.d.ts +35 -0
  65. package/dist/models/catalog.js +232 -0
  66. package/dist/models/context_limits.d.ts +2 -0
  67. package/dist/models/context_limits.js +7 -0
  68. package/dist/models/execution_provider.d.ts +9 -0
  69. package/dist/models/execution_provider.js +17 -0
  70. package/dist/models/gateways.d.ts +11 -0
  71. package/dist/models/gateways.js +45 -0
  72. package/dist/models/ids.d.ts +1 -0
  73. package/dist/models/ids.js +15 -0
  74. package/dist/models/provider_defaults.d.ts +4 -0
  75. package/dist/models/provider_defaults.js +44 -0
  76. package/dist/models/runtime_overrides.d.ts +7 -0
  77. package/dist/models/runtime_overrides.js +226 -0
  78. package/dist/models/subscriptions.d.ts +8 -0
  79. package/dist/models/subscriptions.js +37 -0
  80. package/dist/observability/errors.d.ts +8 -0
  81. package/dist/observability/errors.js +11 -0
  82. package/dist/platform/platform.d.ts +156 -0
  83. package/dist/platform/platform.js +11 -0
  84. package/dist/platform/routing_contract.d.ts +2 -0
  85. package/dist/platform/routing_contract.js +5 -0
  86. package/dist/protocol/input/anthropic_messages.d.ts +2 -0
  87. package/dist/protocol/input/anthropic_messages.js +494 -0
  88. package/dist/protocol/input/chat_completions.d.ts +4 -0
  89. package/dist/protocol/input/chat_completions.js +214 -0
  90. package/dist/protocol/input/chat_completions_validation.d.ts +2 -0
  91. package/dist/protocol/input/chat_completions_validation.js +258 -0
  92. package/dist/protocol/input/openai_responses.d.ts +2 -0
  93. package/dist/protocol/input/openai_responses.js +666 -0
  94. package/dist/protocol/input/router_model.d.ts +7 -0
  95. package/dist/protocol/input/router_model.js +43 -0
  96. package/dist/protocol/output/anthropic_messages.d.ts +10 -0
  97. package/dist/protocol/output/anthropic_messages.js +15 -0
  98. package/dist/protocol/output/anthropic_messages_output.d.ts +10 -0
  99. package/dist/protocol/output/anthropic_messages_output.js +124 -0
  100. package/dist/protocol/output/anthropic_messages_stream.d.ts +16 -0
  101. package/dist/protocol/output/anthropic_messages_stream.js +267 -0
  102. package/dist/protocol/output/chat_completions.d.ts +29 -0
  103. package/dist/protocol/output/chat_completions.js +406 -0
  104. package/dist/protocol/output/chat_reasoning_detail.d.ts +2 -0
  105. package/dist/protocol/output/chat_reasoning_detail.js +13 -0
  106. package/dist/protocol/output/delivered_stream_snapshot.d.ts +10 -0
  107. package/dist/protocol/output/delivered_stream_snapshot.js +31 -0
  108. package/dist/protocol/output/openai_responses.d.ts +10 -0
  109. package/dist/protocol/output/openai_responses.js +14 -0
  110. package/dist/protocol/output/openai_responses_output.d.ts +14 -0
  111. package/dist/protocol/output/openai_responses_output.js +125 -0
  112. package/dist/protocol/output/openai_responses_stream.d.ts +18 -0
  113. package/dist/protocol/output/openai_responses_stream.js +546 -0
  114. package/dist/protocol/output/sse_stream.d.ts +31 -0
  115. package/dist/protocol/output/sse_stream.js +67 -0
  116. package/dist/providers/anthropic_safeguards.d.ts +11 -0
  117. package/dist/providers/anthropic_safeguards.js +81 -0
  118. package/dist/providers/aws_assume_role.d.ts +17 -0
  119. package/dist/providers/aws_assume_role.js +107 -0
  120. package/dist/providers/cancel_estimate.d.ts +43 -0
  121. package/dist/providers/cancel_estimate.js +89 -0
  122. package/dist/providers/execution.d.ts +72 -0
  123. package/dist/providers/execution.js +491 -0
  124. package/dist/providers/model_capabilities.d.ts +11 -0
  125. package/dist/providers/model_capabilities.js +29 -0
  126. package/dist/providers/pi.d.ts +65 -0
  127. package/dist/providers/pi.js +325 -0
  128. package/dist/providers/pi_context.d.ts +7 -0
  129. package/dist/providers/pi_context.js +405 -0
  130. package/dist/providers/pi_options.d.ts +11 -0
  131. package/dist/providers/pi_options.js +410 -0
  132. package/dist/providers/pi_output.d.ts +2 -0
  133. package/dist/providers/pi_output.js +453 -0
  134. package/dist/providers/provider_attempt_runner.d.ts +55 -0
  135. package/dist/providers/provider_attempt_runner.js +90 -0
  136. package/dist/providers/provider_call.d.ts +77 -0
  137. package/dist/providers/provider_call.js +296 -0
  138. package/dist/providers/provider_reported_cost.d.ts +10 -0
  139. package/dist/providers/provider_reported_cost.js +123 -0
  140. package/dist/providers/reasoning.d.ts +12 -0
  141. package/dist/providers/reasoning.js +30 -0
  142. package/dist/providers/response_capture.d.ts +23 -0
  143. package/dist/providers/response_capture.js +47 -0
  144. package/dist/providers/stream_finalization.d.ts +46 -0
  145. package/dist/providers/stream_finalization.js +165 -0
  146. package/dist/providers/subscription_limits.d.ts +33 -0
  147. package/dist/providers/subscription_limits.js +179 -0
  148. package/dist/providers/subscription_usage.d.ts +10 -0
  149. package/dist/providers/subscription_usage.js +79 -0
  150. package/dist/runtime/claude_code/auxiliary_routing.d.ts +3 -0
  151. package/dist/runtime/claude_code/auxiliary_routing.js +60 -0
  152. package/dist/runtime/customer_disconnect.d.ts +20 -0
  153. package/dist/runtime/customer_disconnect.js +49 -0
  154. package/dist/runtime/explicit_model.d.ts +7 -0
  155. package/dist/runtime/explicit_model.js +57 -0
  156. package/dist/runtime/harness_identity/conversation.d.ts +33 -0
  157. package/dist/runtime/harness_identity/conversation.js +39 -0
  158. package/dist/runtime/harness_identity/extract.d.ts +8 -0
  159. package/dist/runtime/harness_identity/extract.js +214 -0
  160. package/dist/runtime/harness_identity/index.d.ts +2 -0
  161. package/dist/runtime/harness_identity/index.js +2 -0
  162. package/dist/runtime/prepare_routed_completion.d.ts +33 -0
  163. package/dist/runtime/prepare_routed_completion.js +186 -0
  164. package/dist/runtime/provider_stream_lifecycle.d.ts +31 -0
  165. package/dist/runtime/provider_stream_lifecycle.js +88 -0
  166. package/dist/runtime/provider_stream_outcome.d.ts +23 -0
  167. package/dist/runtime/provider_stream_outcome.js +55 -0
  168. package/dist/runtime/request_tags.d.ts +7 -0
  169. package/dist/runtime/request_tags.js +33 -0
  170. package/dist/runtime/routed_completion.d.ts +17 -0
  171. package/dist/runtime/routed_completion.js +80 -0
  172. package/dist/runtime/routed_protocol.d.ts +30 -0
  173. package/dist/runtime/routed_protocol.js +1 -0
  174. package/dist/runtime/routed_runtime.d.ts +40 -0
  175. package/dist/runtime/routed_runtime.js +535 -0
  176. package/dist/runtime/routing_lease.d.ts +26 -0
  177. package/dist/runtime/routing_lease.js +210 -0
  178. package/dist/runtime/runtime_reporter.d.ts +71 -0
  179. package/dist/runtime/runtime_reporter.js +35 -0
  180. package/dist/runtime/strict_provider_access.d.ts +6 -0
  181. package/dist/runtime/strict_provider_access.js +40 -0
  182. package/dist/self_host/config.d.ts +46 -0
  183. package/dist/self_host/config.js +105 -0
  184. package/dist/self_host/main.d.ts +16 -0
  185. package/dist/self_host/main.js +95 -0
  186. package/dist/self_host/platform.d.ts +13 -0
  187. package/dist/self_host/platform.js +50 -0
  188. package/dist/self_host/prefix_store.d.ts +46 -0
  189. package/dist/self_host/prefix_store.js +261 -0
  190. package/dist/self_host/resolve.d.ts +28 -0
  191. package/dist/self_host/resolve.js +167 -0
  192. package/dist/self_host/subscriptions/access.d.ts +10 -0
  193. package/dist/self_host/subscriptions/access.js +37 -0
  194. package/dist/self_host/subscriptions/http.d.ts +15 -0
  195. package/dist/self_host/subscriptions/http.js +187 -0
  196. package/dist/self_host/subscriptions/index.d.ts +24 -0
  197. package/dist/self_host/subscriptions/index.js +24 -0
  198. package/dist/self_host/subscriptions/oauth.d.ts +59 -0
  199. package/dist/self_host/subscriptions/oauth.js +376 -0
  200. package/dist/self_host/subscriptions/store.d.ts +78 -0
  201. package/dist/self_host/subscriptions/store.js +236 -0
  202. package/dist/strategies/auto_routing_selector.d.ts +12 -0
  203. package/dist/strategies/auto_routing_selector.js +61 -0
  204. package/dist/strategies/eval_relevance.d.ts +17 -0
  205. package/dist/strategies/eval_relevance.js +32 -0
  206. package/dist/strategies/fallback_decision.d.ts +8 -0
  207. package/dist/strategies/fallback_decision.js +17 -0
  208. package/dist/strategies/priority_selector.d.ts +7 -0
  209. package/dist/strategies/priority_selector.js +37 -0
  210. package/dist/strategies/route_decision.d.ts +22 -0
  211. package/dist/strategies/route_decision.js +65 -0
  212. package/dist/strategies/routing.d.ts +74 -0
  213. package/dist/strategies/routing.js +280 -0
  214. package/dist/strategies/selector_projection.d.ts +15 -0
  215. package/dist/strategies/selector_projection.js +161 -0
  216. package/dist/telemetry/background.d.ts +7 -0
  217. package/dist/telemetry/background.js +33 -0
  218. package/dist/telemetry/benchmark_replay.d.ts +37 -0
  219. package/dist/telemetry/benchmark_replay.js +108 -0
  220. package/dist/telemetry/billing_finalization.d.ts +64 -0
  221. package/dist/telemetry/billing_finalization.js +96 -0
  222. package/dist/telemetry/ingest_values.d.ts +4 -0
  223. package/dist/telemetry/ingest_values.js +12 -0
  224. package/dist/telemetry/model_cost.d.ts +3 -0
  225. package/dist/telemetry/model_cost.js +15 -0
  226. package/dist/telemetry/prefix_state.d.ts +47 -0
  227. package/dist/telemetry/prefix_state.js +116 -0
  228. package/dist/telemetry/report.d.ts +88 -0
  229. package/dist/telemetry/report.js +621 -0
  230. package/dist/telemetry/requests/interaction_observability.d.ts +45 -0
  231. package/dist/telemetry/requests/interaction_observability.js +180 -0
  232. package/dist/telemetry/requests/retained_interaction_request.d.ts +8 -0
  233. package/dist/telemetry/requests/retained_interaction_request.js +10 -0
  234. package/dist/telemetry/scrub.d.ts +2 -0
  235. package/dist/telemetry/scrub.js +31 -0
  236. package/dist/telemetry/skills/claude/catalog.d.ts +6 -0
  237. package/dist/telemetry/skills/claude/catalog.js +99 -0
  238. package/dist/telemetry/skills/claude/file_reads.d.ts +4 -0
  239. package/dist/telemetry/skills/claude/file_reads.js +110 -0
  240. package/dist/telemetry/skills/claude/observations.d.ts +3 -0
  241. package/dist/telemetry/skills/claude/observations.js +366 -0
  242. package/dist/telemetry/skills/codex/catalog.d.ts +11 -0
  243. package/dist/telemetry/skills/codex/catalog.js +138 -0
  244. package/dist/telemetry/skills/codex/exec_file_reads.d.ts +9 -0
  245. package/dist/telemetry/skills/codex/exec_file_reads.js +36 -0
  246. package/dist/telemetry/skills/codex/explicit.d.ts +3 -0
  247. package/dist/telemetry/skills/codex/explicit.js +90 -0
  248. package/dist/telemetry/skills/codex/file_reads.d.ts +4 -0
  249. package/dist/telemetry/skills/codex/file_reads.js +37 -0
  250. package/dist/telemetry/skills/codex/identity.d.ts +2 -0
  251. package/dist/telemetry/skills/codex/identity.js +20 -0
  252. package/dist/telemetry/skills/observations.d.ts +21 -0
  253. package/dist/telemetry/skills/observations.js +41 -0
  254. package/dist/telemetry/skills/paths.d.ts +11 -0
  255. package/dist/telemetry/skills/paths.js +61 -0
  256. package/dist/telemetry/skills/pi.d.ts +6 -0
  257. package/dist/telemetry/skills/pi.js +223 -0
  258. package/dist/telemetry/skills/shell_file_reads.d.ts +7 -0
  259. package/dist/telemetry/skills/shell_file_reads.js +226 -0
  260. package/dist/telemetry/skills/shell_words.d.ts +13 -0
  261. package/dist/telemetry/skills/shell_words.js +189 -0
  262. package/dist/telemetry/tools/input.d.ts +2 -0
  263. package/dist/telemetry/tools/input.js +14 -0
  264. package/dist/telemetry/tools/observations.d.ts +29 -0
  265. package/dist/telemetry/tools/observations.js +247 -0
  266. package/dist/telemetry/usage.d.ts +57 -0
  267. package/dist/telemetry/usage.js +136 -0
  268. package/dist/types.d.ts +97 -0
  269. package/dist/types.js +1 -0
  270. package/package.json +22 -7
  271. package/src/bun.ts +2 -2
  272. package/src/context/eval_catalog.ts +1 -1
  273. package/src/context/interaction_fingerprint.ts +9 -9
  274. package/src/context/interaction_fingerprint_format.ts +1 -1
  275. package/src/context/interaction_lease_depth.ts +1 -1
  276. package/src/context/pricing.ts +6 -3
  277. package/src/context/provider_prompt_accounting.ts +5 -5
  278. package/src/context/routing_context.ts +16 -16
  279. package/src/http/auth.ts +1 -1
  280. package/src/http/handler.ts +15 -8
  281. package/src/http/serve.ts +3 -3
  282. package/src/index.ts +14 -6
  283. package/src/ingress/anthropic_messages.ts +12 -12
  284. package/src/ingress/anthropic_models.ts +1 -1
  285. package/src/ingress/chat_completions.ts +17 -10
  286. package/src/ingress/claude_code/request_context.ts +2 -2
  287. package/src/ingress/codex.ts +14 -10
  288. package/src/ingress/codex_models.ts +4 -4
  289. package/src/ingress/json.ts +1 -1
  290. package/src/ingress/models.ts +22 -10
  291. package/src/ingress/muse_code.ts +9 -0
  292. package/src/ingress/muse_models.ts +36 -0
  293. package/src/interaction/capabilities.ts +1 -1
  294. package/src/interaction/portable_reasoning_state.ts +1 -1
  295. package/src/interaction/provider_continuation_state.ts +1 -1
  296. package/src/interaction/tool_identity.ts +2 -2
  297. package/src/interaction/types.ts +2 -0
  298. package/src/models/catalog.ts +310 -0
  299. package/src/models/context_limits.ts +1 -1
  300. package/src/models/execution_provider.ts +5 -2
  301. package/src/models/ids.ts +1 -1
  302. package/src/models/provider_defaults.ts +4 -1
  303. package/src/models/runtime_overrides.ts +23 -1
  304. package/src/models/subscriptions.ts +54 -0
  305. package/src/observability/errors.ts +2 -2
  306. package/src/platform/platform.ts +9 -5
  307. package/src/protocol/input/anthropic_messages.ts +7 -7
  308. package/src/protocol/input/chat_completions.ts +8 -6
  309. package/src/protocol/input/chat_completions_validation.ts +6 -5
  310. package/src/protocol/input/openai_responses.ts +6 -6
  311. package/src/protocol/output/anthropic_messages.ts +3 -3
  312. package/src/protocol/output/anthropic_messages_output.ts +6 -4
  313. package/src/protocol/output/anthropic_messages_stream.ts +7 -7
  314. package/src/protocol/output/chat_completions.ts +13 -13
  315. package/src/protocol/output/chat_reasoning_detail.ts +1 -1
  316. package/src/protocol/output/openai_responses.ts +3 -3
  317. package/src/protocol/output/openai_responses_output.ts +4 -2
  318. package/src/protocol/output/openai_responses_stream.ts +6 -6
  319. package/src/protocol/output/sse_stream.ts +3 -3
  320. package/src/providers/anthropic_safeguards.ts +2 -2
  321. package/src/providers/aws_assume_role.ts +2 -2
  322. package/src/providers/cancel_estimate.ts +1 -1
  323. package/src/providers/execution.ts +17 -17
  324. package/src/providers/pi.ts +34 -19
  325. package/src/providers/pi_context.ts +6 -6
  326. package/src/providers/pi_options.ts +27 -11
  327. package/src/providers/pi_output.ts +5 -5
  328. package/src/providers/provider_attempt_runner.ts +1 -1
  329. package/src/providers/provider_call.ts +21 -17
  330. package/src/providers/provider_reported_cost.ts +3 -3
  331. package/src/providers/reasoning.ts +2 -2
  332. package/src/providers/stream_finalization.ts +9 -9
  333. package/src/providers/subscription_limits.ts +24 -7
  334. package/src/runtime/claude_code/auxiliary_routing.ts +5 -5
  335. package/src/runtime/customer_disconnect.ts +1 -1
  336. package/src/runtime/explicit_model.ts +19 -20
  337. package/src/runtime/harness_identity/conversation.ts +1 -1
  338. package/src/runtime/harness_identity/extract.ts +3 -3
  339. package/src/runtime/harness_identity/index.ts +2 -2
  340. package/src/runtime/prepare_routed_completion.ts +35 -16
  341. package/src/runtime/provider_stream_lifecycle.ts +1 -1
  342. package/src/runtime/provider_stream_outcome.ts +2 -2
  343. package/src/runtime/request_tags.ts +2 -2
  344. package/src/runtime/routed_completion.ts +11 -11
  345. package/src/runtime/routed_protocol.ts +2 -2
  346. package/src/runtime/routed_runtime.ts +20 -19
  347. package/src/runtime/routing_lease.ts +7 -7
  348. package/src/runtime/runtime_reporter.ts +3 -3
  349. package/src/runtime/strict_provider_access.ts +42 -0
  350. package/src/self_host/main.ts +12 -12
  351. package/src/self_host/platform.ts +5 -5
  352. package/src/self_host/prefix_store.ts +2 -2
  353. package/src/self_host/resolve.ts +17 -31
  354. package/src/self_host/subscriptions/access.ts +2 -2
  355. package/src/self_host/subscriptions/http.ts +2 -2
  356. package/src/self_host/subscriptions/index.ts +4 -4
  357. package/src/self_host/subscriptions/oauth.ts +139 -8
  358. package/src/self_host/subscriptions/store.ts +2 -1
  359. package/src/strategies/auto_routing_selector.ts +2 -2
  360. package/src/strategies/eval_relevance.ts +3 -3
  361. package/src/strategies/priority_selector.ts +1 -1
  362. package/src/strategies/route_decision.ts +7 -7
  363. package/src/strategies/routing.ts +10 -10
  364. package/src/strategies/selector_projection.ts +2 -2
  365. package/src/telemetry/billing_finalization.ts +3 -3
  366. package/src/telemetry/model_cost.ts +1 -1
  367. package/src/telemetry/prefix_state.ts +4 -4
  368. package/src/telemetry/report.ts +21 -21
  369. package/src/telemetry/requests/interaction_observability.ts +1 -1
  370. package/src/telemetry/requests/retained_interaction_request.ts +1 -1
  371. package/src/telemetry/skills/claude/catalog.ts +1 -1
  372. package/src/telemetry/skills/claude/file_reads.ts +6 -6
  373. package/src/telemetry/skills/claude/observations.ts +3 -3
  374. package/src/telemetry/skills/codex/catalog.ts +3 -3
  375. package/src/telemetry/skills/codex/exec_file_reads.ts +4 -4
  376. package/src/telemetry/skills/codex/explicit.ts +3 -3
  377. package/src/telemetry/skills/codex/file_reads.ts +5 -5
  378. package/src/telemetry/skills/observations.ts +7 -7
  379. package/src/telemetry/skills/pi.ts +3 -3
  380. package/src/telemetry/skills/shell_file_reads.ts +2 -2
  381. package/src/telemetry/skills/shell_words.ts +1 -1
  382. package/src/telemetry/tools/input.ts +1 -1
  383. package/src/telemetry/tools/observations.ts +9 -9
  384. package/src/telemetry/usage.ts +5 -5
  385. package/src/types.ts +20 -3
package/README.md CHANGED
@@ -64,7 +64,7 @@ docker run -p 8080:8080 \
64
64
  | `DARI_GATEWAY_DB` | SQLite database for subscriptions and conversation state. Default `dari-gateway.db`. It stores subscription tokens in plaintext; protect it like a secret. |
65
65
  | `DARI_AUTO_ROUTING_API_KEY` | Optional. Select among a router's models with Dari Auto Routing. |
66
66
  | `PORT` | Listen port. Default `8080`. |
67
- | Provider keys | Each provider's standard variable, such as `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, or `OPENROUTER_API_KEY`. |
67
+ | Provider keys | Each provider's standard variable, such as `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `META_API_KEY`, or `OPENROUTER_API_KEY`. |
68
68
 
69
69
  ## Configure
70
70
 
@@ -88,13 +88,17 @@ providers: # endpoints outside the built-in catalog
88
88
 
89
89
  Model ids are `provider/model`. Clients send `model: "dari/routing"` to let the router choose, or `model: "dari/model/<id>"` to pin one of its models. A Claude Code subscription serves Anthropic models only for Claude Code itself; a ChatGPT subscription serves OpenAI models for every client.
90
90
 
91
+ ### Model catalog
92
+
93
+ `GET /v1/models?detail=1` (any gateway key; optionally `&provider=openrouter,meta`) and `listModelCatalog({ providers?, fetch?, signal? })` list each provider's tool-capable models as `dari/model/<id>`-ready ids with context window, max output tokens, input modalities, accepted thinking levels, and list prices in USD per million tokens (input, output, cache read, cache write, long-context tiers) with `price_as_of`. OpenRouter and Vercel AI Gateway are read live from their public models endpoints; other providers (default: OpenAI, Anthropic, Meta, xAI, Fireworks) come from the bundled Pi catalog.
94
+
91
95
  ## Coding agents
92
96
 
93
97
  ```bash
94
98
  export DARI_GATEWAY_URL=http://localhost:8080
95
99
  export DARI_GATEWAY_KEY=<one of DARI_GATEWAY_KEYS>
96
100
 
97
- dari credentials subscription connect claude-code # or codex; repeat to pool plans
101
+ dari credentials subscription connect claude-code # or codex or muse-code; repeat to pool plans
98
102
  dari claude
99
103
  ```
100
104
 
@@ -115,8 +119,8 @@ The root entry needs no Bun APIs, so any runtime with web-standard `fetch`, `Req
115
119
 
116
120
  Platforms can also:
117
121
 
118
- - implement `resolveProviderCredential({ provider, model, routerId, organizationId, apiKey })` to supply a per-request `{ apiKey, baseUrl?, headers? }`, such as a tenant's own key, in place of the router's resolved key;
119
- - resolve routers with `strict: true` to serve only the requested `dari/model/<id>` at the requested thinking level, with no selector, lease, fallback, or personal subscription;
122
+ - implement `resolveProviderCredential({ provider, model, routerId, organizationId, apiKey, clientHarness? })` to supply a per-request `{ apiKey, baseUrl?, headers?, subscription? }`, such as a tenant's own key, in place of the router's resolved key. With `subscription` (`"openai_codex"`, `"anthropic_claude_code"`, or `"meta_muse"`), `apiKey` is that plan's access token: Codex's `auth.json` `tokens.access_token`, the token `claude setup-token` prints, or the Model API key a Meta sign-in mints. The platform keeps it fresh. Strict routers serve these supplied plans, but never subscriptions the gateway resolved itself. A plan serves only its own provider's models; a Claude Code plan serves only Claude Code clients, and a Muse Code plan only Muse Code clients (recognized by their `x-client-id`);
123
+ - resolve routers with `strict: true` to serve only the requested `dari/model/<id>` at the requested thinking level, with no selector, lease, fallback, or personal subscription. Set `strict_providers: ["openai"]` on the resolved router to permit any bundled-catalog model from that provider without enumerating `enabled_models`. Use `dari/model/openai/gpt-5.5`; bare IDs and unknown models remain refused. This grant is ignored on non-strict routers and does not discover uncatalogued models;
120
124
  - read exact usage from `recordRequest`: the summary carries input, output, cache-read, and cache-write tokens and `total_cost_usd`, preferring the provider's billed cost (`cost_source: "provider"`, from OpenRouter and Vercel AI Gateway). Failed and aborted requests are recorded too;
121
125
  - attribute cost with `X-Dari-Tags: run=r1,trial=3`, which is parsed into `RequestRecord.tags` and the `recordUsage` payload's `tags`.
122
126
 
package/dist/bun.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export { installShutdownHandlers, startServer } from "./http/serve.js";
2
+ export { startSelfHostedGateway } from "./self_host/main.js";
package/dist/bun.js ADDED
@@ -0,0 +1,4 @@
1
+ // Bun-only entry points: the Bun.serve HTTP server and the self-hosted
2
+ // gateway, whose state lives in bun:sqlite.
3
+ export { installShutdownHandlers, startServer } from "./http/serve.js";
4
+ export { startSelfHostedGateway } from "./self_host/main.js";
@@ -0,0 +1,3 @@
1
+ import type { PublicEvalCatalogCard } from "../types.js";
2
+ import type { RouterEval } from "@mupt-ai/dari-router/policy-engine";
3
+ export declare function publicCatalogSelectorEvals(catalog: PublicEvalCatalogCard[] | null | undefined): RouterEval[];
@@ -0,0 +1,7 @@
1
+ // Convert public cards into hidden ratio-calibration inputs. Cards without a
2
+ // sync timestamp or scores carry no signal and are dropped.
3
+ export function publicCatalogSelectorEvals(catalog) {
4
+ if (!catalog)
5
+ return [];
6
+ return catalog.filter((card) => card.updated_at !== null && card.scores.length > 0);
7
+ }
@@ -0,0 +1,27 @@
1
+ import type { InteractionOutput, InteractionRequest, ProviderIdentity } from "../interaction/types.js";
2
+ export type InteractionPrefixContext = {
3
+ chainByModel: ReadonlyMap<string, string[]>;
4
+ itemIndexByHashByModel: ReadonlyMap<string, ReadonlyMap<string, number>>;
5
+ looseChain: string[];
6
+ fingerprints: {
7
+ tool_choice_fp: string;
8
+ response_format_fp: string;
9
+ };
10
+ };
11
+ /**
12
+ * Hash variants sent during router resolution. The portable chain covers
13
+ * providers that receive readable history only. Exact continuation-source
14
+ * variants cover a return to the originating model. Because provider APIs
15
+ * are unknown before resolution, Responses tool history also contributes a
16
+ * composite call/item-ID variant for OpenAI-compatible Responses targets.
17
+ */
18
+ export declare function interactionPrefixLookupHashes(routerId: string, request: InteractionRequest): string[];
19
+ export declare function interactionLooseChain(routerId: string, request: InteractionRequest): string[];
20
+ export declare function interactionConversationPrefix(request: InteractionRequest): string;
21
+ export declare function interactionPrefixContext(routerId: string, request: InteractionRequest, targets: ReadonlyMap<string, ProviderIdentity>): InteractionPrefixContext;
22
+ export declare function interactionPrefixChain(routerId: string, request: InteractionRequest, target: ProviderIdentity | null): string[];
23
+ export declare function extendInteractionChain(lastHash: string, output: InteractionOutput, target: ProviderIdentity, policy: {
24
+ includeItemIds: boolean;
25
+ sourceProtocol: InteractionRequest["sourceProtocol"];
26
+ }): string[];
27
+ export declare function extendInteractionLooseChain(lastHash: string, output: InteractionOutput, sourceProtocol: InteractionRequest["sourceProtocol"]): string[];
@@ -0,0 +1,519 @@
1
+ import { createHash } from "node:crypto";
2
+ import { stableStringify } from "@mupt-ai/dari-router/policy-engine";
3
+ import { anthropicMessagesToInteraction } from "../protocol/input/anthropic_messages.js";
4
+ import { internalChatCompletionsToInteraction } from "../protocol/input/chat_completions.js";
5
+ import { anthropicContent } from "../protocol/output/anthropic_messages_output.js";
6
+ import { assistantMessagePayload } from "../protocol/output/chat_completions.js";
7
+ import { compatibleProviderContinuation } from "../interaction/provider_continuation_state.js";
8
+ import { providerToolCallId, toolWireName } from "../interaction/tool_identity.js";
9
+ import { ROUTING_PREFIX_HASHES_MAX_COUNT } from "../platform/routing_contract.js";
10
+ import { appendFingerprintContentText, canonicalInteractionFingerprintStep, interactionFingerprintContent, interactionFingerprintHeadHash, interactionOptionsFingerprints, normalizedAssistantFingerprintContent, } from "./interaction_fingerprint_format.js";
11
+ const MAX_CONTINUATION_TARGETS = 16;
12
+ // The loose tier ignores reasoning and item ids, so provider identity and
13
+ // tool-call-id composition cannot influence it: one chain per request.
14
+ const LOOSE_POLICY = {
15
+ includeItemIds: false,
16
+ includePhase: false,
17
+ canonicalizeFunctionArguments: true,
18
+ loose: true,
19
+ };
20
+ // Salts the loose chain's seed so the two hash tiers can never collide in
21
+ // the shared prefix-entry lookup space.
22
+ const LOOSE_SEED_SALT = "fp-loose-1";
23
+ const CONVERSATION_PREFIX_VERSION = "conversation-prefix-v1";
24
+ /**
25
+ * Hash variants sent during router resolution. The portable chain covers
26
+ * providers that receive readable history only. Exact continuation-source
27
+ * variants cover a return to the originating model. Because provider APIs
28
+ * are unknown before resolution, Responses tool history also contributes a
29
+ * composite call/item-ID variant for OpenAI-compatible Responses targets.
30
+ */
31
+ export function interactionPrefixLookupHashes(routerId, request) {
32
+ const targets = [null];
33
+ const seen = new Set();
34
+ for (let index = request.items.length - 1; index >= 0 && seen.size < MAX_CONTINUATION_TARGETS; index -= 1) {
35
+ const item = request.items[index];
36
+ if (item.type !== "reasoning" || !item.continuation)
37
+ continue;
38
+ const key = identityKey(item.continuation.source);
39
+ if (seen.has(key))
40
+ continue;
41
+ seen.add(key);
42
+ targets.push(item.continuation.source);
43
+ }
44
+ const chains = targets.map((target) => interactionPrefixChain(routerId, request, target));
45
+ if (request.sourceProtocol === "openai_responses") {
46
+ chains.push(interactionPrefixChainFor(routerId, request, null, "openai-responses"));
47
+ }
48
+ chains.push(interactionLooseChain(routerId, request));
49
+ return deepestDistinctHashes(chains, ROUTING_PREFIX_HASHES_MAX_COUNT);
50
+ }
51
+ // The loose (client-durable) chain: what the conversation looks like once
52
+ // reasoning payloads, item ids, and provider-specific canonicalization are
53
+ // stripped. Distinct seed keeps its hashes disjoint from the strict tier.
54
+ export function interactionLooseChain(routerId, request) {
55
+ return fingerprintChain(sha256(`${interactionFingerprintHeadHash(routerId, request)}\u0000${LOOSE_SEED_SALT}`), looseFingerprintSteps(request.sourceProtocol, request.items));
56
+ }
57
+ // Stable logical-conversation discriminator. This deliberately excludes the
58
+ // cache head (instructions and tools) and hashes only the first normalized
59
+ // transcript step. Growing history and tool changes preserve identity, while
60
+ // unrelated work reusing the same harness session gets a new group.
61
+ export function interactionConversationPrefix(request) {
62
+ const firstStep = conversationFingerprintSteps(looseFingerprintSteps(request.sourceProtocol, request.items)).at(0);
63
+ return sha256(stableStringify({
64
+ version: CONVERSATION_PREFIX_VERSION,
65
+ firstStep: firstStep === undefined
66
+ ? null
67
+ : canonicalInteractionFingerprintStep(firstStep),
68
+ }));
69
+ }
70
+ export function interactionPrefixContext(routerId, request, targets) {
71
+ const chainByModel = new Map();
72
+ const itemIndexByHashByModel = new Map();
73
+ for (const [model, target] of targets) {
74
+ const steps = interactionPrefixStepsFor(routerId, request, target, target.api);
75
+ chainByModel.set(model, steps.map((step) => step.hash));
76
+ itemIndexByHashByModel.set(model, new Map(steps.map((step) => [step.hash, step.itemIndex])));
77
+ }
78
+ return {
79
+ chainByModel,
80
+ itemIndexByHashByModel,
81
+ looseChain: interactionLooseChain(routerId, request),
82
+ fingerprints: interactionOptionsFingerprints(request),
83
+ };
84
+ }
85
+ // Loose fingerprints share the strict grouping logic so step boundaries
86
+ // stay identical whether or not the client echoed reasoning; the policy just
87
+ // drops the volatile fields. Target-independent by construction.
88
+ function looseFingerprintSteps(sourceProtocol, items) {
89
+ return sourceProtocol === "openai_chat"
90
+ ? fingerprintChatInputSteps(items, null, null, LOOSE_POLICY)
91
+ : fingerprintSteps(items, null, null, LOOSE_POLICY);
92
+ }
93
+ export function interactionPrefixChain(routerId, request, target) {
94
+ return interactionPrefixStepsFor(routerId, request, target, target?.api ?? null)
95
+ .map((step) => step.hash);
96
+ }
97
+ function interactionPrefixChainFor(routerId, request, target, toolCallApi) {
98
+ return interactionPrefixStepsFor(routerId, request, target, toolCallApi)
99
+ .map((step) => step.hash);
100
+ }
101
+ function interactionPrefixStepsFor(routerId, request, target, toolCallApi) {
102
+ let hash = interactionFingerprintHeadHash(routerId, request);
103
+ const steps = [];
104
+ const responses = request.sourceProtocol === "openai_responses";
105
+ const fingerprintStepsForRequest = conversationFingerprintSteps(request.sourceProtocol === "openai_chat"
106
+ ? fingerprintChatInputSteps(request.items, target, toolCallApi)
107
+ : fingerprintSteps(request.items, target, toolCallApi, {
108
+ includeItemIds: true,
109
+ includePhase: responses,
110
+ canonicalizeFunctionArguments: responses,
111
+ }));
112
+ for (const step of fingerprintStepsForRequest) {
113
+ hash = extendFingerprintHash(hash, step);
114
+ steps.push({ hash, itemIndex: step.itemIndex });
115
+ }
116
+ return steps;
117
+ }
118
+ export function extendInteractionChain(lastHash, output, target, policy) {
119
+ let hash = lastHash;
120
+ const extension = [];
121
+ const steps = fingerprintClientEchoSteps(output, target, policy);
122
+ for (const step of steps) {
123
+ if (step.actor === "system" || step.actor === "developer")
124
+ continue;
125
+ hash = extendFingerprintHash(hash, step);
126
+ extension.push(hash);
127
+ }
128
+ return extension;
129
+ }
130
+ function fingerprintClientEchoSteps(output, target, policy) {
131
+ const items = clientEchoItems(output, policy.sourceProtocol);
132
+ if (policy.sourceProtocol === "openai_chat") {
133
+ return fingerprintChatInputSteps(items, target, target.api);
134
+ }
135
+ return fingerprintSteps(items, target, target.api, {
136
+ includeItemIds: policy.includeItemIds,
137
+ includePhase: policy.sourceProtocol === "openai_responses",
138
+ canonicalizeFunctionArguments: true,
139
+ });
140
+ }
141
+ // Prefix extensions must match the assistant output as the next client request
142
+ // will carry it, not necessarily the provider's canonical output items.
143
+ function clientEchoItems(output, sourceProtocol) {
144
+ if (sourceProtocol === "openai_chat") {
145
+ return internalChatCompletionsToInteraction({
146
+ model: "dari/routing",
147
+ messages: [assistantMessagePayload(output)],
148
+ }).items;
149
+ }
150
+ if (sourceProtocol === "anthropic_messages") {
151
+ return anthropicMessagesToInteraction({
152
+ model: "dari/routing",
153
+ max_tokens: 1,
154
+ messages: [{ role: "assistant", content: anthropicContent(output) }],
155
+ }).items;
156
+ }
157
+ return output.items;
158
+ }
159
+ // Loose-tier extension for the reply, mirroring interactionLooseChain's
160
+ // policy: what the next request's loose chain computes at this depth no
161
+ // matter which volatile fields the client's echo keeps.
162
+ export function extendInteractionLooseChain(lastHash, output, sourceProtocol) {
163
+ let hash = lastHash;
164
+ const extension = [];
165
+ const items = clientEchoItems(output, sourceProtocol);
166
+ for (const step of looseFingerprintSteps(sourceProtocol, items)) {
167
+ if (step.actor === "system" || step.actor === "developer")
168
+ continue;
169
+ hash = extendFingerprintHash(hash, step);
170
+ extension.push(hash);
171
+ }
172
+ return extension;
173
+ }
174
+ // Chat carries reasoning, assistant text, and tool calls in one assistant
175
+ // message. Its canonical interaction items intentionally separate those
176
+ // concerns, so prefix hashing must regroup one wire message before hashing.
177
+ function fingerprintChatInputSteps(items, target, toolCallApi, policy) {
178
+ const steps = [];
179
+ const toolCalls = new Map();
180
+ let pendingReasoning = [];
181
+ let pendingReasoningItemIndex = -1;
182
+ const flushReasoning = () => {
183
+ if (pendingReasoning.length === 0)
184
+ return;
185
+ steps.push({
186
+ actor: "assistant",
187
+ itemIndex: pendingReasoningItemIndex,
188
+ content: null,
189
+ calls: [],
190
+ resultCallId: null,
191
+ reasoning: pendingReasoning,
192
+ });
193
+ pendingReasoning = [];
194
+ pendingReasoningItemIndex = -1;
195
+ };
196
+ for (const [itemIndex, item] of items.entries()) {
197
+ if (item.type === "reasoning") {
198
+ if (policy?.loose)
199
+ continue;
200
+ pendingReasoning.push(reasoningFingerprint(item, target, false));
201
+ pendingReasoningItemIndex = itemIndex;
202
+ continue;
203
+ }
204
+ if (item.type === "message") {
205
+ if (item.role !== "assistant")
206
+ flushReasoning();
207
+ steps.push({
208
+ actor: item.role,
209
+ itemIndex,
210
+ content: item.role === "assistant"
211
+ ? normalizedAssistantFingerprintContent(item.content, item.contentShape)
212
+ : interactionFingerprintContent(item.content, item.contentShape),
213
+ calls: [],
214
+ resultCallId: null,
215
+ ...(item.role === "assistant" && pendingReasoning.length > 0
216
+ ? { reasoning: pendingReasoning }
217
+ : {}),
218
+ });
219
+ pendingReasoning = [];
220
+ pendingReasoningItemIndex = -1;
221
+ continue;
222
+ }
223
+ if (item.type === "reasoning_configuration") {
224
+ // Configuration updates change execution effort without becoming part
225
+ // of the conversational identity, just like request-level effort.
226
+ flushReasoning();
227
+ continue;
228
+ }
229
+ if (item.type === "tool_result") {
230
+ flushReasoning();
231
+ steps.push({
232
+ actor: "tool",
233
+ itemIndex,
234
+ content: interactionFingerprintContent(item.output, item.outputShape),
235
+ calls: [],
236
+ resultCallId: toolCalls.get(item.callId) ?? item.callId,
237
+ });
238
+ continue;
239
+ }
240
+ flushReasoning();
241
+ let assistant = steps.at(-1);
242
+ if (!assistant || assistant.actor !== "assistant") {
243
+ assistant = {
244
+ actor: "assistant",
245
+ content: null,
246
+ calls: [],
247
+ resultCallId: null,
248
+ itemIndex,
249
+ };
250
+ steps.push(assistant);
251
+ }
252
+ assistant.itemIndex = itemIndex;
253
+ if (item.type === "tool_call") {
254
+ const id = appendToolCall(assistant, item, toolCallApi, false, policy?.canonicalizeFunctionArguments ?? false);
255
+ toolCalls.set(item.callId, id);
256
+ }
257
+ else {
258
+ appendHostedToolCall(assistant, item);
259
+ }
260
+ }
261
+ flushReasoning();
262
+ return steps;
263
+ }
264
+ function fingerprintSteps(items, target, toolCallApi, policy) {
265
+ const steps = [];
266
+ const toolCalls = new Map();
267
+ for (const [itemIndex, item] of items.entries()) {
268
+ if (item.type === "reasoning") {
269
+ if (policy.loose)
270
+ continue;
271
+ const continuation = compatibleProviderContinuation(item.continuation, target);
272
+ const readable = continuationReadableText(item, continuation);
273
+ const itemFingerprint = reasoningFingerprint(item, target, policy.includeItemIds);
274
+ const previous = steps.at(-1);
275
+ if (previous?.actor === "assistant"
276
+ && (previous.calls.length > 0 || previous.reasoning?.length)) {
277
+ previous.itemIndex = itemIndex;
278
+ previous.content = appendFingerprintContentText(previous.content, readable);
279
+ previous.reasoning = [...(previous.reasoning ?? []), itemFingerprint];
280
+ continue;
281
+ }
282
+ steps.push({
283
+ actor: "assistant",
284
+ itemIndex,
285
+ content: readable || null,
286
+ calls: [],
287
+ resultCallId: null,
288
+ reasoning: [itemFingerprint],
289
+ });
290
+ continue;
291
+ }
292
+ if (item.type === "reasoning_configuration") {
293
+ continue;
294
+ }
295
+ if (item.type === "tool_result") {
296
+ steps.push({
297
+ actor: "tool",
298
+ itemIndex,
299
+ content: interactionFingerprintContent(item.output, item.outputShape),
300
+ calls: [],
301
+ resultCallId: toolCalls.get(item.callId) ?? item.callId,
302
+ });
303
+ continue;
304
+ }
305
+ if (item.type === "tool_call") {
306
+ let assistant = steps.at(-1);
307
+ if (!assistant || assistant.actor !== "assistant") {
308
+ assistant = {
309
+ actor: "assistant",
310
+ content: null,
311
+ calls: [],
312
+ resultCallId: null,
313
+ itemIndex,
314
+ };
315
+ steps.push(assistant);
316
+ }
317
+ assistant.itemIndex = itemIndex;
318
+ const id = appendToolCall(assistant, item, toolCallApi, policy.includeItemIds, policy.canonicalizeFunctionArguments);
319
+ toolCalls.set(item.callId, id);
320
+ continue;
321
+ }
322
+ if (item.type === "hosted_tool_call") {
323
+ let assistant = steps.at(-1);
324
+ if (!assistant || assistant.actor !== "assistant") {
325
+ assistant = {
326
+ actor: "assistant",
327
+ content: null,
328
+ calls: [],
329
+ resultCallId: null,
330
+ itemIndex,
331
+ };
332
+ steps.push(assistant);
333
+ }
334
+ assistant.itemIndex = itemIndex;
335
+ appendHostedToolCall(assistant, item);
336
+ continue;
337
+ }
338
+ steps.push({
339
+ actor: item.role,
340
+ itemIndex,
341
+ content: policy.loose && item.role === "assistant"
342
+ ? normalizedAssistantFingerprintContent(item.content, item.contentShape)
343
+ : interactionFingerprintContent(item.content, item.contentShape),
344
+ calls: [],
345
+ resultCallId: null,
346
+ ...(policy.includeItemIds && item.id ? { itemId: item.id } : {}),
347
+ ...(policy.includePhase && item.phase ? { phase: item.phase } : {}),
348
+ });
349
+ }
350
+ return steps;
351
+ }
352
+ function reasoningFingerprint(item, target, includeItemId) {
353
+ const continuation = compatibleProviderContinuation(item.continuation, target);
354
+ const readable = continuationReadableText(item, continuation);
355
+ return {
356
+ ...(includeItemId && item.id ? { itemId: item.id } : {}),
357
+ readableSha256: sha256(readable),
358
+ ...(continuation
359
+ ? { continuationStateSha256: sha256(stableStringify(continuation)) }
360
+ : {}),
361
+ };
362
+ }
363
+ function appendToolCall(assistant, item, toolCallApi, includeItemId, canonicalizeFunctionArguments) {
364
+ const id = providerToolCallId(item.callId, includeItemId ? item.id : undefined, toolCallApi);
365
+ assistant.calls = [
366
+ ...assistant.calls,
367
+ {
368
+ id,
369
+ kind: item.kind,
370
+ name: toolWireName(item.namespace, item.name),
371
+ input: toolArguments(item.kind, item.input, canonicalizeFunctionArguments),
372
+ },
373
+ ];
374
+ return id;
375
+ }
376
+ function appendHostedToolCall(assistant, item) {
377
+ const payload = {
378
+ ...item.payload,
379
+ type: item.providerType,
380
+ id: item.id,
381
+ };
382
+ if (item.status)
383
+ payload.status = item.status;
384
+ else
385
+ delete payload.status;
386
+ assistant.calls = [
387
+ ...assistant.calls,
388
+ {
389
+ id: item.id,
390
+ kind: "hosted",
391
+ name: item.tool,
392
+ input: payload,
393
+ },
394
+ ];
395
+ }
396
+ function continuationReadableText(item, continuation) {
397
+ if (continuation?.kind === "anthropic_thinking")
398
+ return normalizedReadable(continuation.thinking);
399
+ if (continuation?.kind === "anthropic_redacted_thinking")
400
+ return "";
401
+ return normalizedReadable([...item.summary, ...item.content].join("\n"));
402
+ }
403
+ // Streamed reasoning reaches clients as delta concatenations whose whitespace
404
+ // joins differ from the aggregated response body (part separators, trailing
405
+ // newlines), and the client echoes whichever form it saw. Whitespace therefore
406
+ // cannot participate in conversation identity.
407
+ function normalizedReadable(text) {
408
+ return text.replace(/\s+/g, " ").trim();
409
+ }
410
+ function fingerprintChain(seed, steps) {
411
+ let hash = seed;
412
+ return conversationFingerprintSteps(steps).map((step) => {
413
+ hash = extendFingerprintHash(hash, step);
414
+ return hash;
415
+ });
416
+ }
417
+ function conversationFingerprintSteps(steps) {
418
+ const positional = [];
419
+ let sawConversationStep = false;
420
+ for (const step of steps) {
421
+ if (step.actor !== "system" && step.actor !== "developer") {
422
+ sawConversationStep = true;
423
+ const previous = positional.at(-1);
424
+ if (step.actor === "user" && previous?.actor === "user") {
425
+ previous.content = appendPositionalFingerprintContent(previous.content, step.content);
426
+ previous.itemIndex = step.itemIndex;
427
+ }
428
+ else {
429
+ positional.push({ ...step });
430
+ }
431
+ continue;
432
+ }
433
+ if (!sawConversationStep)
434
+ continue;
435
+ const text = fingerprintReadableText(step.content);
436
+ if (!text)
437
+ continue;
438
+ const previous = positional.at(-1);
439
+ if (previous?.actor === "user" || previous?.actor === "tool") {
440
+ previous.content = appendPositionalFingerprintText(previous.content, text);
441
+ previous.itemIndex = step.itemIndex;
442
+ continue;
443
+ }
444
+ positional.push({
445
+ actor: "user",
446
+ content: [{ type: "text", text }],
447
+ calls: [],
448
+ resultCallId: null,
449
+ itemIndex: step.itemIndex,
450
+ });
451
+ }
452
+ return positional;
453
+ }
454
+ function fingerprintReadableText(content) {
455
+ if (typeof content === "string")
456
+ return content;
457
+ if (!Array.isArray(content))
458
+ return "";
459
+ return content.map((part) => part.type === "text" ? part.text : "(image omitted)").join("\n");
460
+ }
461
+ function appendPositionalFingerprintText(content, text) {
462
+ return appendPositionalFingerprintContent(content, [{ type: "text", text }]);
463
+ }
464
+ function appendPositionalFingerprintContent(content, appended) {
465
+ const contentParts = typeof content === "string"
466
+ ? [{ type: "text", text: content }]
467
+ : content ?? [];
468
+ const appendedParts = typeof appended === "string"
469
+ ? [{ type: "text", text: appended }]
470
+ : appended ?? [];
471
+ return [...contentParts, ...appendedParts];
472
+ }
473
+ function extendFingerprintHash(lastHash, step) {
474
+ return sha256(`${lastHash}\u0000${canonicalInteractionFingerprintStep(step)}`);
475
+ }
476
+ function toolArguments(kind, input, canonicalizeFunctionArguments) {
477
+ if (kind === "custom")
478
+ return JSON.stringify({ input: typeof input === "string" ? input : "" });
479
+ if (canonicalizeFunctionArguments && typeof input === "string") {
480
+ try {
481
+ const parsed = JSON.parse(input);
482
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed))
483
+ return parsed;
484
+ }
485
+ catch {
486
+ // Provider execution reports malformed function arguments separately;
487
+ // fingerprinting itself must remain best-effort.
488
+ }
489
+ }
490
+ return input;
491
+ }
492
+ function deepestDistinctHashes(chains, max) {
493
+ const result = [];
494
+ const seen = new Set();
495
+ for (let depth = 1; result.length < max; depth += 1) {
496
+ let found = false;
497
+ for (const chain of chains) {
498
+ const hash = chain.at(-depth);
499
+ if (!hash)
500
+ continue;
501
+ found = true;
502
+ if (!seen.has(hash)) {
503
+ seen.add(hash);
504
+ result.push(hash);
505
+ if (result.length === max)
506
+ break;
507
+ }
508
+ }
509
+ if (!found)
510
+ break;
511
+ }
512
+ return result;
513
+ }
514
+ function identityKey(identity) {
515
+ return `${identity.provider}\u0000${identity.api}\u0000${identity.model}`;
516
+ }
517
+ function sha256(text) {
518
+ return createHash("sha256").update(text, "utf8").digest("hex");
519
+ }
@@ -0,0 +1,42 @@
1
+ import type { InteractionContent, InteractionRequest } from "../interaction/types.js";
2
+ export type FingerprintContent = string | Array<{
3
+ type: "text";
4
+ text: string;
5
+ } | {
6
+ type: "image";
7
+ url: string;
8
+ detail?: "auto" | "low" | "high" | "original";
9
+ } | {
10
+ type: "tool_reference";
11
+ toolName: string;
12
+ }> | null;
13
+ export type FingerprintCall = {
14
+ id: string;
15
+ kind: "function" | "custom" | "hosted";
16
+ name: string;
17
+ input: unknown;
18
+ };
19
+ export type ReasoningFingerprint = {
20
+ itemId?: string;
21
+ readableSha256: string;
22
+ continuationStateSha256?: string;
23
+ };
24
+ export type InteractionFingerprintStep = {
25
+ actor: "system" | "developer" | "user" | "assistant" | "tool";
26
+ content: FingerprintContent;
27
+ calls: FingerprintCall[];
28
+ resultCallId: string | null;
29
+ itemIndex: number;
30
+ itemId?: string;
31
+ phase?: "commentary" | "final_answer";
32
+ reasoning?: ReasoningFingerprint[];
33
+ };
34
+ export declare function interactionFingerprintHeadHash(routerId: string, request: InteractionRequest): string;
35
+ export declare function interactionOptionsFingerprints(request: InteractionRequest): {
36
+ tool_choice_fp: string;
37
+ response_format_fp: string;
38
+ };
39
+ export declare function canonicalInteractionFingerprintStep(step: InteractionFingerprintStep): string;
40
+ export declare function interactionFingerprintContent(content: string | InteractionContent[] | null, shape: "string" | "parts" | "null" | "absent"): FingerprintContent;
41
+ export declare function normalizedAssistantFingerprintContent(content: string | InteractionContent[] | null, shape: "string" | "parts" | "null" | "absent"): FingerprintContent;
42
+ export declare function appendFingerprintContentText(content: FingerprintContent, text: string): FingerprintContent;