@jsonstudio/llms 0.4.2

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 (538) hide show
  1. package/README.md +265 -0
  2. package/dist/api/index.d.ts +10 -0
  3. package/dist/api/index.js +11 -0
  4. package/dist/api/llmswitch-config.d.ts +15 -0
  5. package/dist/api/llmswitch-config.js +415 -0
  6. package/dist/api/llmswitch-types.d.ts +412 -0
  7. package/dist/api/llmswitch-types.js +60 -0
  8. package/dist/bridge/routecodex-adapter.d.ts +74 -0
  9. package/dist/bridge/routecodex-adapter.js +226 -0
  10. package/dist/config/index.d.ts +3 -0
  11. package/dist/config/index.js +5 -0
  12. package/dist/config-unified/enhanced-path-resolver.d.ts +5 -0
  13. package/dist/config-unified/enhanced-path-resolver.js +38 -0
  14. package/dist/config-unified/unified-config.d.ts +26 -0
  15. package/dist/config-unified/unified-config.js +187 -0
  16. package/dist/conversion/codec-registry.d.ts +10 -0
  17. package/dist/conversion/codec-registry.js +25 -0
  18. package/dist/conversion/codecs/anthropic-openai-codec.d.ts +23 -0
  19. package/dist/conversion/codecs/anthropic-openai-codec.js +546 -0
  20. package/dist/conversion/codecs/gemini-openai-codec.d.ts +16 -0
  21. package/dist/conversion/codecs/gemini-openai-codec.js +437 -0
  22. package/dist/conversion/codecs/openai-openai-codec.d.ts +12 -0
  23. package/dist/conversion/codecs/openai-openai-codec.js +125 -0
  24. package/dist/conversion/codecs/responses-openai-codec.d.ts +12 -0
  25. package/dist/conversion/codecs/responses-openai-codec.js +154 -0
  26. package/dist/conversion/config/config-manager.d.ts +212 -0
  27. package/dist/conversion/config/config-manager.js +310 -0
  28. package/dist/conversion/conversion-v3/adapters/index.d.ts +2 -0
  29. package/dist/conversion/conversion-v3/adapters/index.js +1 -0
  30. package/dist/conversion/conversion-v3/adapters/v3-to-standard-adapter.d.ts +38 -0
  31. package/dist/conversion/conversion-v3/adapters/v3-to-standard-adapter.js +55 -0
  32. package/dist/conversion/conversion-v3/compatibility/compatibility-profiles.d.ts +22 -0
  33. package/dist/conversion/conversion-v3/compatibility/compatibility-profiles.js +84 -0
  34. package/dist/conversion/conversion-v3/compatibility/compatibility-stages.d.ts +4 -0
  35. package/dist/conversion/conversion-v3/compatibility/compatibility-stages.js +285 -0
  36. package/dist/conversion/conversion-v3/compatibility/index.d.ts +3 -0
  37. package/dist/conversion/conversion-v3/compatibility/index.js +2 -0
  38. package/dist/conversion/conversion-v3/config/default-configs.d.ts +48 -0
  39. package/dist/conversion/conversion-v3/config/default-configs.js +1083 -0
  40. package/dist/conversion/conversion-v3/config/index.d.ts +5 -0
  41. package/dist/conversion/conversion-v3/config/index.js +5 -0
  42. package/dist/conversion/conversion-v3/config/pipeline-config-manager.d.ts +49 -0
  43. package/dist/conversion/conversion-v3/config/pipeline-config-manager.js +65 -0
  44. package/dist/conversion/conversion-v3/index.d.ts +11 -0
  45. package/dist/conversion/conversion-v3/index.js +17 -0
  46. package/dist/conversion/conversion-v3/nodes/index.d.ts +56 -0
  47. package/dist/conversion/conversion-v3/nodes/index.js +149 -0
  48. package/dist/conversion/conversion-v3/nodes/input/anthropic-input-node.d.ts +25 -0
  49. package/dist/conversion/conversion-v3/nodes/input/anthropic-input-node.js +56 -0
  50. package/dist/conversion/conversion-v3/nodes/input/base-input-node.d.ts +75 -0
  51. package/dist/conversion/conversion-v3/nodes/input/base-input-node.js +237 -0
  52. package/dist/conversion/conversion-v3/nodes/input/chat-input-node.d.ts +25 -0
  53. package/dist/conversion/conversion-v3/nodes/input/chat-input-node.js +56 -0
  54. package/dist/conversion/conversion-v3/nodes/input/chat-shape-helpers.d.ts +4 -0
  55. package/dist/conversion/conversion-v3/nodes/input/chat-shape-helpers.js +197 -0
  56. package/dist/conversion/conversion-v3/nodes/input/gemini-input-node.d.ts +16 -0
  57. package/dist/conversion/conversion-v3/nodes/input/gemini-input-node.js +125 -0
  58. package/dist/conversion/conversion-v3/nodes/input/index.d.ts +8 -0
  59. package/dist/conversion/conversion-v3/nodes/input/index.js +8 -0
  60. package/dist/conversion/conversion-v3/nodes/input/input-decision.d.ts +46 -0
  61. package/dist/conversion/conversion-v3/nodes/input/input-decision.js +125 -0
  62. package/dist/conversion/conversion-v3/nodes/input/responses-input-node.d.ts +20 -0
  63. package/dist/conversion/conversion-v3/nodes/input/responses-input-node.js +51 -0
  64. package/dist/conversion/conversion-v3/nodes/output/anthropic-output-node.d.ts +71 -0
  65. package/dist/conversion/conversion-v3/nodes/output/anthropic-output-node.js +320 -0
  66. package/dist/conversion/conversion-v3/nodes/output/base-output-node.d.ts +116 -0
  67. package/dist/conversion/conversion-v3/nodes/output/base-output-node.js +512 -0
  68. package/dist/conversion/conversion-v3/nodes/output/index.d.ts +7 -0
  69. package/dist/conversion/conversion-v3/nodes/output/index.js +7 -0
  70. package/dist/conversion/conversion-v3/nodes/output/openai-output-node.d.ts +71 -0
  71. package/dist/conversion/conversion-v3/nodes/output/openai-output-node.js +293 -0
  72. package/dist/conversion/conversion-v3/nodes/output/output-decision.d.ts +68 -0
  73. package/dist/conversion/conversion-v3/nodes/output/output-decision.js +161 -0
  74. package/dist/conversion/conversion-v3/nodes/output/responses-output-node.d.ts +64 -0
  75. package/dist/conversion/conversion-v3/nodes/output/responses-output-node.js +323 -0
  76. package/dist/conversion/conversion-v3/nodes/process/base-process-node.d.ts +72 -0
  77. package/dist/conversion/conversion-v3/nodes/process/base-process-node.js +246 -0
  78. package/dist/conversion/conversion-v3/nodes/process/chat-process-node.d.ts +135 -0
  79. package/dist/conversion/conversion-v3/nodes/process/chat-process-node.js +854 -0
  80. package/dist/conversion/conversion-v3/nodes/process/compatibility-process-node.d.ts +29 -0
  81. package/dist/conversion/conversion-v3/nodes/process/compatibility-process-node.js +181 -0
  82. package/dist/conversion/conversion-v3/nodes/process/index.d.ts +10 -0
  83. package/dist/conversion/conversion-v3/nodes/process/index.js +10 -0
  84. package/dist/conversion/conversion-v3/nodes/process/passthrough-process-node.d.ts +59 -0
  85. package/dist/conversion/conversion-v3/nodes/process/passthrough-process-node.js +243 -0
  86. package/dist/conversion/conversion-v3/nodes/process/response-process-node.d.ts +17 -0
  87. package/dist/conversion/conversion-v3/nodes/process/response-process-node.js +213 -0
  88. package/dist/conversion/conversion-v3/nodes/process/tool-process-node.d.ts +26 -0
  89. package/dist/conversion/conversion-v3/nodes/process/tool-process-node.js +299 -0
  90. package/dist/conversion/conversion-v3/nodes/process/virtual-router-process-node.d.ts +40 -0
  91. package/dist/conversion/conversion-v3/nodes/process/virtual-router-process-node.js +430 -0
  92. package/dist/conversion/conversion-v3/nodes/response/anthropic-response-input-node.d.ts +12 -0
  93. package/dist/conversion/conversion-v3/nodes/response/anthropic-response-input-node.js +129 -0
  94. package/dist/conversion/conversion-v3/nodes/response/chat-to-responses-response-node.d.ts +15 -0
  95. package/dist/conversion/conversion-v3/nodes/response/chat-to-responses-response-node.js +57 -0
  96. package/dist/conversion/conversion-v3/nodes/response/index.d.ts +4 -0
  97. package/dist/conversion/conversion-v3/nodes/response/index.js +4 -0
  98. package/dist/conversion/conversion-v3/nodes/response/openai-response-input-node.d.ts +15 -0
  99. package/dist/conversion/conversion-v3/nodes/response/openai-response-input-node.js +87 -0
  100. package/dist/conversion/conversion-v3/nodes/response/response-utils.d.ts +1 -0
  101. package/dist/conversion/conversion-v3/nodes/response/response-utils.js +1 -0
  102. package/dist/conversion/conversion-v3/nodes/response/responses-response-input-node.d.ts +12 -0
  103. package/dist/conversion/conversion-v3/nodes/response/responses-response-input-node.js +67 -0
  104. package/dist/conversion/conversion-v3/nodes/sse/index.d.ts +3 -0
  105. package/dist/conversion/conversion-v3/nodes/sse/index.js +3 -0
  106. package/dist/conversion/conversion-v3/nodes/sse/sse-input-node.d.ts +27 -0
  107. package/dist/conversion/conversion-v3/nodes/sse/sse-input-node.js +165 -0
  108. package/dist/conversion/conversion-v3/nodes/sse/sse-output-node.d.ts +19 -0
  109. package/dist/conversion/conversion-v3/nodes/sse/sse-output-node.js +267 -0
  110. package/dist/conversion/conversion-v3/nodes/sse/sse-passthrough-node.d.ts +18 -0
  111. package/dist/conversion/conversion-v3/nodes/sse/sse-passthrough-node.js +48 -0
  112. package/dist/conversion/conversion-v3/pipelines/index.d.ts +6 -0
  113. package/dist/conversion/conversion-v3/pipelines/index.js +6 -0
  114. package/dist/conversion/conversion-v3/pipelines/super-pipeline.d.ts +112 -0
  115. package/dist/conversion/conversion-v3/pipelines/super-pipeline.js +566 -0
  116. package/dist/conversion/conversion-v3/response/provider-response-converter.d.ts +28 -0
  117. package/dist/conversion/conversion-v3/response/provider-response-converter.js +249 -0
  118. package/dist/conversion/conversion-v3/sse/index.d.ts +140 -0
  119. package/dist/conversion/conversion-v3/sse/index.js +115 -0
  120. package/dist/conversion/conversion-v3/sse/json-to-sse/anthropic-json-to-sse-converter.d.ts +11 -0
  121. package/dist/conversion/conversion-v3/sse/json-to-sse/anthropic-json-to-sse-converter.js +79 -0
  122. package/dist/conversion/conversion-v3/sse/json-to-sse/chat-json-to-sse-converter.d.ts +79 -0
  123. package/dist/conversion/conversion-v3/sse/json-to-sse/chat-json-to-sse-converter.js +296 -0
  124. package/dist/conversion/conversion-v3/sse/json-to-sse/event-generators/chat.d.ts +55 -0
  125. package/dist/conversion/conversion-v3/sse/json-to-sse/event-generators/chat.js +233 -0
  126. package/dist/conversion/conversion-v3/sse/json-to-sse/event-generators/responses.d.ts +99 -0
  127. package/dist/conversion/conversion-v3/sse/json-to-sse/event-generators/responses.js +599 -0
  128. package/dist/conversion/conversion-v3/sse/json-to-sse/index.d.ts +6 -0
  129. package/dist/conversion/conversion-v3/sse/json-to-sse/index.js +7 -0
  130. package/dist/conversion/conversion-v3/sse/json-to-sse/responses-json-to-sse-converter.d.ts +79 -0
  131. package/dist/conversion/conversion-v3/sse/json-to-sse/responses-json-to-sse-converter.js +322 -0
  132. package/dist/conversion/conversion-v3/sse/json-to-sse/sequencers/chat-sequencer.d.ts +37 -0
  133. package/dist/conversion/conversion-v3/sse/json-to-sse/sequencers/chat-sequencer.js +218 -0
  134. package/dist/conversion/conversion-v3/sse/json-to-sse/sequencers/responses-sequencer.d.ts +40 -0
  135. package/dist/conversion/conversion-v3/sse/json-to-sse/sequencers/responses-sequencer.js +263 -0
  136. package/dist/conversion/conversion-v3/sse/registry/sse-codec-registry.d.ts +32 -0
  137. package/dist/conversion/conversion-v3/sse/registry/sse-codec-registry.js +106 -0
  138. package/dist/conversion/conversion-v3/sse/shared/chat-serializer.d.ts +4 -0
  139. package/dist/conversion/conversion-v3/sse/shared/chat-serializer.js +40 -0
  140. package/dist/conversion/conversion-v3/sse/shared/constants.d.ts +272 -0
  141. package/dist/conversion/conversion-v3/sse/shared/constants.js +321 -0
  142. package/dist/conversion/conversion-v3/sse/shared/serializers/base-serializer.d.ts +158 -0
  143. package/dist/conversion/conversion-v3/sse/shared/serializers/base-serializer.js +210 -0
  144. package/dist/conversion/conversion-v3/sse/shared/serializers/chat-event-serializer.d.ts +82 -0
  145. package/dist/conversion/conversion-v3/sse/shared/serializers/chat-event-serializer.js +275 -0
  146. package/dist/conversion/conversion-v3/sse/shared/serializers/index.d.ts +39 -0
  147. package/dist/conversion/conversion-v3/sse/shared/serializers/index.js +54 -0
  148. package/dist/conversion/conversion-v3/sse/shared/serializers/responses-event-serializer.d.ts +123 -0
  149. package/dist/conversion/conversion-v3/sse/shared/serializers/responses-event-serializer.js +356 -0
  150. package/dist/conversion/conversion-v3/sse/shared/serializers/types.d.ts +51 -0
  151. package/dist/conversion/conversion-v3/sse/shared/serializers/types.js +4 -0
  152. package/dist/conversion/conversion-v3/sse/shared/utils.d.ts +254 -0
  153. package/dist/conversion/conversion-v3/sse/shared/utils.js +543 -0
  154. package/dist/conversion/conversion-v3/sse/shared/writer.d.ts +111 -0
  155. package/dist/conversion/conversion-v3/sse/shared/writer.js +268 -0
  156. package/dist/conversion/conversion-v3/sse/sse-to-json/anthropic-sse-to-json-converter.d.ts +13 -0
  157. package/dist/conversion/conversion-v3/sse/sse-to-json/anthropic-sse-to-json-converter.js +139 -0
  158. package/dist/conversion/conversion-v3/sse/sse-to-json/builders/response-builder.d.ts +165 -0
  159. package/dist/conversion/conversion-v3/sse/sse-to-json/builders/response-builder.js +776 -0
  160. package/dist/conversion/conversion-v3/sse/sse-to-json/chat-sse-to-json-converter.d.ts +106 -0
  161. package/dist/conversion/conversion-v3/sse/sse-to-json/chat-sse-to-json-converter.js +540 -0
  162. package/dist/conversion/conversion-v3/sse/sse-to-json/index.d.ts +6 -0
  163. package/dist/conversion/conversion-v3/sse/sse-to-json/index.js +7 -0
  164. package/dist/conversion/conversion-v3/sse/sse-to-json/parsers/sse-parser.d.ts +73 -0
  165. package/dist/conversion/conversion-v3/sse/sse-to-json/parsers/sse-parser.js +332 -0
  166. package/dist/conversion/conversion-v3/sse/sse-to-json/responses-sse-to-json-converter.d.ts +59 -0
  167. package/dist/conversion/conversion-v3/sse/sse-to-json/responses-sse-to-json-converter.js +270 -0
  168. package/dist/conversion/conversion-v3/sse/types/anthropic-types.d.ts +87 -0
  169. package/dist/conversion/conversion-v3/sse/types/anthropic-types.js +5 -0
  170. package/dist/conversion/conversion-v3/sse/types/chat-types.d.ts +308 -0
  171. package/dist/conversion/conversion-v3/sse/types/chat-types.js +32 -0
  172. package/dist/conversion/conversion-v3/sse/types/conversion-context.d.ts +211 -0
  173. package/dist/conversion/conversion-v3/sse/types/conversion-context.js +20 -0
  174. package/dist/conversion/conversion-v3/sse/types/core-interfaces.d.ts +90 -0
  175. package/dist/conversion/conversion-v3/sse/types/core-interfaces.js +5 -0
  176. package/dist/conversion/conversion-v3/sse/types/index.d.ts +14 -0
  177. package/dist/conversion/conversion-v3/sse/types/index.js +7 -0
  178. package/dist/conversion/conversion-v3/sse/types/responses-types.d.ts +328 -0
  179. package/dist/conversion/conversion-v3/sse/types/responses-types.js +38 -0
  180. package/dist/conversion/conversion-v3/sse/types/sse-events.d.ts +180 -0
  181. package/dist/conversion/conversion-v3/sse/types/sse-events.js +150 -0
  182. package/dist/conversion/conversion-v3/sse/types/stream-state.d.ts +204 -0
  183. package/dist/conversion/conversion-v3/sse/types/stream-state.js +44 -0
  184. package/dist/conversion/conversion-v3/sse/types/utility-types.d.ts +230 -0
  185. package/dist/conversion/conversion-v3/sse/types/utility-types.js +49 -0
  186. package/dist/conversion/conversion-v3/standards/context-adapter.d.ts +146 -0
  187. package/dist/conversion/conversion-v3/standards/context-adapter.js +438 -0
  188. package/dist/conversion/conversion-v3/standards/errors.d.ts +38 -0
  189. package/dist/conversion/conversion-v3/standards/errors.js +27 -0
  190. package/dist/conversion/conversion-v3/standards/index.d.ts +15 -0
  191. package/dist/conversion/conversion-v3/standards/index.js +11 -0
  192. package/dist/conversion/conversion-v3/standards/node-capabilities.d.ts +123 -0
  193. package/dist/conversion/conversion-v3/standards/node-capabilities.js +330 -0
  194. package/dist/conversion/conversion-v3/standards/pipeline-context.d.ts +237 -0
  195. package/dist/conversion/conversion-v3/standards/pipeline-context.js +84 -0
  196. package/dist/conversion/conversion-v3/standards/pipeline-node.d.ts +196 -0
  197. package/dist/conversion/conversion-v3/standards/pipeline-node.js +316 -0
  198. package/dist/conversion/conversion-v3/standards/snapshot-handles.d.ts +24 -0
  199. package/dist/conversion/conversion-v3/standards/snapshot-handles.js +49 -0
  200. package/dist/conversion/conversion-v3/types/config-types.d.ts +242 -0
  201. package/dist/conversion/conversion-v3/types/config-types.js +13 -0
  202. package/dist/conversion/conversion-v3/types/index.d.ts +8 -0
  203. package/dist/conversion/conversion-v3/types/index.js +11 -0
  204. package/dist/conversion/conversion-v3/types/node-types.d.ts +211 -0
  205. package/dist/conversion/conversion-v3/types/node-types.js +20 -0
  206. package/dist/conversion/conversion-v3/types/pipeline-types.d.ts +246 -0
  207. package/dist/conversion/conversion-v3/types/pipeline-types.js +26 -0
  208. package/dist/conversion/conversion-v3/types/request-types.d.ts +293 -0
  209. package/dist/conversion/conversion-v3/types/request-types.js +26 -0
  210. package/dist/conversion/conversion-v3/utils/provider-payload-sanitizer.d.ts +10 -0
  211. package/dist/conversion/conversion-v3/utils/provider-payload-sanitizer.js +103 -0
  212. package/dist/conversion/conversion-v3/validations/index.d.ts +8 -0
  213. package/dist/conversion/conversion-v3/validations/index.js +7 -0
  214. package/dist/conversion/conversion-v3/validations/node-graph-validator.d.ts +116 -0
  215. package/dist/conversion/conversion-v3/validations/node-graph-validator.js +505 -0
  216. package/dist/conversion/conversion-v3/validations/tool-governance-enforcer.d.ts +139 -0
  217. package/dist/conversion/conversion-v3/validations/tool-governance-enforcer.js +338 -0
  218. package/dist/conversion/hub/config/types.d.ts +26 -0
  219. package/dist/conversion/hub/config/types.js +1 -0
  220. package/dist/conversion/hub/core/detour-registry.d.ts +9 -0
  221. package/dist/conversion/hub/core/detour-registry.js +23 -0
  222. package/dist/conversion/hub/core/hub-context.d.ts +21 -0
  223. package/dist/conversion/hub/core/hub-context.js +1 -0
  224. package/dist/conversion/hub/core/index.d.ts +3 -0
  225. package/dist/conversion/hub/core/index.js +3 -0
  226. package/dist/conversion/hub/core/stage-driver.d.ts +30 -0
  227. package/dist/conversion/hub/core/stage-driver.js +31 -0
  228. package/dist/conversion/hub/format-adapters/anthropic-format-adapter.d.ts +16 -0
  229. package/dist/conversion/hub/format-adapters/anthropic-format-adapter.js +23 -0
  230. package/dist/conversion/hub/format-adapters/chat-format-adapter.d.ts +17 -0
  231. package/dist/conversion/hub/format-adapters/chat-format-adapter.js +23 -0
  232. package/dist/conversion/hub/format-adapters/gemini-format-adapter.d.ts +16 -0
  233. package/dist/conversion/hub/format-adapters/gemini-format-adapter.js +23 -0
  234. package/dist/conversion/hub/format-adapters/index.d.ts +21 -0
  235. package/dist/conversion/hub/format-adapters/index.js +4 -0
  236. package/dist/conversion/hub/format-adapters/responses-format-adapter.d.ts +17 -0
  237. package/dist/conversion/hub/format-adapters/responses-format-adapter.js +23 -0
  238. package/dist/conversion/hub/hub-feature.d.ts +1 -0
  239. package/dist/conversion/hub/hub-feature.js +25 -0
  240. package/dist/conversion/hub/node-support.d.ts +19 -0
  241. package/dist/conversion/hub/node-support.js +115 -0
  242. package/dist/conversion/hub/pipeline/hub-pipeline.d.ts +68 -0
  243. package/dist/conversion/hub/pipeline/hub-pipeline.js +421 -0
  244. package/dist/conversion/hub/pipelines/inbound.d.ts +22 -0
  245. package/dist/conversion/hub/pipelines/inbound.js +64 -0
  246. package/dist/conversion/hub/pipelines/outbound.d.ts +22 -0
  247. package/dist/conversion/hub/pipelines/outbound.js +57 -0
  248. package/dist/conversion/hub/process/chat-process.d.ts +13 -0
  249. package/dist/conversion/hub/process/chat-process.js +50 -0
  250. package/dist/conversion/hub/registry.d.ts +28 -0
  251. package/dist/conversion/hub/registry.js +98 -0
  252. package/dist/conversion/hub/response/chat-response-utils.d.ts +6 -0
  253. package/dist/conversion/hub/response/chat-response-utils.js +89 -0
  254. package/dist/conversion/hub/response/provider-response.d.ts +20 -0
  255. package/dist/conversion/hub/response/provider-response.js +196 -0
  256. package/dist/conversion/hub/response/response-mappers.d.ts +19 -0
  257. package/dist/conversion/hub/response/response-mappers.js +23 -0
  258. package/dist/conversion/hub/response/response-runtime.d.ts +3 -0
  259. package/dist/conversion/hub/response/response-runtime.js +206 -0
  260. package/dist/conversion/hub/semantic-mappers/anthropic-mapper.d.ts +7 -0
  261. package/dist/conversion/hub/semantic-mappers/anthropic-mapper.js +308 -0
  262. package/dist/conversion/hub/semantic-mappers/chat-mapper.d.ts +7 -0
  263. package/dist/conversion/hub/semantic-mappers/chat-mapper.js +304 -0
  264. package/dist/conversion/hub/semantic-mappers/gemini-mapper.d.ts +7 -0
  265. package/dist/conversion/hub/semantic-mappers/gemini-mapper.js +477 -0
  266. package/dist/conversion/hub/semantic-mappers/index.d.ts +4 -0
  267. package/dist/conversion/hub/semantic-mappers/index.js +4 -0
  268. package/dist/conversion/hub/semantic-mappers/responses-mapper.d.ts +21 -0
  269. package/dist/conversion/hub/semantic-mappers/responses-mapper.js +379 -0
  270. package/dist/conversion/hub/snapshot-recorder.d.ts +12 -0
  271. package/dist/conversion/hub/snapshot-recorder.js +69 -0
  272. package/dist/conversion/hub/standardized-bridge.d.ts +12 -0
  273. package/dist/conversion/hub/standardized-bridge.js +248 -0
  274. package/dist/conversion/hub/types/chat-envelope.d.ts +67 -0
  275. package/dist/conversion/hub/types/chat-envelope.js +1 -0
  276. package/dist/conversion/hub/types/chat-schema.d.ts +112 -0
  277. package/dist/conversion/hub/types/chat-schema.js +1 -0
  278. package/dist/conversion/hub/types/errors.d.ts +5 -0
  279. package/dist/conversion/hub/types/errors.js +13 -0
  280. package/dist/conversion/hub/types/format-envelope.d.ts +7 -0
  281. package/dist/conversion/hub/types/format-envelope.js +1 -0
  282. package/dist/conversion/hub/types/index.d.ts +6 -0
  283. package/dist/conversion/hub/types/index.js +6 -0
  284. package/dist/conversion/hub/types/json.d.ts +9 -0
  285. package/dist/conversion/hub/types/json.js +9 -0
  286. package/dist/conversion/hub/types/node.d.ts +31 -0
  287. package/dist/conversion/hub/types/node.js +1 -0
  288. package/dist/conversion/hub/types/standardized.d.ts +94 -0
  289. package/dist/conversion/hub/types/standardized.js +1 -0
  290. package/dist/conversion/index.d.ts +28 -0
  291. package/dist/conversion/index.js +28 -0
  292. package/dist/conversion/responses/responses-openai-bridge.d.ts +95 -0
  293. package/dist/conversion/responses/responses-openai-bridge.js +1330 -0
  294. package/dist/conversion/schema-validator.d.ts +7 -0
  295. package/dist/conversion/schema-validator.js +67 -0
  296. package/dist/conversion/shared/args-mapping.d.ts +18 -0
  297. package/dist/conversion/shared/args-mapping.js +213 -0
  298. package/dist/conversion/shared/chat-request-filters.d.ts +9 -0
  299. package/dist/conversion/shared/chat-request-filters.js +74 -0
  300. package/dist/conversion/shared/jsonish.d.ts +3 -0
  301. package/dist/conversion/shared/jsonish.js +177 -0
  302. package/dist/conversion/shared/mcp-injection.d.ts +2 -0
  303. package/dist/conversion/shared/mcp-injection.js +89 -0
  304. package/dist/conversion/shared/media.d.ts +1 -0
  305. package/dist/conversion/shared/media.js +9 -0
  306. package/dist/conversion/shared/openai-finalizer.d.ts +9 -0
  307. package/dist/conversion/shared/openai-finalizer.js +104 -0
  308. package/dist/conversion/shared/openai-message-normalize.d.ts +1 -0
  309. package/dist/conversion/shared/openai-message-normalize.js +442 -0
  310. package/dist/conversion/shared/payload-budget.d.ts +13 -0
  311. package/dist/conversion/shared/payload-budget.js +248 -0
  312. package/dist/conversion/shared/reasoning-mapping.d.ts +5 -0
  313. package/dist/conversion/shared/reasoning-mapping.js +8 -0
  314. package/dist/conversion/shared/responses-conversation-store.d.ts +41 -0
  315. package/dist/conversion/shared/responses-conversation-store.js +285 -0
  316. package/dist/conversion/shared/responses-id-utils.d.ts +7 -0
  317. package/dist/conversion/shared/responses-id-utils.js +29 -0
  318. package/dist/conversion/shared/responses-instructions.d.ts +1 -0
  319. package/dist/conversion/shared/responses-instructions.js +113 -0
  320. package/dist/conversion/shared/responses-metadata.d.ts +1 -0
  321. package/dist/conversion/shared/responses-metadata.js +1 -0
  322. package/dist/conversion/shared/responses-request-adapter.d.ts +66 -0
  323. package/dist/conversion/shared/responses-request-adapter.js +461 -0
  324. package/dist/conversion/shared/snapshot-hooks.d.ts +12 -0
  325. package/dist/conversion/shared/snapshot-hooks.js +7 -0
  326. package/dist/conversion/shared/streaming-text-extractor.d.ts +26 -0
  327. package/dist/conversion/shared/streaming-text-extractor.js +145 -0
  328. package/dist/conversion/shared/text-markup-normalizer.d.ts +9 -0
  329. package/dist/conversion/shared/text-markup-normalizer.js +319 -0
  330. package/dist/conversion/shared/tool-canonicalizer.d.ts +2 -0
  331. package/dist/conversion/shared/tool-canonicalizer.js +50 -0
  332. package/dist/conversion/shared/tool-filter-pipeline.d.ts +17 -0
  333. package/dist/conversion/shared/tool-filter-pipeline.js +79 -0
  334. package/dist/conversion/shared/tool-governor.d.ts +27 -0
  335. package/dist/conversion/shared/tool-governor.js +269 -0
  336. package/dist/conversion/shared/tool-harvester.d.ts +31 -0
  337. package/dist/conversion/shared/tool-harvester.js +321 -0
  338. package/dist/conversion/shared/tool-mapping.d.ts +10 -0
  339. package/dist/conversion/shared/tool-mapping.js +10 -0
  340. package/dist/conversion/shared/tooling.d.ts +26 -0
  341. package/dist/conversion/shared/tooling.js +143 -0
  342. package/dist/conversion/types.d.ts +33 -0
  343. package/dist/conversion/types.js +1 -0
  344. package/dist/core/index.d.ts +6 -0
  345. package/dist/core/index.js +9 -0
  346. package/dist/core/llmswitch-engine-v2.d.ts +132 -0
  347. package/dist/core/llmswitch-engine-v2.js +649 -0
  348. package/dist/core/llmswitch-factory-v2.d.ts +123 -0
  349. package/dist/core/llmswitch-factory-v2.js +521 -0
  350. package/dist/endpoints/base-endpoint-handler.d.ts +128 -0
  351. package/dist/endpoints/base-endpoint-handler.js +545 -0
  352. package/dist/endpoints/chat-endpoint-handler.d.ts +115 -0
  353. package/dist/endpoints/chat-endpoint-handler.js +218 -0
  354. package/dist/endpoints/endpoint-router.d.ts +127 -0
  355. package/dist/endpoints/endpoint-router.js +438 -0
  356. package/dist/endpoints/index.d.ts +13 -0
  357. package/dist/endpoints/index.js +11 -0
  358. package/dist/endpoints/messages-endpoint-handler.d.ts +171 -0
  359. package/dist/endpoints/messages-endpoint-handler.js +238 -0
  360. package/dist/endpoints/responses-endpoint-handler.d.ts +147 -0
  361. package/dist/endpoints/responses-endpoint-handler.js +233 -0
  362. package/dist/filters/builtin/add-fields-filter.d.ts +8 -0
  363. package/dist/filters/builtin/add-fields-filter.js +16 -0
  364. package/dist/filters/builtin/blacklist-filter.d.ts +8 -0
  365. package/dist/filters/builtin/blacklist-filter.js +19 -0
  366. package/dist/filters/builtin/whitelist-filter.d.ts +8 -0
  367. package/dist/filters/builtin/whitelist-filter.js +19 -0
  368. package/dist/filters/engine.d.ts +16 -0
  369. package/dist/filters/engine.js +167 -0
  370. package/dist/filters/index.d.ts +19 -0
  371. package/dist/filters/index.js +24 -0
  372. package/dist/filters/special/request-streaming-to-nonstreaming.d.ts +12 -0
  373. package/dist/filters/special/request-streaming-to-nonstreaming.js +27 -0
  374. package/dist/filters/special/request-tool-choice-policy.d.ts +11 -0
  375. package/dist/filters/special/request-tool-choice-policy.js +27 -0
  376. package/dist/filters/special/request-tool-list-filter.d.ts +11 -0
  377. package/dist/filters/special/request-tool-list-filter.js +167 -0
  378. package/dist/filters/special/request-toolcalls-stringify.d.ts +10 -0
  379. package/dist/filters/special/request-toolcalls-stringify.js +44 -0
  380. package/dist/filters/special/request-tools-normalize.d.ts +12 -0
  381. package/dist/filters/special/request-tools-normalize.js +140 -0
  382. package/dist/filters/special/response-finish-invariants.d.ts +11 -0
  383. package/dist/filters/special/response-finish-invariants.js +30 -0
  384. package/dist/filters/special/response-openai-to-responses-bridge.d.ts +13 -0
  385. package/dist/filters/special/response-openai-to-responses-bridge.js +24 -0
  386. package/dist/filters/special/response-tool-arguments-blacklist.d.ts +12 -0
  387. package/dist/filters/special/response-tool-arguments-blacklist.js +63 -0
  388. package/dist/filters/special/response-tool-arguments-schema-converge.d.ts +13 -0
  389. package/dist/filters/special/response-tool-arguments-schema-converge.js +63 -0
  390. package/dist/filters/special/response-tool-arguments-stringify.d.ts +9 -0
  391. package/dist/filters/special/response-tool-arguments-stringify.js +134 -0
  392. package/dist/filters/special/response-tool-arguments-toon-decode.d.ts +10 -0
  393. package/dist/filters/special/response-tool-arguments-toon-decode.js +94 -0
  394. package/dist/filters/special/response-tool-arguments-whitelist.d.ts +11 -0
  395. package/dist/filters/special/response-tool-arguments-whitelist.js +56 -0
  396. package/dist/filters/special/response-tool-text-canonicalize.d.ts +10 -0
  397. package/dist/filters/special/response-tool-text-canonicalize.js +20 -0
  398. package/dist/filters/special/tool-filter-hooks.d.ts +19 -0
  399. package/dist/filters/special/tool-filter-hooks.js +341 -0
  400. package/dist/filters/special/tool-post-constraints.d.ts +31 -0
  401. package/dist/filters/special/tool-post-constraints.js +120 -0
  402. package/dist/filters/types.d.ts +68 -0
  403. package/dist/filters/types.js +3 -0
  404. package/dist/filters/utils/fieldmap-loader.d.ts +2 -0
  405. package/dist/filters/utils/fieldmap-loader.js +16 -0
  406. package/dist/filters/utils/snapshot-writer.d.ts +10 -0
  407. package/dist/filters/utils/snapshot-writer.js +47 -0
  408. package/dist/guidance/index.d.ts +3 -0
  409. package/dist/guidance/index.js +228 -0
  410. package/dist/hooks/hooks-integration.d.ts +161 -0
  411. package/dist/hooks/hooks-integration.js +519 -0
  412. package/dist/hooks/index.d.ts +10 -0
  413. package/dist/hooks/index.js +13 -0
  414. package/dist/html-to-markdown.d.ts +5 -0
  415. package/dist/html-to-markdown.js +66 -0
  416. package/dist/http/sse-response.d.ts +22 -0
  417. package/dist/http/sse-response.js +103 -0
  418. package/dist/index.d.ts +10 -0
  419. package/dist/index.js +10 -0
  420. package/dist/router/virtual-router/bootstrap.d.ts +6 -0
  421. package/dist/router/virtual-router/bootstrap.js +620 -0
  422. package/dist/router/virtual-router/classifier.d.ts +10 -0
  423. package/dist/router/virtual-router/classifier.js +99 -0
  424. package/dist/router/virtual-router/engine.d.ts +35 -0
  425. package/dist/router/virtual-router/engine.js +260 -0
  426. package/dist/router/virtual-router/error-center.d.ts +10 -0
  427. package/dist/router/virtual-router/error-center.js +39 -0
  428. package/dist/router/virtual-router/features.d.ts +3 -0
  429. package/dist/router/virtual-router/features.js +162 -0
  430. package/dist/router/virtual-router/health-manager.d.ts +18 -0
  431. package/dist/router/virtual-router/health-manager.js +98 -0
  432. package/dist/router/virtual-router/load-balancer.d.ts +18 -0
  433. package/dist/router/virtual-router/load-balancer.js +67 -0
  434. package/dist/router/virtual-router/provider-registry.d.ts +11 -0
  435. package/dist/router/virtual-router/provider-registry.js +74 -0
  436. package/dist/router/virtual-router/types.d.ts +206 -0
  437. package/dist/router/virtual-router/types.js +31 -0
  438. package/dist/sse/index.d.ts +140 -0
  439. package/dist/sse/index.js +115 -0
  440. package/dist/sse/json-to-sse/anthropic-json-to-sse-converter.d.ts +11 -0
  441. package/dist/sse/json-to-sse/anthropic-json-to-sse-converter.js +79 -0
  442. package/dist/sse/json-to-sse/chat-json-to-sse-converter.d.ts +79 -0
  443. package/dist/sse/json-to-sse/chat-json-to-sse-converter.js +296 -0
  444. package/dist/sse/json-to-sse/event-generators/chat.d.ts +55 -0
  445. package/dist/sse/json-to-sse/event-generators/chat.js +233 -0
  446. package/dist/sse/json-to-sse/event-generators/responses.d.ts +99 -0
  447. package/dist/sse/json-to-sse/event-generators/responses.js +599 -0
  448. package/dist/sse/json-to-sse/index.d.ts +6 -0
  449. package/dist/sse/json-to-sse/index.js +7 -0
  450. package/dist/sse/json-to-sse/responses-json-to-sse-converter.d.ts +79 -0
  451. package/dist/sse/json-to-sse/responses-json-to-sse-converter.js +322 -0
  452. package/dist/sse/json-to-sse/sequencers/chat-sequencer.d.ts +37 -0
  453. package/dist/sse/json-to-sse/sequencers/chat-sequencer.js +218 -0
  454. package/dist/sse/json-to-sse/sequencers/responses-sequencer.d.ts +40 -0
  455. package/dist/sse/json-to-sse/sequencers/responses-sequencer.js +263 -0
  456. package/dist/sse/registry/sse-codec-registry.d.ts +32 -0
  457. package/dist/sse/registry/sse-codec-registry.js +106 -0
  458. package/dist/sse/shared/chat-serializer.d.ts +4 -0
  459. package/dist/sse/shared/chat-serializer.js +40 -0
  460. package/dist/sse/shared/constants.d.ts +272 -0
  461. package/dist/sse/shared/constants.js +321 -0
  462. package/dist/sse/shared/serializers/base-serializer.d.ts +158 -0
  463. package/dist/sse/shared/serializers/base-serializer.js +210 -0
  464. package/dist/sse/shared/serializers/chat-event-serializer.d.ts +82 -0
  465. package/dist/sse/shared/serializers/chat-event-serializer.js +275 -0
  466. package/dist/sse/shared/serializers/index.d.ts +39 -0
  467. package/dist/sse/shared/serializers/index.js +54 -0
  468. package/dist/sse/shared/serializers/responses-event-serializer.d.ts +123 -0
  469. package/dist/sse/shared/serializers/responses-event-serializer.js +356 -0
  470. package/dist/sse/shared/serializers/types.d.ts +51 -0
  471. package/dist/sse/shared/serializers/types.js +4 -0
  472. package/dist/sse/shared/utils.d.ts +254 -0
  473. package/dist/sse/shared/utils.js +543 -0
  474. package/dist/sse/shared/writer.d.ts +111 -0
  475. package/dist/sse/shared/writer.js +268 -0
  476. package/dist/sse/sse-to-json/anthropic-sse-to-json-converter.d.ts +13 -0
  477. package/dist/sse/sse-to-json/anthropic-sse-to-json-converter.js +139 -0
  478. package/dist/sse/sse-to-json/builders/response-builder.d.ts +165 -0
  479. package/dist/sse/sse-to-json/builders/response-builder.js +776 -0
  480. package/dist/sse/sse-to-json/chat-sse-to-json-converter.d.ts +106 -0
  481. package/dist/sse/sse-to-json/chat-sse-to-json-converter.js +540 -0
  482. package/dist/sse/sse-to-json/index.d.ts +6 -0
  483. package/dist/sse/sse-to-json/index.js +7 -0
  484. package/dist/sse/sse-to-json/parsers/sse-parser.d.ts +73 -0
  485. package/dist/sse/sse-to-json/parsers/sse-parser.js +340 -0
  486. package/dist/sse/sse-to-json/responses-sse-to-json-converter.d.ts +59 -0
  487. package/dist/sse/sse-to-json/responses-sse-to-json-converter.js +270 -0
  488. package/dist/sse/types/anthropic-types.d.ts +87 -0
  489. package/dist/sse/types/anthropic-types.js +5 -0
  490. package/dist/sse/types/chat-types.d.ts +308 -0
  491. package/dist/sse/types/chat-types.js +32 -0
  492. package/dist/sse/types/conversion-context.d.ts +211 -0
  493. package/dist/sse/types/conversion-context.js +20 -0
  494. package/dist/sse/types/core-interfaces.d.ts +90 -0
  495. package/dist/sse/types/core-interfaces.js +5 -0
  496. package/dist/sse/types/index.d.ts +14 -0
  497. package/dist/sse/types/index.js +7 -0
  498. package/dist/sse/types/responses-types.d.ts +328 -0
  499. package/dist/sse/types/responses-types.js +38 -0
  500. package/dist/sse/types/sse-events.d.ts +180 -0
  501. package/dist/sse/types/sse-events.js +150 -0
  502. package/dist/sse/types/stream-state.d.ts +204 -0
  503. package/dist/sse/types/stream-state.js +44 -0
  504. package/dist/sse/types/utility-types.d.ts +230 -0
  505. package/dist/sse/types/utility-types.js +49 -0
  506. package/dist/tools/proxy/anthropic-tool-proxy.d.ts +19 -0
  507. package/dist/tools/proxy/anthropic-tool-proxy.js +57 -0
  508. package/dist/tools/proxy/executors/web-fetch.d.ts +6 -0
  509. package/dist/tools/proxy/executors/web-fetch.js +39 -0
  510. package/dist/tools/proxy/registry.d.ts +8 -0
  511. package/dist/tools/proxy/registry.js +14 -0
  512. package/dist/tools/proxy/types.d.ts +29 -0
  513. package/dist/tools/proxy/types.js +1 -0
  514. package/dist/tools/tool-registry.d.ts +8 -0
  515. package/dist/tools/tool-registry.js +154 -0
  516. package/dist/tools/web-fetch-html.d.ts +15 -0
  517. package/dist/tools/web-fetch-html.js +83 -0
  518. package/dist/utils/conversion-adapter.d.ts +65 -0
  519. package/dist/utils/conversion-adapter.js +183 -0
  520. package/dist/utils/error-factory.d.ts +88 -0
  521. package/dist/utils/error-factory.js +138 -0
  522. package/dist/utils/error-utils.d.ts +334 -0
  523. package/dist/utils/error-utils.js +782 -0
  524. package/dist/utils/index.d.ts +8 -0
  525. package/dist/utils/index.js +13 -0
  526. package/dist/utils/performance-utils.d.ts +205 -0
  527. package/dist/utils/performance-utils.js +440 -0
  528. package/dist/utils/profile-mapper.d.ts +32 -0
  529. package/dist/utils/profile-mapper.js +269 -0
  530. package/dist/utils/request-processor.d.ts +52 -0
  531. package/dist/utils/request-processor.js +210 -0
  532. package/dist/utils/request-utils.d.ts +117 -0
  533. package/dist/utils/request-utils.js +333 -0
  534. package/dist/utils/response-utils.d.ts +127 -0
  535. package/dist/utils/response-utils.js +516 -0
  536. package/dist/utils/token-counter.d.ts +89 -0
  537. package/dist/utils/token-counter.js +541 -0
  538. package/package.json +65 -0
@@ -0,0 +1,620 @@
1
+ import { VirtualRouterError, VirtualRouterErrorCode } from './types.js';
2
+ const DEFAULT_CLASSIFIER = {
3
+ longContextThresholdTokens: 60000,
4
+ thinkingKeywords: ['think step', 'analysis', 'reasoning', '仔细分析', '深度思考'],
5
+ codingKeywords: ['apply_patch', 'write_file', 'create_file', 'shell', '修改文件', '写入文件'],
6
+ backgroundKeywords: ['background', 'context dump', '上下文'],
7
+ visionKeywords: ['vision', 'image', 'picture', 'photo']
8
+ };
9
+ const DEFAULT_LOAD_BALANCING = { strategy: 'round-robin' };
10
+ const DEFAULT_HEALTH = { failureThreshold: 3, cooldownMs: 30_000, fatalCooldownMs: 300_000 };
11
+ /**
12
+ * 将用户提供的 Virtual Router 配置(或包含 virtualrouter 字段的整体配置)
13
+ * 规范化为 VirtualRouterConfig,供 HubPipeline / VirtualRouterEngine 直接使用。
14
+ */
15
+ export function bootstrapVirtualRouterConfig(input) {
16
+ const section = extractVirtualRouterSection(input);
17
+ const providersSource = asRecord(section.providers);
18
+ if (!Object.keys(providersSource).length) {
19
+ throw new VirtualRouterError('Virtual Router requires at least one provider in configuration', VirtualRouterErrorCode.CONFIG_ERROR);
20
+ }
21
+ const routingSource = normalizeRouting(section.routing);
22
+ if (!Object.keys(routingSource).length) {
23
+ throw new VirtualRouterError('Virtual Router routing table cannot be empty', VirtualRouterErrorCode.CONFIG_ERROR);
24
+ }
25
+ const { runtimeEntries, aliasIndex } = buildProviderRuntimeEntries(providersSource);
26
+ const { routing, targetKeys } = expandRoutingTable(routingSource, aliasIndex);
27
+ if (!routing.default || routing.default.length === 0) {
28
+ throw new VirtualRouterError('Virtual Router default route must contain at least one provider target', VirtualRouterErrorCode.CONFIG_ERROR);
29
+ }
30
+ const { profiles: providerProfiles, targetRuntime } = buildProviderProfiles(targetKeys, runtimeEntries);
31
+ const classifier = normalizeClassifier(section.classifier);
32
+ const loadBalancing = section.loadBalancing ?? DEFAULT_LOAD_BALANCING;
33
+ const health = section.health ?? DEFAULT_HEALTH;
34
+ const config = {
35
+ routing,
36
+ providers: providerProfiles,
37
+ classifier,
38
+ loadBalancing,
39
+ health
40
+ };
41
+ return {
42
+ config,
43
+ runtime: runtimeEntries,
44
+ targetRuntime,
45
+ providers: providerProfiles,
46
+ routing
47
+ };
48
+ }
49
+ function extractVirtualRouterSection(input) {
50
+ const root = asRecord(input);
51
+ const section = root.virtualrouter && typeof root.virtualrouter === 'object'
52
+ ? asRecord(root.virtualrouter)
53
+ : root;
54
+ const providers = asRecord(section.providers ?? root.providers);
55
+ const routing = asRecord(section.routing ?? root.routing);
56
+ const classifier = (section.classifier ?? root.classifier);
57
+ const loadBalancing = normalizeLoadBalancing(section.loadBalancing ?? root.loadBalancing);
58
+ const health = normalizeHealth(section.health ?? root.health);
59
+ return { providers, routing, classifier, loadBalancing, health };
60
+ }
61
+ function buildProviderRuntimeEntries(providers) {
62
+ const runtimeEntries = {};
63
+ const aliasIndex = new Map();
64
+ for (const [providerId, providerRaw] of Object.entries(providers)) {
65
+ const normalizedProvider = normalizeProvider(providerId, providerRaw);
66
+ const authEntries = extractProviderAuthEntries(providerId, providerRaw);
67
+ if (!authEntries.length) {
68
+ throw new VirtualRouterError(`Provider ${providerId} requires at least one auth entry`, VirtualRouterErrorCode.CONFIG_ERROR);
69
+ }
70
+ aliasIndex.set(providerId, authEntries.map((entry) => entry.keyAlias));
71
+ for (const entry of authEntries) {
72
+ const runtimeKey = buildRuntimeKey(providerId, entry.keyAlias);
73
+ const runtimeAuth = {
74
+ type: entry.auth.type,
75
+ rawType: entry.auth.rawType,
76
+ oauthProviderId: entry.auth.oauthProviderId,
77
+ secretRef: entry.auth.secretRef,
78
+ value: entry.auth.value,
79
+ tokenFile: entry.auth.tokenFile,
80
+ tokenUrl: entry.auth.tokenUrl,
81
+ deviceCodeUrl: entry.auth.deviceCodeUrl,
82
+ clientId: entry.auth.clientId,
83
+ clientSecret: entry.auth.clientSecret,
84
+ scopes: entry.auth.scopes && entry.auth.scopes.length ? [...entry.auth.scopes] : undefined,
85
+ authorizationUrl: entry.auth.authorizationUrl,
86
+ userInfoUrl: entry.auth.userInfoUrl,
87
+ refreshUrl: entry.auth.refreshUrl
88
+ };
89
+ if (runtimeAuth.type === 'apiKey' && !runtimeAuth.secretRef) {
90
+ runtimeAuth.secretRef = `${providerId}.${entry.keyAlias}`;
91
+ }
92
+ runtimeEntries[runtimeKey] = {
93
+ runtimeKey,
94
+ providerId,
95
+ keyAlias: entry.keyAlias,
96
+ providerType: normalizedProvider.providerType,
97
+ endpoint: normalizedProvider.endpoint,
98
+ headers: normalizedProvider.headers,
99
+ auth: runtimeAuth,
100
+ outboundProfile: normalizedProvider.outboundProfile,
101
+ compatibilityProfile: normalizedProvider.compatibilityProfile,
102
+ processMode: normalizedProvider.processMode
103
+ };
104
+ }
105
+ }
106
+ return { runtimeEntries, aliasIndex };
107
+ }
108
+ function expandRoutingTable(routingSource, aliasIndex) {
109
+ const routing = {};
110
+ const targetKeys = new Set();
111
+ for (const [routeName, entries] of Object.entries(routingSource)) {
112
+ const expanded = [];
113
+ for (const entry of entries) {
114
+ const parsed = parseRouteEntry(entry, aliasIndex);
115
+ if (!parsed) {
116
+ continue;
117
+ }
118
+ if (!aliasIndex.has(parsed.providerId)) {
119
+ throw new VirtualRouterError(`Route "${routeName}" references unknown provider "${parsed.providerId}"`, VirtualRouterErrorCode.CONFIG_ERROR);
120
+ }
121
+ const aliases = parsed.keyAlias ? [parsed.keyAlias] : aliasIndex.get(parsed.providerId);
122
+ if (!aliases.length) {
123
+ throw new VirtualRouterError(`Provider ${parsed.providerId} has no auth aliases but is referenced in routing`, VirtualRouterErrorCode.CONFIG_ERROR);
124
+ }
125
+ for (const alias of aliases) {
126
+ const runtimeKey = buildRuntimeKey(parsed.providerId, alias);
127
+ const targetKey = `${runtimeKey}.${parsed.modelId}`;
128
+ pushUnique(expanded, targetKey);
129
+ targetKeys.add(targetKey);
130
+ }
131
+ }
132
+ routing[routeName] = expanded;
133
+ }
134
+ return { routing, targetKeys };
135
+ }
136
+ function buildProviderProfiles(targetKeys, runtimeEntries) {
137
+ const profiles = {};
138
+ const targetRuntime = {};
139
+ for (const targetKey of targetKeys) {
140
+ const parsed = parseTargetKey(targetKey);
141
+ if (!parsed)
142
+ continue;
143
+ const runtimeKey = buildRuntimeKey(parsed.providerId, parsed.keyAlias);
144
+ const runtime = runtimeEntries[runtimeKey];
145
+ if (!runtime) {
146
+ throw new VirtualRouterError(`Routing target ${targetKey} references unknown runtime key ${runtimeKey}`, VirtualRouterErrorCode.CONFIG_ERROR);
147
+ }
148
+ profiles[targetKey] = {
149
+ providerKey: targetKey,
150
+ providerType: runtime.providerType,
151
+ endpoint: runtime.endpoint,
152
+ auth: { ...runtime.auth },
153
+ outboundProfile: runtime.outboundProfile,
154
+ compatibilityProfile: runtime.compatibilityProfile,
155
+ runtimeKey,
156
+ modelId: parsed.modelId,
157
+ processMode: runtime.processMode || 'chat'
158
+ };
159
+ targetRuntime[targetKey] = {
160
+ ...runtime,
161
+ modelId: parsed.modelId
162
+ };
163
+ }
164
+ return { profiles, targetRuntime };
165
+ }
166
+ function normalizeRouting(source) {
167
+ const routing = {};
168
+ for (const [routeName, entries] of Object.entries(source)) {
169
+ if (!Array.isArray(entries))
170
+ continue;
171
+ const normalized = entries
172
+ .map((entry) => (typeof entry === 'string' ? entry.trim() : ''))
173
+ .filter(Boolean);
174
+ routing[routeName] = Array.from(new Set(normalized));
175
+ }
176
+ return routing;
177
+ }
178
+ function normalizeClassifier(input) {
179
+ const normalized = asRecord(input);
180
+ const result = {
181
+ longContextThresholdTokens: typeof normalized.longContextThresholdTokens === 'number'
182
+ ? normalized.longContextThresholdTokens
183
+ : DEFAULT_CLASSIFIER.longContextThresholdTokens,
184
+ thinkingKeywords: normalizeStringArray(normalized.thinkingKeywords, DEFAULT_CLASSIFIER.thinkingKeywords),
185
+ codingKeywords: normalizeStringArray(normalized.codingKeywords, DEFAULT_CLASSIFIER.codingKeywords),
186
+ backgroundKeywords: normalizeStringArray(normalized.backgroundKeywords, DEFAULT_CLASSIFIER.backgroundKeywords),
187
+ visionKeywords: normalizeStringArray(normalized.visionKeywords, DEFAULT_CLASSIFIER.visionKeywords)
188
+ };
189
+ return result;
190
+ }
191
+ function normalizeStringArray(value, fallback) {
192
+ if (!Array.isArray(value)) {
193
+ return [...fallback];
194
+ }
195
+ const normalized = value.map((item) => (typeof item === 'string' ? item.trim() : '')).filter(Boolean);
196
+ return normalized.length ? normalized : [...fallback];
197
+ }
198
+ function normalizeProvider(providerId, raw) {
199
+ const provider = asRecord(raw);
200
+ const providerType = detectProviderType(provider);
201
+ const endpoint = typeof provider.endpoint === 'string' && provider.endpoint.trim()
202
+ ? provider.endpoint.trim()
203
+ : typeof provider.baseURL === 'string' && provider.baseURL.trim()
204
+ ? provider.baseURL.trim()
205
+ : typeof provider.baseUrl === 'string' && provider.baseUrl.trim()
206
+ ? provider.baseUrl.trim()
207
+ : '';
208
+ const headers = normalizeHeaders(provider.headers);
209
+ const compatibilityProfile = resolveCompatibilityProfile(provider);
210
+ const processMode = normalizeProcessMode(provider.process);
211
+ return {
212
+ providerId,
213
+ providerType,
214
+ endpoint,
215
+ headers,
216
+ outboundProfile: mapOutboundProfile(providerType),
217
+ compatibilityProfile,
218
+ processMode
219
+ };
220
+ }
221
+ function resolveCompatibilityProfile(provider) {
222
+ const compat = provider.compat;
223
+ if (typeof compat === 'string' && compat.trim().length > 0) {
224
+ return compat.trim();
225
+ }
226
+ return 'default';
227
+ }
228
+ function normalizeProcessMode(value) {
229
+ if (typeof value !== 'string') {
230
+ return 'chat';
231
+ }
232
+ const normalized = value.trim().toLowerCase();
233
+ if (normalized === 'passthrough') {
234
+ return 'passthrough';
235
+ }
236
+ return 'chat';
237
+ }
238
+ function extractProviderAuthEntries(providerId, raw) {
239
+ const provider = asRecord(raw);
240
+ const auth = asRecord(provider.auth);
241
+ const entries = [];
242
+ const aliasSet = new Set();
243
+ const baseTypeInfo = interpretAuthType(auth.type);
244
+ const baseType = baseTypeInfo.type;
245
+ const baseTypeSource = typeof auth.type === 'string' ? auth.type : undefined;
246
+ const defaults = collectAuthDefaults(auth);
247
+ const buildAuthCandidate = (typeHint, extras = {}) => {
248
+ const source = typeof typeHint === 'string' && typeHint.trim()
249
+ ? typeHint.trim()
250
+ : baseTypeSource;
251
+ const typeInfo = interpretAuthType(source ?? baseType);
252
+ const rawType = typeInfo.raw ?? source ?? baseTypeSource;
253
+ return {
254
+ ...extras,
255
+ type: typeInfo.type,
256
+ rawType,
257
+ oauthProviderId: extras?.oauthProviderId ?? typeInfo.oauthProviderId
258
+ };
259
+ };
260
+ const pushEntry = (candidateAlias, authConfig) => {
261
+ const alias = normalizeAlias(candidateAlias, aliasSet);
262
+ const typeSource = authConfig?.rawType ??
263
+ authConfig?.type ??
264
+ baseTypeSource ??
265
+ baseType;
266
+ const typeInfo = interpretAuthType(typeSource);
267
+ const entryType = typeInfo.type;
268
+ const oauthProviderId = authConfig?.oauthProviderId ??
269
+ typeInfo.oauthProviderId ??
270
+ baseTypeInfo.oauthProviderId;
271
+ if (entryType === 'oauth' && !oauthProviderId) {
272
+ throw new VirtualRouterError(`Provider ${providerId} OAuth auth entries must declare provider-specific type (e.g. "qwen-oauth")`, VirtualRouterErrorCode.CONFIG_ERROR);
273
+ }
274
+ const normalized = {
275
+ type: entryType,
276
+ rawType: typeof typeSource === 'string' ? typeSource : undefined,
277
+ oauthProviderId,
278
+ value: readOptionalString(authConfig?.value ?? authConfig?.apiKey),
279
+ secretRef: readOptionalString(authConfig?.secretRef)
280
+ };
281
+ normalized.tokenFile = readOptionalString(authConfig?.tokenFile);
282
+ normalized.tokenUrl = readOptionalString(authConfig?.tokenUrl ?? authConfig?.token_url);
283
+ normalized.deviceCodeUrl = readOptionalString(authConfig?.deviceCodeUrl ?? authConfig?.device_code_url);
284
+ normalized.clientId = readOptionalString(authConfig?.clientId ?? authConfig?.client_id);
285
+ normalized.clientSecret = readOptionalString(authConfig?.clientSecret ?? authConfig?.client_secret);
286
+ normalized.authorizationUrl = readOptionalString(authConfig?.authorizationUrl ??
287
+ authConfig?.authorization_url ??
288
+ authConfig?.authUrl);
289
+ normalized.userInfoUrl = readOptionalString(authConfig?.userInfoUrl ?? authConfig?.user_info_url);
290
+ normalized.refreshUrl = readOptionalString(authConfig?.refreshUrl ?? authConfig?.refresh_url);
291
+ normalized.scopes = normalizeScopeList(authConfig?.scopes ?? authConfig?.scope);
292
+ normalized.secretRef ??= defaults.secretRef;
293
+ normalized.tokenFile ??= defaults.tokenFile;
294
+ normalized.tokenUrl ??= defaults.tokenUrl;
295
+ normalized.deviceCodeUrl ??= defaults.deviceCodeUrl;
296
+ normalized.clientId ??= defaults.clientId;
297
+ normalized.clientSecret ??= defaults.clientSecret;
298
+ normalized.authorizationUrl ??= defaults.authorizationUrl;
299
+ normalized.userInfoUrl ??= defaults.userInfoUrl;
300
+ normalized.refreshUrl ??= defaults.refreshUrl;
301
+ normalized.scopes = mergeScopes(normalized.scopes, defaults.scopes);
302
+ if (entryType === 'apiKey') {
303
+ if (!normalized.secretRef && normalized.value) {
304
+ normalized.secretRef = `${providerId}.${alias}`;
305
+ }
306
+ else if (!normalized.secretRef) {
307
+ normalized.secretRef = `${providerId}.${alias}`;
308
+ }
309
+ }
310
+ entries.push({ keyAlias: alias, auth: normalized });
311
+ aliasSet.add(alias);
312
+ };
313
+ const fromRecord = (record) => {
314
+ const data = asRecord(record);
315
+ const alias = readOptionalString(data.alias);
316
+ const typeValue = data.type ?? baseTypeSource ?? baseType;
317
+ pushEntry(alias, buildAuthCandidate(typeValue, {
318
+ value: data.value ?? data.apiKey,
319
+ secretRef: data.secretRef,
320
+ tokenFile: data.tokenFile,
321
+ tokenUrl: data.tokenUrl ?? data.token_url,
322
+ deviceCodeUrl: data.deviceCodeUrl ?? data.device_code_url,
323
+ clientId: data.clientId ?? data.client_id,
324
+ clientSecret: data.clientSecret ?? data.client_secret,
325
+ authorizationUrl: data.authorizationUrl ??
326
+ data.authorization_url ??
327
+ data.authUrl,
328
+ userInfoUrl: data.userInfoUrl ?? data.user_info_url,
329
+ refreshUrl: data.refreshUrl ?? data.refresh_url,
330
+ scopes: data.scopes ?? data.scope
331
+ }));
332
+ };
333
+ if (Array.isArray(auth.entries)) {
334
+ for (const entry of auth.entries) {
335
+ fromRecord(entry);
336
+ }
337
+ }
338
+ if (Array.isArray(auth.keys)) {
339
+ for (const entry of auth.keys) {
340
+ fromRecord(entry);
341
+ }
342
+ }
343
+ else {
344
+ const keysObject = asRecord(auth.keys);
345
+ for (const [alias, entry] of Object.entries(keysObject)) {
346
+ if (entry && typeof entry === 'object') {
347
+ fromRecord({ alias, ...entry });
348
+ }
349
+ else if (typeof entry === 'string') {
350
+ pushEntry(alias, buildAuthCandidate(baseTypeSource, { value: entry }));
351
+ }
352
+ }
353
+ }
354
+ const apiKeyField = provider.apiKey ?? provider.apiKeys ?? auth.apiKey;
355
+ if (Array.isArray(apiKeyField)) {
356
+ for (const item of apiKeyField) {
357
+ if (typeof item === 'string' && item.trim()) {
358
+ pushEntry(undefined, buildAuthCandidate(baseTypeSource, { value: item.trim() }));
359
+ }
360
+ else if (item && typeof item === 'object') {
361
+ fromRecord(item);
362
+ }
363
+ }
364
+ }
365
+ else if (typeof apiKeyField === 'string' && apiKeyField.trim()) {
366
+ pushEntry(undefined, buildAuthCandidate(baseTypeSource, { value: apiKeyField.trim() }));
367
+ }
368
+ if (!entries.length) {
369
+ const fallbackExtras = {
370
+ value: readOptionalString(auth.value),
371
+ secretRef: readOptionalString(auth.secretRef),
372
+ tokenFile: readOptionalString(auth.tokenFile ?? auth.file),
373
+ tokenUrl: readOptionalString(auth.tokenUrl ?? auth.token_url),
374
+ deviceCodeUrl: readOptionalString(auth.deviceCodeUrl ?? auth.device_code_url),
375
+ clientId: readOptionalString(auth.clientId ?? auth.client_id),
376
+ clientSecret: readOptionalString(auth.clientSecret ?? auth.client_secret),
377
+ authorizationUrl: readOptionalString(auth?.authorizationUrl ?? auth?.authorization_url ?? auth?.authUrl),
378
+ userInfoUrl: readOptionalString(auth?.userInfoUrl ?? auth?.user_info_url),
379
+ refreshUrl: readOptionalString(auth?.refreshUrl ?? auth?.refresh_url),
380
+ scopes: normalizeScopeList(auth?.scopes ?? auth?.scope)
381
+ };
382
+ const fallbackHasData = Boolean(fallbackExtras.value ||
383
+ fallbackExtras.secretRef ||
384
+ fallbackExtras.tokenFile ||
385
+ fallbackExtras.tokenUrl ||
386
+ fallbackExtras.deviceCodeUrl ||
387
+ fallbackExtras.clientId ||
388
+ fallbackExtras.clientSecret ||
389
+ (fallbackExtras.scopes &&
390
+ Array.isArray(fallbackExtras.scopes) &&
391
+ fallbackExtras.scopes.length));
392
+ if (fallbackHasData) {
393
+ pushEntry(undefined, buildAuthCandidate(baseTypeSource, fallbackExtras));
394
+ }
395
+ }
396
+ if (!entries.length) {
397
+ throw new VirtualRouterError(`Provider ${providerId} is missing auth configuration`, VirtualRouterErrorCode.CONFIG_ERROR);
398
+ }
399
+ return entries;
400
+ }
401
+ function parseRouteEntry(entry, aliasIndex) {
402
+ const value = typeof entry === 'string' ? entry.trim() : '';
403
+ if (!value)
404
+ return null;
405
+ const firstDot = value.indexOf('.');
406
+ if (firstDot <= 0 || firstDot === value.length - 1)
407
+ return null;
408
+ const providerId = value.slice(0, firstDot);
409
+ const remainder = value.slice(firstDot + 1);
410
+ const aliases = aliasIndex.get(providerId);
411
+ if (aliases && aliases.length) {
412
+ const secondDot = remainder.indexOf('.');
413
+ if (secondDot > 0 && secondDot < remainder.length - 1) {
414
+ const aliasCandidate = remainder.slice(0, secondDot);
415
+ if (aliases.includes(aliasCandidate)) {
416
+ return {
417
+ providerId,
418
+ keyAlias: aliasCandidate,
419
+ modelId: remainder.slice(secondDot + 1)
420
+ };
421
+ }
422
+ }
423
+ }
424
+ return { providerId, modelId: remainder };
425
+ }
426
+ function parseTargetKey(targetKey) {
427
+ const value = typeof targetKey === 'string' ? targetKey.trim() : '';
428
+ if (!value)
429
+ return null;
430
+ const firstDot = value.indexOf('.');
431
+ if (firstDot <= 0 || firstDot === value.length - 1)
432
+ return null;
433
+ const providerId = value.slice(0, firstDot);
434
+ const remainder = value.slice(firstDot + 1);
435
+ const secondDot = remainder.indexOf('.');
436
+ if (secondDot <= 0 || secondDot === remainder.length - 1)
437
+ return null;
438
+ return {
439
+ providerId,
440
+ keyAlias: remainder.slice(0, secondDot),
441
+ modelId: remainder.slice(secondDot + 1)
442
+ };
443
+ }
444
+ function detectProviderType(provider) {
445
+ const raw = (provider.providerType || provider.protocol || provider.type || '').toString().toLowerCase();
446
+ const id = (provider.providerId || provider.id || '').toString().toLowerCase();
447
+ const match = (value, keyword) => value.includes(keyword);
448
+ const source = `${raw}|${id}`;
449
+ const normalized = (src) => (src && src.trim() ? src.trim() : '');
450
+ const lexicon = normalized(source);
451
+ if (!lexicon)
452
+ return 'openai';
453
+ if (match(lexicon, 'anthropic') || match(lexicon, 'claude'))
454
+ return 'anthropic';
455
+ if (match(lexicon, 'responses'))
456
+ return 'responses';
457
+ if (match(lexicon, 'gemini'))
458
+ return 'gemini';
459
+ if (match(lexicon, 'iflow'))
460
+ return 'iflow';
461
+ if (match(lexicon, 'qwen'))
462
+ return 'qwen';
463
+ if (match(lexicon, 'glm'))
464
+ return 'glm';
465
+ if (match(lexicon, 'lmstudio'))
466
+ return 'lmstudio';
467
+ return raw || 'openai';
468
+ }
469
+ function mapOutboundProfile(providerType) {
470
+ const value = providerType.toLowerCase();
471
+ if (value === 'anthropic')
472
+ return 'anthropic-messages';
473
+ if (value === 'responses')
474
+ return 'openai-responses';
475
+ if (value === 'gemini')
476
+ return 'gemini-chat';
477
+ return 'openai-chat';
478
+ }
479
+ function collectAuthDefaults(auth) {
480
+ return {
481
+ secretRef: readOptionalString(auth.secretRef) ?? readOptionalString(auth?.file),
482
+ tokenFile: readOptionalString(auth.tokenFile) ?? readOptionalString(auth?.file),
483
+ tokenUrl: readOptionalString(auth.tokenUrl ?? auth.token_url),
484
+ deviceCodeUrl: readOptionalString(auth.deviceCodeUrl ?? auth.device_code_url),
485
+ clientId: readOptionalString(auth.clientId ?? auth.client_id),
486
+ clientSecret: readOptionalString(auth.clientSecret ?? auth.client_secret),
487
+ authorizationUrl: readOptionalString(auth?.authorizationUrl ?? auth?.authorization_url ?? auth?.authUrl),
488
+ userInfoUrl: readOptionalString(auth?.userInfoUrl ?? auth?.user_info_url),
489
+ refreshUrl: readOptionalString(auth?.refreshUrl ?? auth?.refresh_url),
490
+ scopes: normalizeScopeList(auth?.scopes ?? auth?.scope)
491
+ };
492
+ }
493
+ function readOptionalString(value) {
494
+ if (typeof value !== 'string') {
495
+ return undefined;
496
+ }
497
+ const trimmed = value.trim();
498
+ return trimmed ? trimmed : undefined;
499
+ }
500
+ function normalizeScopeList(value) {
501
+ if (Array.isArray(value)) {
502
+ const normalized = value
503
+ .map((item) => readOptionalString(item))
504
+ .filter((item) => typeof item === 'string');
505
+ return normalized.length ? normalized : undefined;
506
+ }
507
+ if (typeof value === 'string' && value.trim()) {
508
+ const normalized = value
509
+ .split(/[\,\s]+/)
510
+ .map((item) => item.trim())
511
+ .filter(Boolean);
512
+ return normalized.length ? normalized : undefined;
513
+ }
514
+ return undefined;
515
+ }
516
+ function mergeScopes(primary, fallback) {
517
+ if ((!primary || !primary.length) && (!fallback || !fallback.length)) {
518
+ return undefined;
519
+ }
520
+ const merged = new Set();
521
+ for (const scope of primary ?? []) {
522
+ if (scope.trim())
523
+ merged.add(scope.trim());
524
+ }
525
+ for (const scope of fallback ?? []) {
526
+ if (scope.trim())
527
+ merged.add(scope.trim());
528
+ }
529
+ return merged.size ? Array.from(merged) : undefined;
530
+ }
531
+ function interpretAuthType(value) {
532
+ if (typeof value !== 'string') {
533
+ return { type: 'apiKey' };
534
+ }
535
+ const trimmed = value.trim();
536
+ if (!trimmed) {
537
+ return { type: 'apiKey' };
538
+ }
539
+ const lower = trimmed.toLowerCase();
540
+ if (lower === 'apikey' || lower === 'api-key') {
541
+ return { type: 'apiKey', raw: trimmed };
542
+ }
543
+ if (lower === 'oauth') {
544
+ return { type: 'oauth', raw: trimmed };
545
+ }
546
+ const match = lower.match(/^([a-z0-9._-]+)-oauth$/);
547
+ if (match) {
548
+ return { type: 'oauth', oauthProviderId: match[1], raw: trimmed };
549
+ }
550
+ if (lower.includes('oauth')) {
551
+ return { type: 'oauth', raw: trimmed };
552
+ }
553
+ return { type: 'apiKey', raw: trimmed };
554
+ }
555
+ function normalizeLoadBalancing(input) {
556
+ if (!input || typeof input !== 'object')
557
+ return undefined;
558
+ const record = input;
559
+ const strategyRaw = typeof record.strategy === 'string' ? record.strategy.trim().toLowerCase() : '';
560
+ if (!strategyRaw)
561
+ return undefined;
562
+ const strategy = strategyRaw === 'weighted' || strategyRaw === 'sticky' ? strategyRaw : 'round-robin';
563
+ const weightsRaw = asRecord(record.weights);
564
+ const weightsEntries = {};
565
+ for (const [key, value] of Object.entries(weightsRaw)) {
566
+ if (typeof value === 'number' && Number.isFinite(value)) {
567
+ weightsEntries[key] = value;
568
+ }
569
+ }
570
+ return Object.keys(weightsEntries).length
571
+ ? { strategy, weights: weightsEntries }
572
+ : { strategy };
573
+ }
574
+ function normalizeHealth(input) {
575
+ if (!input || typeof input !== 'object')
576
+ return undefined;
577
+ const record = input;
578
+ const failureThreshold = typeof record.failureThreshold === 'number' ? record.failureThreshold : undefined;
579
+ const cooldownMs = typeof record.cooldownMs === 'number' ? record.cooldownMs : undefined;
580
+ const fatalCooldownMs = typeof record.fatalCooldownMs === 'number' ? record.fatalCooldownMs : undefined;
581
+ if (typeof failureThreshold !== 'number' || typeof cooldownMs !== 'number') {
582
+ return undefined;
583
+ }
584
+ return fatalCooldownMs !== undefined
585
+ ? { failureThreshold, cooldownMs, fatalCooldownMs }
586
+ : { failureThreshold, cooldownMs };
587
+ }
588
+ function normalizeHeaders(input) {
589
+ if (!input || typeof input !== 'object') {
590
+ return undefined;
591
+ }
592
+ const entries = {};
593
+ for (const [key, value] of Object.entries(input)) {
594
+ if (typeof value === 'string') {
595
+ entries[key] = value;
596
+ }
597
+ }
598
+ return Object.keys(entries).length ? entries : undefined;
599
+ }
600
+ function asRecord(value) {
601
+ return (value && typeof value === 'object' ? value : {});
602
+ }
603
+ function normalizeAlias(candidate, existing) {
604
+ const base = candidate && candidate.trim() ? candidate.trim() : `key${existing.size + 1}`;
605
+ let alias = base;
606
+ let i = 1;
607
+ while (existing.has(alias)) {
608
+ alias = `${base}_${i}`;
609
+ i += 1;
610
+ }
611
+ return alias;
612
+ }
613
+ function pushUnique(list, value) {
614
+ if (!list.includes(value)) {
615
+ list.push(value);
616
+ }
617
+ }
618
+ function buildRuntimeKey(providerId, keyAlias) {
619
+ return `${providerId}.${keyAlias}`;
620
+ }
@@ -0,0 +1,10 @@
1
+ import type { ClassificationResult, RoutingFeatures, VirtualRouterClassifierConfig } from './types.js';
2
+ export declare class RoutingClassifier {
3
+ private readonly config;
4
+ constructor(config: VirtualRouterClassifierConfig);
5
+ classify(features: RoutingFeatures): ClassificationResult;
6
+ private buildResult;
7
+ private ensureDefaultCandidate;
8
+ private orderRoutes;
9
+ private routeWeight;
10
+ }