@jsonstudio/rcc 0.89.3 → 0.89.164

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 (270) hide show
  1. package/README.md +240 -179
  2. package/config/modules.json +1 -11
  3. package/dist/build-info.js +2 -2
  4. package/dist/build-info.js.map +1 -1
  5. package/dist/client/gemini-cli/gemini-cli-protocol-client.d.ts +16 -0
  6. package/dist/client/gemini-cli/gemini-cli-protocol-client.js +56 -0
  7. package/dist/client/gemini-cli/gemini-cli-protocol-client.js.map +1 -0
  8. package/dist/client/openai/chat-protocol-client.js.map +1 -1
  9. package/dist/config/modules.json +1 -11
  10. package/dist/core/provider-health-manager.d.ts +17 -0
  11. package/dist/core/provider-health-manager.js +66 -0
  12. package/dist/core/provider-health-manager.js.map +1 -0
  13. package/dist/error-handling/route-error-hub.d.ts +48 -0
  14. package/dist/error-handling/route-error-hub.js +131 -0
  15. package/dist/error-handling/route-error-hub.js.map +1 -0
  16. package/dist/index.js +26 -1
  17. package/dist/index.js.map +1 -1
  18. package/dist/modules/llmswitch/bridge.d.ts +2 -0
  19. package/dist/modules/llmswitch/bridge.js +17 -0
  20. package/dist/modules/llmswitch/bridge.js.map +1 -1
  21. package/dist/modules/pipeline/utils/colored-logger.d.ts +14 -0
  22. package/dist/modules/pipeline/utils/colored-logger.js +48 -0
  23. package/dist/modules/pipeline/utils/colored-logger.js.map +1 -0
  24. package/dist/modules/pipeline/utils/debug-logger.d.ts +2 -0
  25. package/dist/modules/pipeline/utils/debug-logger.js +36 -0
  26. package/dist/modules/pipeline/utils/debug-logger.js.map +1 -1
  27. package/dist/providers/auth/gemini-cli-userinfo-helper.d.ts +53 -0
  28. package/dist/providers/auth/gemini-cli-userinfo-helper.js +152 -0
  29. package/dist/providers/auth/gemini-cli-userinfo-helper.js.map +1 -0
  30. package/dist/providers/auth/oauth-auth.js +3 -2
  31. package/dist/providers/auth/oauth-auth.js.map +1 -1
  32. package/dist/providers/auth/oauth-lifecycle.js +21 -20
  33. package/dist/providers/auth/oauth-lifecycle.js.map +1 -1
  34. package/dist/providers/auth/oauth-logger.d.ts +1 -0
  35. package/dist/providers/auth/oauth-logger.js +21 -0
  36. package/dist/providers/auth/oauth-logger.js.map +1 -0
  37. package/dist/providers/compat/compat-directory-loader.js +2 -55
  38. package/dist/providers/compat/compat-directory-loader.js.map +1 -1
  39. package/dist/providers/compat/compatibility-factory.d.ts +4 -4
  40. package/dist/providers/compat/compatibility-factory.js +108 -0
  41. package/dist/providers/compat/compatibility-factory.js.map +1 -1
  42. package/dist/providers/compat/glm/glm-compatibility.d.ts +2 -2
  43. package/dist/providers/compat/glm/glm-compatibility.js +7 -7
  44. package/dist/providers/compat/glm/glm-compatibility.js.map +1 -1
  45. package/dist/providers/compat/glm/index.js +0 -6
  46. package/dist/providers/compat/glm/index.js.map +1 -1
  47. package/dist/providers/compat/iflow/iflow-compatibility.d.ts +1 -1
  48. package/dist/providers/compat/iflow/iflow-compatibility.js +6 -6
  49. package/dist/providers/compat/iflow/iflow-compatibility.js.map +1 -1
  50. package/dist/providers/compat/index.d.ts +0 -6
  51. package/dist/providers/compat/index.js +0 -7
  52. package/dist/providers/compat/index.js.map +1 -1
  53. package/dist/providers/compat/lmstudio-compatibility.d.ts +2 -2
  54. package/dist/providers/compat/lmstudio-compatibility.js +4 -4
  55. package/dist/providers/compat/lmstudio-compatibility.js.map +1 -1
  56. package/dist/providers/compat/passthrough-compatibility.d.ts +1 -1
  57. package/dist/providers/compat/passthrough-compatibility.js +3 -3
  58. package/dist/providers/compat/passthrough-compatibility.js.map +1 -1
  59. package/dist/providers/compat/profiles/chat/glm/index.d.ts +6 -0
  60. package/dist/providers/compat/profiles/chat/glm/index.js +6 -0
  61. package/dist/providers/compat/profiles/chat/glm/index.js.map +1 -0
  62. package/dist/providers/compat/profiles/chat/iflow/index.d.ts +6 -0
  63. package/dist/providers/compat/profiles/chat/iflow/index.js +6 -0
  64. package/dist/providers/compat/profiles/chat/iflow/index.js.map +1 -0
  65. package/dist/providers/compat/profiles/chat/lmstudio/index.d.ts +6 -0
  66. package/dist/providers/compat/profiles/chat/lmstudio/index.js +6 -0
  67. package/dist/providers/compat/profiles/chat/lmstudio/index.js.map +1 -0
  68. package/dist/providers/compat/profiles/chat/qwen/index.d.ts +6 -0
  69. package/dist/providers/compat/profiles/chat/qwen/index.js +6 -0
  70. package/dist/providers/compat/profiles/chat/qwen/index.js.map +1 -0
  71. package/dist/providers/compat/profiles/compat/passthrough/index.d.ts +6 -0
  72. package/dist/providers/compat/profiles/compat/passthrough/index.js +6 -0
  73. package/dist/providers/compat/profiles/compat/passthrough/index.js.map +1 -0
  74. package/dist/providers/compat/profiles/responses/c4m/index.d.ts +6 -0
  75. package/dist/providers/compat/profiles/responses/c4m/index.js +6 -0
  76. package/dist/providers/compat/profiles/responses/c4m/index.js.map +1 -0
  77. package/dist/providers/compat/profiles/responses/default/index.d.ts +6 -0
  78. package/dist/providers/compat/profiles/responses/default/index.js +6 -0
  79. package/dist/providers/compat/profiles/responses/default/index.js.map +1 -0
  80. package/dist/providers/compat/profiles/responses/fai/index.d.ts +6 -0
  81. package/dist/providers/compat/profiles/responses/fai/index.js +6 -0
  82. package/dist/providers/compat/profiles/responses/fai/index.js.map +1 -0
  83. package/dist/providers/compat/profiles/responses/fc/index.d.ts +6 -0
  84. package/dist/providers/compat/profiles/responses/fc/index.js +6 -0
  85. package/dist/providers/compat/profiles/responses/fc/index.js.map +1 -0
  86. package/dist/providers/compat/qwen/index.js +0 -6
  87. package/dist/providers/compat/qwen/index.js.map +1 -1
  88. package/dist/providers/compat/qwen-compatibility.d.ts +2 -2
  89. package/dist/providers/compat/qwen-compatibility.js +4 -4
  90. package/dist/providers/compat/qwen-compatibility.js.map +1 -1
  91. package/dist/providers/compat/register-compat-module.d.ts +8 -0
  92. package/dist/providers/compat/register-compat-module.js +53 -0
  93. package/dist/providers/compat/register-compat-module.js.map +1 -0
  94. package/dist/providers/compat/responses/c4m-responses-compatibility.d.ts +6 -2
  95. package/dist/providers/compat/responses/c4m-responses-compatibility.js +85 -3
  96. package/dist/providers/compat/responses/c4m-responses-compatibility.js.map +1 -1
  97. package/dist/providers/compat/standard-compatibility-utils.js +45 -15
  98. package/dist/providers/compat/standard-compatibility-utils.js.map +1 -1
  99. package/dist/providers/core/api/provider-config.d.ts +1 -1
  100. package/dist/providers/core/api/provider-types.d.ts +3 -1
  101. package/dist/providers/core/api/provider-types.js +1 -0
  102. package/dist/providers/core/api/provider-types.js.map +1 -1
  103. package/dist/providers/core/config/service-profiles.js +5 -2
  104. package/dist/providers/core/config/service-profiles.js.map +1 -1
  105. package/dist/providers/core/runtime/base-provider.d.ts +3 -0
  106. package/dist/providers/core/runtime/base-provider.js +101 -6
  107. package/dist/providers/core/runtime/base-provider.js.map +1 -1
  108. package/dist/providers/core/runtime/gemini-cli-http-provider.d.ts +34 -0
  109. package/dist/providers/core/runtime/gemini-cli-http-provider.js +152 -0
  110. package/dist/providers/core/runtime/gemini-cli-http-provider.js.map +1 -0
  111. package/dist/providers/core/runtime/http-transport-provider.d.ts +1 -0
  112. package/dist/providers/core/runtime/http-transport-provider.js +178 -123
  113. package/dist/providers/core/runtime/http-transport-provider.js.map +1 -1
  114. package/dist/providers/core/runtime/provider-factory.d.ts +1 -1
  115. package/dist/providers/core/runtime/provider-factory.js +8 -0
  116. package/dist/providers/core/runtime/provider-factory.js.map +1 -1
  117. package/dist/providers/core/runtime/provider-runtime-metadata.d.ts +1 -0
  118. package/dist/providers/core/runtime/provider-runtime-metadata.js.map +1 -1
  119. package/dist/providers/core/runtime/responses-provider.d.ts +7 -0
  120. package/dist/providers/core/runtime/responses-provider.js +228 -12
  121. package/dist/providers/core/runtime/responses-provider.js.map +1 -1
  122. package/dist/providers/core/strategies/oauth-auth-code-flow.js +10 -9
  123. package/dist/providers/core/strategies/oauth-auth-code-flow.js.map +1 -1
  124. package/dist/providers/core/strategies/oauth-device-flow.js +10 -9
  125. package/dist/providers/core/strategies/oauth-device-flow.js.map +1 -1
  126. package/dist/providers/core/utils/provider-error-reporter.js +63 -15
  127. package/dist/providers/core/utils/provider-error-reporter.js.map +1 -1
  128. package/dist/providers/core/utils/provider-type-utils.d.ts +1 -1
  129. package/dist/providers/core/utils/provider-type-utils.js +6 -1
  130. package/dist/providers/core/utils/provider-type-utils.js.map +1 -1
  131. package/dist/providers/core/utils/snapshot-writer.d.ts +10 -0
  132. package/dist/providers/core/utils/snapshot-writer.js +85 -0
  133. package/dist/providers/core/utils/snapshot-writer.js.map +1 -1
  134. package/dist/providers/mock/mock-provider-runtime.js +44 -0
  135. package/dist/providers/mock/mock-provider-runtime.js.map +1 -1
  136. package/dist/providers/profile/provider-profile-loader.js +26 -19
  137. package/dist/providers/profile/provider-profile-loader.js.map +1 -1
  138. package/dist/providers/profile/provider-profile.d.ts +2 -2
  139. package/dist/server/handlers/chat-handler.js +9 -3
  140. package/dist/server/handlers/chat-handler.js.map +1 -1
  141. package/dist/server/handlers/handler-utils.d.ts +7 -1
  142. package/dist/server/handlers/handler-utils.js +64 -52
  143. package/dist/server/handlers/handler-utils.js.map +1 -1
  144. package/dist/server/handlers/messages-handler.js +9 -3
  145. package/dist/server/handlers/messages-handler.js.map +1 -1
  146. package/dist/server/handlers/responses-handler.js +21 -13
  147. package/dist/server/handlers/responses-handler.js.map +1 -1
  148. package/dist/server/runtime/http-server/colored-logger.d.ts +1 -0
  149. package/dist/server/runtime/http-server/colored-logger.js +33 -0
  150. package/dist/server/runtime/http-server/colored-logger.js.map +1 -0
  151. package/dist/server/runtime/http-server/index.d.ts +3 -0
  152. package/dist/server/runtime/http-server/index.js +76 -19
  153. package/dist/server/runtime/http-server/index.js.map +1 -1
  154. package/dist/server/runtime/http-server/provider-utils.d.ts +3 -1
  155. package/dist/server/runtime/http-server/provider-utils.js +12 -2
  156. package/dist/server/runtime/http-server/provider-utils.js.map +1 -1
  157. package/dist/server/runtime/http-server/request-executor.js +6 -2
  158. package/dist/server/runtime/http-server/request-executor.js.map +1 -1
  159. package/dist/server/runtime/http-server/routes.js +31 -11
  160. package/dist/server/runtime/http-server/routes.js.map +1 -1
  161. package/dist/server/runtime/http-server/types.d.ts +2 -1
  162. package/dist/utils/error-center-payload.d.ts +7 -0
  163. package/dist/utils/error-center-payload.js +67 -0
  164. package/dist/utils/error-center-payload.js.map +1 -0
  165. package/dist/utils/error-handler-registry.d.ts +7 -0
  166. package/dist/utils/error-handler-registry.js +44 -12
  167. package/dist/utils/error-handler-registry.js.map +1 -1
  168. package/node_modules/@jsonstudio/llms/dist/conversion/codecs/responses-openai-codec.js +16 -1
  169. package/node_modules/@jsonstudio/llms/dist/conversion/compat/profiles/chat-glm.json +17 -0
  170. package/node_modules/@jsonstudio/llms/dist/conversion/compat/profiles/chat-iflow.json +36 -0
  171. package/node_modules/@jsonstudio/llms/dist/conversion/compat/profiles/chat-lmstudio.json +37 -0
  172. package/node_modules/@jsonstudio/llms/dist/conversion/compat/profiles/chat-qwen.json +18 -0
  173. package/node_modules/@jsonstudio/llms/dist/conversion/compat/profiles/responses-c4m.json +45 -0
  174. package/node_modules/@jsonstudio/llms/dist/conversion/config/compat-profiles.json +38 -0
  175. package/node_modules/@jsonstudio/llms/dist/conversion/config/sample-config.json +314 -0
  176. package/node_modules/@jsonstudio/llms/dist/conversion/config/version-switch.json +150 -0
  177. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/compat/compat-engine.d.ts +4 -0
  178. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/compat/compat-engine.js +667 -0
  179. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/compat/compat-profile-store.d.ts +2 -0
  180. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/compat/compat-profile-store.js +76 -0
  181. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/compat/compat-types.d.ts +62 -0
  182. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/compat/compat-types.js +1 -0
  183. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/hub-pipeline.d.ts +2 -0
  184. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/hub-pipeline.js +110 -29
  185. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage3_compat/index.d.ts +14 -0
  186. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage3_compat/index.js +23 -0
  187. package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage1_client_remap/index.js +34 -0
  188. package/node_modules/@jsonstudio/llms/dist/conversion/hub/process/chat-process.js +4 -1
  189. package/node_modules/@jsonstudio/llms/dist/conversion/hub/response/provider-response.js +26 -0
  190. package/node_modules/@jsonstudio/llms/dist/conversion/responses/responses-openai-bridge.d.ts +1 -0
  191. package/node_modules/@jsonstudio/llms/dist/conversion/responses/responses-openai-bridge.js +71 -0
  192. package/node_modules/@jsonstudio/llms/dist/conversion/shared/responses-conversation-store.d.ts +35 -0
  193. package/node_modules/@jsonstudio/llms/dist/conversion/shared/responses-conversation-store.js +64 -19
  194. package/node_modules/@jsonstudio/llms/dist/conversion/shared/tool-filter-pipeline.d.ts +21 -0
  195. package/node_modules/@jsonstudio/llms/dist/conversion/shared/tool-filter-pipeline.js +138 -22
  196. package/node_modules/@jsonstudio/llms/dist/conversion/shared/tool-governor.d.ts +21 -0
  197. package/node_modules/@jsonstudio/llms/dist/conversion/shared/tool-governor.js +116 -1
  198. package/node_modules/@jsonstudio/llms/dist/conversion/shared/tool-mapping.js +52 -2
  199. package/node_modules/@jsonstudio/llms/dist/filters/config/openai-openai.fieldmap.json +18 -0
  200. package/node_modules/@jsonstudio/llms/dist/filters/special/request-tools-normalize.js +20 -1
  201. package/node_modules/@jsonstudio/llms/dist/guidance/index.js +6 -2
  202. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/bootstrap.js +16 -7
  203. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/classifier.js +40 -37
  204. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/default-thinking-keywords.d.ts +1 -0
  205. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/default-thinking-keywords.js +13 -0
  206. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/engine.d.ts +39 -0
  207. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/engine.js +52 -11
  208. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/features.js +340 -11
  209. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/token-counter.d.ts +2 -0
  210. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/token-counter.js +105 -0
  211. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/types.d.ts +8 -0
  212. package/node_modules/@jsonstudio/llms/dist/router/virtual-router/types.js +2 -2
  213. package/node_modules/@jsonstudio/llms/dist/sse/sse-to-json/builders/response-builder.d.ts +2 -0
  214. package/node_modules/@jsonstudio/llms/dist/sse/sse-to-json/builders/response-builder.js +53 -11
  215. package/node_modules/@jsonstudio/llms/dist/test-output/virtual-router/results.json +1 -0
  216. package/node_modules/@jsonstudio/llms/dist/test-output/virtual-router/summary.json +12 -0
  217. package/node_modules/@jsonstudio/llms/dist/tools/tool-registry.js +4 -3
  218. package/node_modules/@jsonstudio/llms/package.json +3 -3
  219. package/package.json +11 -9
  220. package/scripts/analyze-routing-classifier.mjs +166 -0
  221. package/scripts/analyze-routing-samples.mjs +216 -0
  222. package/scripts/analyze-thinking-keywords.mjs +17 -2
  223. package/scripts/build-core.mjs +8 -0
  224. package/scripts/classify-sample-tools.mjs +252 -0
  225. package/scripts/ensure-llmswitch-mode.mjs +95 -0
  226. package/scripts/gen-build-info.mjs +58 -4
  227. package/scripts/install-global.sh +1 -1
  228. package/scripts/install-release.sh +7 -0
  229. package/scripts/mock-provider/run-regressions.mjs +60 -14
  230. package/scripts/tests/apply-patch-loop.mjs +100 -9
  231. package/scripts/tests/golden-provider-cycle.mjs +12 -1
  232. package/scripts/tests/responses-provider-dry-run.mjs +15 -1
  233. package/scripts/tests/virtual-router-health.mjs +12 -5
  234. package/scripts/tools/capture-provider-goldens.mjs +75 -25
  235. package/scripts/tools/responses-golden-dry-run.mjs +17 -1
  236. package/scripts/tools/responses-provider-replay.mjs +17 -1
  237. package/scripts/tools/sync-ci-goldens.mjs +131 -0
  238. package/scripts/verification/samples/openai-chat-list-local-files.json +19 -796
  239. package/scripts/verify-e2e-toolcall.mjs +52 -0
  240. package/dist/providers/compat/config/index.d.ts +0 -1
  241. package/dist/providers/compat/config/index.js +0 -5
  242. package/dist/providers/compat/config/index.js.map +0 -1
  243. package/dist/providers/compat/iflow/index.d.ts +0 -27
  244. package/dist/providers/compat/iflow/index.js +0 -32
  245. package/dist/providers/compat/iflow/index.js.map +0 -1
  246. package/dist/providers/compat/lmstudio/index.d.ts +0 -4
  247. package/dist/providers/compat/lmstudio/index.js +0 -10
  248. package/dist/providers/compat/lmstudio/index.js.map +0 -1
  249. package/dist/providers/compat/passthrough/index.d.ts +0 -4
  250. package/dist/providers/compat/passthrough/index.js +0 -9
  251. package/dist/providers/compat/passthrough/index.js.map +0 -1
  252. package/dist/providers/compat/responses/index.d.ts +0 -1
  253. package/dist/providers/compat/responses/index.js +0 -8
  254. package/dist/providers/compat/responses/index.js.map +0 -1
  255. package/dist/providers/core/composite/compat/anthropic.d.ts +0 -3
  256. package/dist/providers/core/composite/compat/anthropic.js +0 -7
  257. package/dist/providers/core/composite/compat/anthropic.js.map +0 -1
  258. package/dist/providers/core/composite/compat/gemini.d.ts +0 -3
  259. package/dist/providers/core/composite/compat/gemini.js +0 -7
  260. package/dist/providers/core/composite/compat/gemini.js.map +0 -1
  261. package/dist/providers/core/composite/compat/openai-compat-aggregator.d.ts +0 -9
  262. package/dist/providers/core/composite/compat/openai-compat-aggregator.js +0 -135
  263. package/dist/providers/core/composite/compat/openai-compat-aggregator.js.map +0 -1
  264. package/dist/providers/core/composite/compat/responses.d.ts +0 -3
  265. package/dist/providers/core/composite/compat/responses.js +0 -91
  266. package/dist/providers/core/composite/compat/responses.js.map +0 -1
  267. package/dist/providers/core/composite/provider-composite.d.ts +0 -50
  268. package/dist/providers/core/composite/provider-composite.js +0 -235
  269. package/dist/providers/core/composite/provider-composite.js.map +0 -1
  270. package/scripts/tests/apply-patch-loop.mjs.bak +0 -363
@@ -1,5 +1,125 @@
1
+ import { countRequestTokens } from './token-counter.js';
1
2
  const THINKING_KEYWORDS = ['let me think', 'chain of thought', 'cot', 'reason step', 'deliberate'];
2
3
  const WEB_TOOL_KEYWORDS = ['websearch', 'web_search', 'web-search', 'webfetch', 'web_fetch', 'web_request', 'search_web', 'internet_search'];
4
+ const READ_TOOL_EXACT = new Set([
5
+ 'read_file',
6
+ 'read_text',
7
+ 'view_file',
8
+ 'view_code',
9
+ 'view_document',
10
+ 'open_file',
11
+ 'get_file',
12
+ 'download_file',
13
+ 'describe_current_request',
14
+ 'list_dir',
15
+ 'list_directory',
16
+ 'list_files',
17
+ 'list_documents',
18
+ 'list_resources',
19
+ 'search_files',
20
+ 'find_files'
21
+ ]);
22
+ const WRITE_TOOL_EXACT = new Set([
23
+ 'apply_patch',
24
+ 'write_file',
25
+ 'create_file',
26
+ 'modify_file',
27
+ 'edit_file',
28
+ 'update_file',
29
+ 'save_file',
30
+ 'append_file',
31
+ 'replace_file',
32
+ 'delete_file',
33
+ 'remove_file',
34
+ 'rename_file',
35
+ 'move_file',
36
+ 'copy_file',
37
+ 'mkdir',
38
+ 'rmdir'
39
+ ]);
40
+ const SEARCH_TOOL_EXACT = new Set(['websearch', 'web_search', 'search_web', 'internet_search', 'webfetch', 'web_fetch']);
41
+ const READ_TOOL_KEYWORDS = ['read', 'list', 'view', 'download', 'open', 'show', 'fetch', 'inspect'];
42
+ const WRITE_TOOL_KEYWORDS = ['write', 'patch', 'modify', 'edit', 'create', 'update', 'append', 'replace', 'delete', 'remove'];
43
+ const SEARCH_TOOL_KEYWORDS = ['search', 'websearch', 'web_fetch', 'webfetch', 'web-request', 'web_request', 'internet'];
44
+ const SHELL_TOOL_NAMES = new Set(['shell_command', 'shell', 'bash']);
45
+ const SHELL_HEREDOC_PATTERN = /<<\s*['"]?[a-z0-9_-]+/i;
46
+ const SHELL_WRITE_PATTERNS = [
47
+ 'apply_patch',
48
+ 'sed -i',
49
+ 'perl -pi',
50
+ 'tee ',
51
+ 'cat <<',
52
+ 'cat >',
53
+ 'printf >',
54
+ 'touch ',
55
+ 'truncate',
56
+ 'mkdir',
57
+ 'mktemp',
58
+ 'rmdir',
59
+ 'rm ',
60
+ 'rm-',
61
+ 'unlink',
62
+ 'mv ',
63
+ 'cp ',
64
+ 'ln -',
65
+ 'chmod',
66
+ 'chown',
67
+ 'chgrp',
68
+ 'tar ',
69
+ 'git add',
70
+ 'git commit',
71
+ 'git apply',
72
+ 'git am',
73
+ 'git rebase',
74
+ 'git checkout',
75
+ 'git merge',
76
+ 'patch <<',
77
+ 'npm install',
78
+ 'pnpm install',
79
+ 'yarn add',
80
+ 'yarn install',
81
+ 'pip install',
82
+ 'pip3 install',
83
+ 'brew install',
84
+ 'cargo add',
85
+ 'cargo install',
86
+ 'go install',
87
+ 'make install'
88
+ ];
89
+ const SHELL_SEARCH_PATTERNS = [
90
+ 'rg ',
91
+ 'rg-',
92
+ 'grep ',
93
+ 'grep-',
94
+ 'ripgrep',
95
+ 'find ',
96
+ 'fd ',
97
+ 'locate ',
98
+ 'search ',
99
+ 'ack ',
100
+ 'ag ',
101
+ 'where ',
102
+ 'which ',
103
+ 'codesearch'
104
+ ];
105
+ const SHELL_READ_PATTERNS = [
106
+ 'ls',
107
+ 'dir ',
108
+ 'pwd',
109
+ 'cat ',
110
+ 'type ',
111
+ 'head ',
112
+ 'tail ',
113
+ 'stat',
114
+ 'tree',
115
+ 'wc ',
116
+ 'du ',
117
+ 'printf "',
118
+ 'python - <<',
119
+ 'python -c',
120
+ 'node - <<',
121
+ 'node -e'
122
+ ];
3
123
  export function buildRoutingFeatures(request, metadata) {
4
124
  const latestUserMessage = getLatestUserMessage(request.messages);
5
125
  const assistantMessages = request.messages.filter((msg) => msg.role === 'assistant');
@@ -7,17 +127,18 @@ export function buildRoutingFeatures(request, metadata) {
7
127
  const normalizedUserText = latestUserText.toLowerCase();
8
128
  const hasTools = Array.isArray(request.tools) && request.tools.length > 0;
9
129
  const hasToolCallResponses = assistantMessages.some((msg) => Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0);
10
- const estimatedTokens = estimateTokens(latestUserText, latestUserText ? 1 : 0);
130
+ const estimatedTokens = computeRequestTokens(request, latestUserText);
11
131
  const hasThinking = detectKeyword(normalizedUserText, THINKING_KEYWORDS);
12
132
  const hasVisionTool = detectVisionTool(request);
13
133
  const hasImageAttachment = hasVisionTool && detectImageAttachment(latestUserMessage);
14
134
  const hasCodingTool = detectCodingTool(request);
15
135
  const hasWebTool = detectWebTool(request);
16
136
  const hasThinkingKeyword = hasThinking || detectExtendedThinkingKeyword(normalizedUserText);
137
+ const lastAssistantTool = detectLastAssistantToolCategory(assistantMessages);
17
138
  return {
18
139
  requestId: metadata.requestId,
19
140
  model: request.model,
20
- totalMessages: latestUserText ? 1 : 0,
141
+ totalMessages: request.messages?.length ?? 0,
21
142
  userTextSample: latestUserText.slice(0, 2000),
22
143
  toolCount: request.tools?.length ?? 0,
23
144
  hasTools,
@@ -28,6 +149,8 @@ export function buildRoutingFeatures(request, metadata) {
28
149
  hasCodingTool,
29
150
  hasThinkingKeyword,
30
151
  estimatedTokens,
152
+ lastAssistantToolCategory: lastAssistantTool?.category,
153
+ lastAssistantToolName: lastAssistantTool?.name,
31
154
  metadata: {
32
155
  ...metadata
33
156
  }
@@ -97,12 +220,15 @@ function detectCodingTool(request) {
97
220
  return false;
98
221
  }
99
222
  return request.tools.some((tool) => {
100
- const functionName = extractToolName(tool);
101
- const description = extractToolDescription(tool);
102
- const chineseDesc = description;
103
- return (/write_file|apply_patch|modify_file|edit_file|create_file|shell|terminal|bash|run_shell/i.test(functionName) ||
104
- /write file|apply patch|modify file|edit file|create file|shell|terminal|bash|run shell/i.test(description || '') ||
105
- /创建文件|修改文件|写入文件|执行shell|执行终端/.test(chineseDesc || ''));
223
+ const functionName = extractToolName(tool).toLowerCase();
224
+ const description = (extractToolDescription(tool) || '').toLowerCase();
225
+ if (!functionName && !description) {
226
+ return false;
227
+ }
228
+ if (WRITE_TOOL_EXACT.has(functionName)) {
229
+ return true;
230
+ }
231
+ return WRITE_TOOL_KEYWORDS.some((keyword) => functionName.includes(keyword.toLowerCase()) || description.includes(keyword.toLowerCase()));
106
232
  });
107
233
  }
108
234
  function detectWebTool(request) {
@@ -125,12 +251,20 @@ function detectExtendedThinkingKeyword(text) {
125
251
  const keywords = ['仔细分析', '思考', '超级思考', '深度思考', 'careful analysis', 'deep thinking', 'deliberate'];
126
252
  return keywords.some((keyword) => text.includes(keyword));
127
253
  }
128
- function estimateTokens(text, messageCount) {
254
+ function computeRequestTokens(request, fallbackText) {
255
+ try {
256
+ return countRequestTokens(request);
257
+ }
258
+ catch {
259
+ return fallbackEstimateTokens(fallbackText, request.messages?.length ?? 0);
260
+ }
261
+ }
262
+ function fallbackEstimateTokens(text, messageCount) {
129
263
  if (!text) {
130
- return Math.max(32, messageCount * 16);
264
+ return Math.max(32, Math.max(messageCount, 1) * 16);
131
265
  }
132
266
  const rough = Math.ceil(text.length / 4);
133
- return Math.max(rough, messageCount * 32);
267
+ return Math.max(rough, Math.max(messageCount, 1) * 32);
134
268
  }
135
269
  function extractToolName(tool) {
136
270
  if (!tool || typeof tool !== 'object') {
@@ -160,3 +294,198 @@ function extractToolDescription(tool) {
160
294
  }
161
295
  return '';
162
296
  }
297
+ function detectLastAssistantToolCategory(messages) {
298
+ for (let idx = messages.length - 1; idx >= 0; idx -= 1) {
299
+ const msg = messages[idx];
300
+ if (!msg || !Array.isArray(msg.tool_calls) || msg.tool_calls.length === 0) {
301
+ continue;
302
+ }
303
+ let fallback;
304
+ for (const call of msg.tool_calls) {
305
+ const classification = classifyToolCall(call);
306
+ if (!classification) {
307
+ continue;
308
+ }
309
+ if (!fallback) {
310
+ fallback = classification;
311
+ }
312
+ if (classification.category !== 'other') {
313
+ return classification;
314
+ }
315
+ }
316
+ if (fallback) {
317
+ return fallback;
318
+ }
319
+ }
320
+ return undefined;
321
+ }
322
+ function classifyToolCall(call) {
323
+ if (!call || typeof call !== 'object') {
324
+ return undefined;
325
+ }
326
+ const functionName = typeof call?.function?.name === 'string' && call.function.name.trim()
327
+ ? canonicalizeToolName(call.function.name)
328
+ : '';
329
+ if (!functionName) {
330
+ return undefined;
331
+ }
332
+ const argsObject = parseToolArguments(call?.function?.arguments);
333
+ const commandText = extractCommandText(argsObject);
334
+ const nameCategory = categorizeToolName(functionName);
335
+ if (nameCategory === 'write' || nameCategory === 'read' || nameCategory === 'search') {
336
+ return { category: nameCategory, name: functionName };
337
+ }
338
+ if (SHELL_TOOL_NAMES.has(functionName)) {
339
+ const shellCategory = classifyShellCommand(commandText);
340
+ return { category: shellCategory, name: functionName };
341
+ }
342
+ if (commandText) {
343
+ const derivedCategory = classifyShellCommand(commandText);
344
+ if (derivedCategory !== 'other') {
345
+ return { category: derivedCategory, name: functionName };
346
+ }
347
+ }
348
+ return { category: 'other', name: functionName };
349
+ }
350
+ function canonicalizeToolName(rawName) {
351
+ const trimmed = rawName.trim();
352
+ const markerIndex = trimmed.indexOf('arg_');
353
+ if (markerIndex > 0) {
354
+ return trimmed.slice(0, markerIndex);
355
+ }
356
+ return trimmed;
357
+ }
358
+ function parseToolArguments(rawArguments) {
359
+ if (!rawArguments) {
360
+ return undefined;
361
+ }
362
+ if (typeof rawArguments === 'string') {
363
+ try {
364
+ return JSON.parse(rawArguments);
365
+ }
366
+ catch {
367
+ return rawArguments;
368
+ }
369
+ }
370
+ if (typeof rawArguments === 'object') {
371
+ return rawArguments;
372
+ }
373
+ return undefined;
374
+ }
375
+ function extractCommandText(args) {
376
+ if (!args) {
377
+ return '';
378
+ }
379
+ if (typeof args === 'string') {
380
+ return args;
381
+ }
382
+ if (Array.isArray(args)) {
383
+ return args.map((item) => (typeof item === 'string' ? item : '')).filter(Boolean).join(' ');
384
+ }
385
+ if (typeof args === 'object') {
386
+ const record = args;
387
+ const command = record.command;
388
+ const input = record.input;
389
+ const nestedArgs = record.args;
390
+ if (typeof command === 'string') {
391
+ return command;
392
+ }
393
+ if (Array.isArray(command)) {
394
+ return command.map((item) => (typeof item === 'string' ? item : '')).filter(Boolean).join(' ');
395
+ }
396
+ if (typeof input === 'string') {
397
+ return input;
398
+ }
399
+ if (typeof nestedArgs === 'string') {
400
+ return nestedArgs;
401
+ }
402
+ if (Array.isArray(nestedArgs)) {
403
+ return nestedArgs.map((item) => (typeof item === 'string' ? item : '')).filter(Boolean).join(' ');
404
+ }
405
+ }
406
+ return '';
407
+ }
408
+ function categorizeToolName(name) {
409
+ const normalized = name.toLowerCase();
410
+ if (SEARCH_TOOL_EXACT.has(normalized) ||
411
+ SEARCH_TOOL_KEYWORDS.some((keyword) => normalized.includes(keyword.toLowerCase()))) {
412
+ return 'search';
413
+ }
414
+ if (READ_TOOL_EXACT.has(normalized) ||
415
+ READ_TOOL_KEYWORDS.some((keyword) => normalized.includes(keyword.toLowerCase()))) {
416
+ return 'read';
417
+ }
418
+ if (WRITE_TOOL_EXACT.has(normalized) ||
419
+ WRITE_TOOL_KEYWORDS.some((keyword) => normalized.includes(keyword.toLowerCase()))) {
420
+ return 'write';
421
+ }
422
+ return 'other';
423
+ }
424
+ function classifyShellCommand(command) {
425
+ if (!command) {
426
+ return 'other';
427
+ }
428
+ if (SHELL_HEREDOC_PATTERN.test(command)) {
429
+ return 'write';
430
+ }
431
+ const segments = splitCommandSegments(command).map(stripShellWrapper);
432
+ if (segments.some((segment) => matchesAnyPattern(segment, SHELL_WRITE_PATTERNS))) {
433
+ return 'write';
434
+ }
435
+ if (segments.some((segment) => matchesAnyPattern(segment, SHELL_SEARCH_PATTERNS))) {
436
+ return 'search';
437
+ }
438
+ if (segments.some((segment) => matchesAnyPattern(segment, SHELL_READ_PATTERNS))) {
439
+ return 'read';
440
+ }
441
+ const stripped = stripShellWrapper(command);
442
+ if (matchesAnyPattern(stripped, SHELL_WRITE_PATTERNS)) {
443
+ return 'write';
444
+ }
445
+ if (matchesAnyPattern(stripped, SHELL_SEARCH_PATTERNS)) {
446
+ return 'search';
447
+ }
448
+ if (matchesAnyPattern(stripped, SHELL_READ_PATTERNS)) {
449
+ return 'read';
450
+ }
451
+ return 'other';
452
+ }
453
+ function splitCommandSegments(command) {
454
+ return command
455
+ .split(/(?:\r?\n|&&|\|\||;)/)
456
+ .map((segment) => segment.trim())
457
+ .filter(Boolean);
458
+ }
459
+ function matchesAnyPattern(text, patterns) {
460
+ if (!text) {
461
+ return false;
462
+ }
463
+ const trimmed = text.trim().toLowerCase();
464
+ const normalized = trimmed.startsWith('sudo ') ? trimmed.slice(5).trim() : trimmed;
465
+ return patterns.some((pattern) => {
466
+ const lowered = pattern.toLowerCase().trim();
467
+ return normalized.startsWith(lowered);
468
+ });
469
+ }
470
+ function stripShellWrapper(segment) {
471
+ let normalized = segment.trim();
472
+ const wrappers = ['bash -lc ', 'bash -lc', 'sh -c ', 'sh -c', '/bin/sh -c ', '/bin/sh -c', 'env -i bash -lc ', 'env -i bash -lc'];
473
+ for (const wrapper of wrappers) {
474
+ if (normalized.toLowerCase().startsWith(wrapper)) {
475
+ normalized = normalized.slice(wrapper.length).trim();
476
+ break;
477
+ }
478
+ }
479
+ normalized = trimEnclosingQuotes(normalized);
480
+ if (normalized.startsWith('sudo ')) {
481
+ normalized = normalized.slice(5).trim();
482
+ }
483
+ return normalized;
484
+ }
485
+ function trimEnclosingQuotes(value) {
486
+ if ((value.startsWith('"') && value.endsWith('"') && value.length > 1) ||
487
+ (value.startsWith("'") && value.endsWith("'") && value.length > 1)) {
488
+ return value.slice(1, -1).trim();
489
+ }
490
+ return value;
491
+ }
@@ -0,0 +1,2 @@
1
+ import type { StandardizedRequest } from '../../conversion/hub/types/standardized.js';
2
+ export declare function countRequestTokens(request: StandardizedRequest): number;
@@ -0,0 +1,105 @@
1
+ import { encoding_for_model, get_encoding } from 'tiktoken';
2
+ const DEFAULT_ENCODING = 'cl100k_base';
3
+ const encoderCache = new Map();
4
+ let defaultEncoder = null;
5
+ function getEncoder(model) {
6
+ if (model) {
7
+ const normalized = model.trim();
8
+ if (encoderCache.has(normalized)) {
9
+ return encoderCache.get(normalized);
10
+ }
11
+ try {
12
+ const encoder = encoding_for_model(normalized);
13
+ encoderCache.set(normalized, encoder);
14
+ return encoder;
15
+ }
16
+ catch {
17
+ // fall back to default encoder
18
+ }
19
+ }
20
+ if (!defaultEncoder) {
21
+ defaultEncoder = get_encoding(DEFAULT_ENCODING);
22
+ }
23
+ return defaultEncoder;
24
+ }
25
+ export function countRequestTokens(request) {
26
+ const encoder = getEncoder(request.model);
27
+ let total = 0;
28
+ for (const message of request.messages || []) {
29
+ total += countMessageTokens(message, encoder);
30
+ }
31
+ if (Array.isArray(request.tools)) {
32
+ for (const tool of request.tools) {
33
+ total += encodeText(JSON.stringify(tool ?? {}), encoder);
34
+ }
35
+ }
36
+ if (request.parameters) {
37
+ total += encodeText(JSON.stringify(request.parameters), encoder);
38
+ }
39
+ if (request.metadata) {
40
+ total += encodeText(JSON.stringify(request.metadata), encoder);
41
+ }
42
+ return total;
43
+ }
44
+ function countMessageTokens(message, encoder) {
45
+ let total = 0;
46
+ total += encodeText(message.role, encoder);
47
+ total += encodeContent(message.content, encoder);
48
+ if (Array.isArray(message.tool_calls)) {
49
+ for (const call of message.tool_calls) {
50
+ total += encodeText(JSON.stringify(call ?? {}), encoder);
51
+ }
52
+ }
53
+ if (Array.isArray(message.metadata?.toolRuns)) {
54
+ total += encodeText(JSON.stringify(message.metadata?.toolRuns), encoder);
55
+ }
56
+ if (message.name) {
57
+ total += encodeText(message.name, encoder);
58
+ }
59
+ if (message.metadata) {
60
+ total += encodeText(JSON.stringify(message.metadata), encoder);
61
+ }
62
+ if (message.tool_call_id) {
63
+ total += encodeText(message.tool_call_id, encoder);
64
+ }
65
+ return total;
66
+ }
67
+ function encodeContent(content, encoder) {
68
+ if (content === null || content === undefined) {
69
+ return 0;
70
+ }
71
+ if (typeof content === 'string') {
72
+ return encodeText(content, encoder);
73
+ }
74
+ if (Array.isArray(content)) {
75
+ let total = 0;
76
+ for (const part of content) {
77
+ if (typeof part === 'string') {
78
+ total += encodeText(part, encoder);
79
+ }
80
+ else if (part && typeof part === 'object') {
81
+ if (typeof part.text === 'string') {
82
+ total += encodeText(part.text, encoder);
83
+ }
84
+ else {
85
+ total += encodeText(JSON.stringify(part), encoder);
86
+ }
87
+ }
88
+ }
89
+ return total;
90
+ }
91
+ if (typeof content === 'object') {
92
+ return encodeText(JSON.stringify(content), encoder);
93
+ }
94
+ return encodeText(String(content), encoder);
95
+ }
96
+ function encodeText(value, encoder) {
97
+ if (value === null || value === undefined) {
98
+ return 0;
99
+ }
100
+ const text = typeof value === 'string' ? value : String(value);
101
+ if (!text.trim()) {
102
+ return 0;
103
+ }
104
+ return encoder.encode(text).length;
105
+ }
@@ -96,6 +96,11 @@ export interface RouterMetadataInput {
96
96
  providerProtocol?: string;
97
97
  stage?: 'inbound' | 'outbound' | 'response';
98
98
  routeHint?: string;
99
+ responsesResume?: {
100
+ previousRequestId?: string;
101
+ restoredFromResponseId?: string;
102
+ [key: string]: unknown;
103
+ };
99
104
  }
100
105
  export interface RoutingFeatures {
101
106
  requestId: string;
@@ -111,6 +116,8 @@ export interface RoutingFeatures {
111
116
  hasCodingTool: boolean;
112
117
  hasThinkingKeyword: boolean;
113
118
  estimatedTokens: number;
119
+ lastAssistantToolCategory?: 'read' | 'write' | 'search' | 'other';
120
+ lastAssistantToolName?: string;
114
121
  metadata: RouterMetadataInput;
115
122
  }
116
123
  export interface ClassificationResult {
@@ -203,6 +210,7 @@ export interface ProviderErrorEvent {
203
210
  stage: string;
204
211
  status?: number;
205
212
  recoverable?: boolean;
213
+ affectsHealth?: boolean;
206
214
  runtime: ProviderErrorRuntimeMetadata;
207
215
  timestamp: number;
208
216
  details?: Record<string, unknown>;
@@ -4,11 +4,11 @@
4
4
  export const DEFAULT_ROUTE = 'default';
5
5
  export const ROUTE_PRIORITY = [
6
6
  'vision',
7
+ 'longcontext',
7
8
  'websearch',
8
9
  'coding',
9
- 'tools',
10
- 'longcontext',
11
10
  'thinking',
11
+ 'tools',
12
12
  'background',
13
13
  DEFAULT_ROUTE
14
14
  ];
@@ -77,6 +77,8 @@ export declare class ResponsesResponseBuilder {
77
77
  * 处理function_call.start事件
78
78
  */
79
79
  private handleFunctionCallStart;
80
+ private coerceArgumentsChunk;
81
+ private shouldOverrideArguments;
80
82
  /**
81
83
  * 处理function_call.delta事件
82
84
  */
@@ -112,6 +112,7 @@ export class ResponsesResponseBuilder {
112
112
  this.handleOutputItemDone(event);
113
113
  break;
114
114
  case 'required_action':
115
+ case 'response.required_action':
115
116
  this.handleRequiredAction(event);
116
117
  break;
117
118
  case 'response.done':
@@ -395,6 +396,36 @@ export class ResponsesResponseBuilder {
395
396
  outputItemState.arguments = '';
396
397
  outputItemState.lastEventTime = event.timestamp;
397
398
  }
399
+ coerceArgumentsChunk(raw) {
400
+ if (typeof raw === 'string') {
401
+ return raw;
402
+ }
403
+ if (raw && typeof raw === 'object') {
404
+ try {
405
+ return JSON.stringify(raw);
406
+ }
407
+ catch {
408
+ return String(raw);
409
+ }
410
+ }
411
+ return undefined;
412
+ }
413
+ shouldOverrideArguments(current, incoming) {
414
+ if (!incoming) {
415
+ return false;
416
+ }
417
+ const trimmed = incoming.trim();
418
+ if (!current || !current.length) {
419
+ return trimmed.length > 0;
420
+ }
421
+ if (!trimmed.length) {
422
+ return false;
423
+ }
424
+ if (trimmed === '{}' || trimmed.toLowerCase() === 'null') {
425
+ return false;
426
+ }
427
+ return true;
428
+ }
398
429
  /**
399
430
  * 处理function_call.delta事件
400
431
  */
@@ -404,10 +435,10 @@ export class ResponsesResponseBuilder {
404
435
  if (!outputItemState) {
405
436
  throw new Error(`Output item not found: ${data.item_id}`);
406
437
  }
407
- const chunk = (data && data.delta && typeof data.delta === 'object' && typeof data.delta.arguments === 'string')
408
- ? String(data.delta.arguments)
409
- : (typeof (data?.delta) === 'string' ? String(data.delta) : (typeof data?.arguments === 'string' ? String(data.arguments) : undefined));
410
- if (typeof chunk === 'string') {
438
+ const chunk = this.coerceArgumentsChunk(data?.delta?.arguments) ??
439
+ this.coerceArgumentsChunk(data?.delta) ??
440
+ this.coerceArgumentsChunk(data?.arguments);
441
+ if (chunk) {
411
442
  outputItemState.arguments = (outputItemState.arguments || '') + chunk;
412
443
  }
413
444
  outputItemState.lastEventTime = event.timestamp;
@@ -445,8 +476,16 @@ export class ResponsesResponseBuilder {
445
476
  outputItemState.name = data.name;
446
477
  if (typeof data.call_id === 'string' && data.call_id)
447
478
  outputItemState.callId = data.call_id;
448
- if (typeof data.arguments === 'string' && data.arguments)
449
- outputItemState.arguments = data.arguments;
479
+ const finalChunk = this.coerceArgumentsChunk(data?.arguments) ??
480
+ this.coerceArgumentsChunk(data?.delta?.arguments) ??
481
+ this.coerceArgumentsChunk(data?.delta);
482
+ if (this.shouldOverrideArguments(outputItemState.arguments, finalChunk)) {
483
+ outputItemState.arguments = finalChunk;
484
+ }
485
+ else if (!outputItemState.arguments && finalChunk) {
486
+ // 没有任何累计增量时,保底写入 done 事件里的值
487
+ outputItemState.arguments = finalChunk;
488
+ }
450
489
  }
451
490
  catch { /* ignore */ }
452
491
  outputItemState.status = 'completed';
@@ -630,14 +669,17 @@ export class ResponsesResponseBuilder {
630
669
  this.state = 'error';
631
670
  }
632
671
  handleResponseCompleted(event) {
633
- const data = event.data;
634
- if (data?.usage) {
635
- this.response.usage = data.usage;
672
+ const payload = event.data?.response ?? event.data;
673
+ const usage = (payload && payload.usage)
674
+ ? payload.usage
675
+ : event.data?.usage;
676
+ if (usage) {
677
+ this.response.usage = usage;
636
678
  }
637
679
  // 标准化完成态:部分上游的 response.completed 不包含 status 字段
638
680
  // 若未提供明确的完成状态,统一标记为 'completed',而不是沿用之前的 in_progress。
639
- this.response.status = (data && data.status != null)
640
- ? data.status
681
+ this.response.status = (payload && payload.status != null)
682
+ ? payload.status
641
683
  : 'completed';
642
684
  // 将已聚合的输出写回并标记完成(若为空数组也重建)
643
685
  try {
@@ -0,0 +1,12 @@
1
+ {
2
+ "samplesRoot": "/Users/fanzhang/.routecodex/codex-samples",
3
+ "configPath": "/Users/fanzhang/Documents/github/sharedmodule/llmswitch-core/test/virtual-router/virtual-router.config.json",
4
+ "stats": {
5
+ "totalSamples": 0,
6
+ "processed": 0,
7
+ "routes": {},
8
+ "providers": {},
9
+ "errors": [],
10
+ "scenarios": {}
11
+ }
12
+ }