@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.
- package/README.md +240 -179
- package/config/modules.json +1 -11
- package/dist/build-info.js +2 -2
- package/dist/build-info.js.map +1 -1
- package/dist/client/gemini-cli/gemini-cli-protocol-client.d.ts +16 -0
- package/dist/client/gemini-cli/gemini-cli-protocol-client.js +56 -0
- package/dist/client/gemini-cli/gemini-cli-protocol-client.js.map +1 -0
- package/dist/client/openai/chat-protocol-client.js.map +1 -1
- package/dist/config/modules.json +1 -11
- package/dist/core/provider-health-manager.d.ts +17 -0
- package/dist/core/provider-health-manager.js +66 -0
- package/dist/core/provider-health-manager.js.map +1 -0
- package/dist/error-handling/route-error-hub.d.ts +48 -0
- package/dist/error-handling/route-error-hub.js +131 -0
- package/dist/error-handling/route-error-hub.js.map +1 -0
- package/dist/index.js +26 -1
- package/dist/index.js.map +1 -1
- package/dist/modules/llmswitch/bridge.d.ts +2 -0
- package/dist/modules/llmswitch/bridge.js +17 -0
- package/dist/modules/llmswitch/bridge.js.map +1 -1
- package/dist/modules/pipeline/utils/colored-logger.d.ts +14 -0
- package/dist/modules/pipeline/utils/colored-logger.js +48 -0
- package/dist/modules/pipeline/utils/colored-logger.js.map +1 -0
- package/dist/modules/pipeline/utils/debug-logger.d.ts +2 -0
- package/dist/modules/pipeline/utils/debug-logger.js +36 -0
- package/dist/modules/pipeline/utils/debug-logger.js.map +1 -1
- package/dist/providers/auth/gemini-cli-userinfo-helper.d.ts +53 -0
- package/dist/providers/auth/gemini-cli-userinfo-helper.js +152 -0
- package/dist/providers/auth/gemini-cli-userinfo-helper.js.map +1 -0
- package/dist/providers/auth/oauth-auth.js +3 -2
- package/dist/providers/auth/oauth-auth.js.map +1 -1
- package/dist/providers/auth/oauth-lifecycle.js +21 -20
- package/dist/providers/auth/oauth-lifecycle.js.map +1 -1
- package/dist/providers/auth/oauth-logger.d.ts +1 -0
- package/dist/providers/auth/oauth-logger.js +21 -0
- package/dist/providers/auth/oauth-logger.js.map +1 -0
- package/dist/providers/compat/compat-directory-loader.js +2 -55
- package/dist/providers/compat/compat-directory-loader.js.map +1 -1
- package/dist/providers/compat/compatibility-factory.d.ts +4 -4
- package/dist/providers/compat/compatibility-factory.js +108 -0
- package/dist/providers/compat/compatibility-factory.js.map +1 -1
- package/dist/providers/compat/glm/glm-compatibility.d.ts +2 -2
- package/dist/providers/compat/glm/glm-compatibility.js +7 -7
- package/dist/providers/compat/glm/glm-compatibility.js.map +1 -1
- package/dist/providers/compat/glm/index.js +0 -6
- package/dist/providers/compat/glm/index.js.map +1 -1
- package/dist/providers/compat/iflow/iflow-compatibility.d.ts +1 -1
- package/dist/providers/compat/iflow/iflow-compatibility.js +6 -6
- package/dist/providers/compat/iflow/iflow-compatibility.js.map +1 -1
- package/dist/providers/compat/index.d.ts +0 -6
- package/dist/providers/compat/index.js +0 -7
- package/dist/providers/compat/index.js.map +1 -1
- package/dist/providers/compat/lmstudio-compatibility.d.ts +2 -2
- package/dist/providers/compat/lmstudio-compatibility.js +4 -4
- package/dist/providers/compat/lmstudio-compatibility.js.map +1 -1
- package/dist/providers/compat/passthrough-compatibility.d.ts +1 -1
- package/dist/providers/compat/passthrough-compatibility.js +3 -3
- package/dist/providers/compat/passthrough-compatibility.js.map +1 -1
- package/dist/providers/compat/profiles/chat/glm/index.d.ts +6 -0
- package/dist/providers/compat/profiles/chat/glm/index.js +6 -0
- package/dist/providers/compat/profiles/chat/glm/index.js.map +1 -0
- package/dist/providers/compat/profiles/chat/iflow/index.d.ts +6 -0
- package/dist/providers/compat/profiles/chat/iflow/index.js +6 -0
- package/dist/providers/compat/profiles/chat/iflow/index.js.map +1 -0
- package/dist/providers/compat/profiles/chat/lmstudio/index.d.ts +6 -0
- package/dist/providers/compat/profiles/chat/lmstudio/index.js +6 -0
- package/dist/providers/compat/profiles/chat/lmstudio/index.js.map +1 -0
- package/dist/providers/compat/profiles/chat/qwen/index.d.ts +6 -0
- package/dist/providers/compat/profiles/chat/qwen/index.js +6 -0
- package/dist/providers/compat/profiles/chat/qwen/index.js.map +1 -0
- package/dist/providers/compat/profiles/compat/passthrough/index.d.ts +6 -0
- package/dist/providers/compat/profiles/compat/passthrough/index.js +6 -0
- package/dist/providers/compat/profiles/compat/passthrough/index.js.map +1 -0
- package/dist/providers/compat/profiles/responses/c4m/index.d.ts +6 -0
- package/dist/providers/compat/profiles/responses/c4m/index.js +6 -0
- package/dist/providers/compat/profiles/responses/c4m/index.js.map +1 -0
- package/dist/providers/compat/profiles/responses/default/index.d.ts +6 -0
- package/dist/providers/compat/profiles/responses/default/index.js +6 -0
- package/dist/providers/compat/profiles/responses/default/index.js.map +1 -0
- package/dist/providers/compat/profiles/responses/fai/index.d.ts +6 -0
- package/dist/providers/compat/profiles/responses/fai/index.js +6 -0
- package/dist/providers/compat/profiles/responses/fai/index.js.map +1 -0
- package/dist/providers/compat/profiles/responses/fc/index.d.ts +6 -0
- package/dist/providers/compat/profiles/responses/fc/index.js +6 -0
- package/dist/providers/compat/profiles/responses/fc/index.js.map +1 -0
- package/dist/providers/compat/qwen/index.js +0 -6
- package/dist/providers/compat/qwen/index.js.map +1 -1
- package/dist/providers/compat/qwen-compatibility.d.ts +2 -2
- package/dist/providers/compat/qwen-compatibility.js +4 -4
- package/dist/providers/compat/qwen-compatibility.js.map +1 -1
- package/dist/providers/compat/register-compat-module.d.ts +8 -0
- package/dist/providers/compat/register-compat-module.js +53 -0
- package/dist/providers/compat/register-compat-module.js.map +1 -0
- package/dist/providers/compat/responses/c4m-responses-compatibility.d.ts +6 -2
- package/dist/providers/compat/responses/c4m-responses-compatibility.js +85 -3
- package/dist/providers/compat/responses/c4m-responses-compatibility.js.map +1 -1
- package/dist/providers/compat/standard-compatibility-utils.js +45 -15
- package/dist/providers/compat/standard-compatibility-utils.js.map +1 -1
- package/dist/providers/core/api/provider-config.d.ts +1 -1
- package/dist/providers/core/api/provider-types.d.ts +3 -1
- package/dist/providers/core/api/provider-types.js +1 -0
- package/dist/providers/core/api/provider-types.js.map +1 -1
- package/dist/providers/core/config/service-profiles.js +5 -2
- package/dist/providers/core/config/service-profiles.js.map +1 -1
- package/dist/providers/core/runtime/base-provider.d.ts +3 -0
- package/dist/providers/core/runtime/base-provider.js +101 -6
- package/dist/providers/core/runtime/base-provider.js.map +1 -1
- package/dist/providers/core/runtime/gemini-cli-http-provider.d.ts +34 -0
- package/dist/providers/core/runtime/gemini-cli-http-provider.js +152 -0
- package/dist/providers/core/runtime/gemini-cli-http-provider.js.map +1 -0
- package/dist/providers/core/runtime/http-transport-provider.d.ts +1 -0
- package/dist/providers/core/runtime/http-transport-provider.js +178 -123
- package/dist/providers/core/runtime/http-transport-provider.js.map +1 -1
- package/dist/providers/core/runtime/provider-factory.d.ts +1 -1
- package/dist/providers/core/runtime/provider-factory.js +8 -0
- package/dist/providers/core/runtime/provider-factory.js.map +1 -1
- package/dist/providers/core/runtime/provider-runtime-metadata.d.ts +1 -0
- package/dist/providers/core/runtime/provider-runtime-metadata.js.map +1 -1
- package/dist/providers/core/runtime/responses-provider.d.ts +7 -0
- package/dist/providers/core/runtime/responses-provider.js +228 -12
- package/dist/providers/core/runtime/responses-provider.js.map +1 -1
- package/dist/providers/core/strategies/oauth-auth-code-flow.js +10 -9
- package/dist/providers/core/strategies/oauth-auth-code-flow.js.map +1 -1
- package/dist/providers/core/strategies/oauth-device-flow.js +10 -9
- package/dist/providers/core/strategies/oauth-device-flow.js.map +1 -1
- package/dist/providers/core/utils/provider-error-reporter.js +63 -15
- package/dist/providers/core/utils/provider-error-reporter.js.map +1 -1
- package/dist/providers/core/utils/provider-type-utils.d.ts +1 -1
- package/dist/providers/core/utils/provider-type-utils.js +6 -1
- package/dist/providers/core/utils/provider-type-utils.js.map +1 -1
- package/dist/providers/core/utils/snapshot-writer.d.ts +10 -0
- package/dist/providers/core/utils/snapshot-writer.js +85 -0
- package/dist/providers/core/utils/snapshot-writer.js.map +1 -1
- package/dist/providers/mock/mock-provider-runtime.js +44 -0
- package/dist/providers/mock/mock-provider-runtime.js.map +1 -1
- package/dist/providers/profile/provider-profile-loader.js +26 -19
- package/dist/providers/profile/provider-profile-loader.js.map +1 -1
- package/dist/providers/profile/provider-profile.d.ts +2 -2
- package/dist/server/handlers/chat-handler.js +9 -3
- package/dist/server/handlers/chat-handler.js.map +1 -1
- package/dist/server/handlers/handler-utils.d.ts +7 -1
- package/dist/server/handlers/handler-utils.js +64 -52
- package/dist/server/handlers/handler-utils.js.map +1 -1
- package/dist/server/handlers/messages-handler.js +9 -3
- package/dist/server/handlers/messages-handler.js.map +1 -1
- package/dist/server/handlers/responses-handler.js +21 -13
- package/dist/server/handlers/responses-handler.js.map +1 -1
- package/dist/server/runtime/http-server/colored-logger.d.ts +1 -0
- package/dist/server/runtime/http-server/colored-logger.js +33 -0
- package/dist/server/runtime/http-server/colored-logger.js.map +1 -0
- package/dist/server/runtime/http-server/index.d.ts +3 -0
- package/dist/server/runtime/http-server/index.js +76 -19
- package/dist/server/runtime/http-server/index.js.map +1 -1
- package/dist/server/runtime/http-server/provider-utils.d.ts +3 -1
- package/dist/server/runtime/http-server/provider-utils.js +12 -2
- package/dist/server/runtime/http-server/provider-utils.js.map +1 -1
- package/dist/server/runtime/http-server/request-executor.js +6 -2
- package/dist/server/runtime/http-server/request-executor.js.map +1 -1
- package/dist/server/runtime/http-server/routes.js +31 -11
- package/dist/server/runtime/http-server/routes.js.map +1 -1
- package/dist/server/runtime/http-server/types.d.ts +2 -1
- package/dist/utils/error-center-payload.d.ts +7 -0
- package/dist/utils/error-center-payload.js +67 -0
- package/dist/utils/error-center-payload.js.map +1 -0
- package/dist/utils/error-handler-registry.d.ts +7 -0
- package/dist/utils/error-handler-registry.js +44 -12
- package/dist/utils/error-handler-registry.js.map +1 -1
- package/node_modules/@jsonstudio/llms/dist/conversion/codecs/responses-openai-codec.js +16 -1
- package/node_modules/@jsonstudio/llms/dist/conversion/compat/profiles/chat-glm.json +17 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/compat/profiles/chat-iflow.json +36 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/compat/profiles/chat-lmstudio.json +37 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/compat/profiles/chat-qwen.json +18 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/compat/profiles/responses-c4m.json +45 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/config/compat-profiles.json +38 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/config/sample-config.json +314 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/config/version-switch.json +150 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/compat/compat-engine.d.ts +4 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/compat/compat-engine.js +667 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/compat/compat-profile-store.d.ts +2 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/compat/compat-profile-store.js +76 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/compat/compat-types.d.ts +62 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/compat/compat-types.js +1 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/hub-pipeline.d.ts +2 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/hub-pipeline.js +110 -29
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage3_compat/index.d.ts +14 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage3_compat/index.js +23 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage1_client_remap/index.js +34 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/process/chat-process.js +4 -1
- package/node_modules/@jsonstudio/llms/dist/conversion/hub/response/provider-response.js +26 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/responses/responses-openai-bridge.d.ts +1 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/responses/responses-openai-bridge.js +71 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/shared/responses-conversation-store.d.ts +35 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/shared/responses-conversation-store.js +64 -19
- package/node_modules/@jsonstudio/llms/dist/conversion/shared/tool-filter-pipeline.d.ts +21 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/shared/tool-filter-pipeline.js +138 -22
- package/node_modules/@jsonstudio/llms/dist/conversion/shared/tool-governor.d.ts +21 -0
- package/node_modules/@jsonstudio/llms/dist/conversion/shared/tool-governor.js +116 -1
- package/node_modules/@jsonstudio/llms/dist/conversion/shared/tool-mapping.js +52 -2
- package/node_modules/@jsonstudio/llms/dist/filters/config/openai-openai.fieldmap.json +18 -0
- package/node_modules/@jsonstudio/llms/dist/filters/special/request-tools-normalize.js +20 -1
- package/node_modules/@jsonstudio/llms/dist/guidance/index.js +6 -2
- package/node_modules/@jsonstudio/llms/dist/router/virtual-router/bootstrap.js +16 -7
- package/node_modules/@jsonstudio/llms/dist/router/virtual-router/classifier.js +40 -37
- package/node_modules/@jsonstudio/llms/dist/router/virtual-router/default-thinking-keywords.d.ts +1 -0
- package/node_modules/@jsonstudio/llms/dist/router/virtual-router/default-thinking-keywords.js +13 -0
- package/node_modules/@jsonstudio/llms/dist/router/virtual-router/engine.d.ts +39 -0
- package/node_modules/@jsonstudio/llms/dist/router/virtual-router/engine.js +52 -11
- package/node_modules/@jsonstudio/llms/dist/router/virtual-router/features.js +340 -11
- package/node_modules/@jsonstudio/llms/dist/router/virtual-router/token-counter.d.ts +2 -0
- package/node_modules/@jsonstudio/llms/dist/router/virtual-router/token-counter.js +105 -0
- package/node_modules/@jsonstudio/llms/dist/router/virtual-router/types.d.ts +8 -0
- package/node_modules/@jsonstudio/llms/dist/router/virtual-router/types.js +2 -2
- package/node_modules/@jsonstudio/llms/dist/sse/sse-to-json/builders/response-builder.d.ts +2 -0
- package/node_modules/@jsonstudio/llms/dist/sse/sse-to-json/builders/response-builder.js +53 -11
- package/node_modules/@jsonstudio/llms/dist/test-output/virtual-router/results.json +1 -0
- package/node_modules/@jsonstudio/llms/dist/test-output/virtual-router/summary.json +12 -0
- package/node_modules/@jsonstudio/llms/dist/tools/tool-registry.js +4 -3
- package/node_modules/@jsonstudio/llms/package.json +3 -3
- package/package.json +11 -9
- package/scripts/analyze-routing-classifier.mjs +166 -0
- package/scripts/analyze-routing-samples.mjs +216 -0
- package/scripts/analyze-thinking-keywords.mjs +17 -2
- package/scripts/build-core.mjs +8 -0
- package/scripts/classify-sample-tools.mjs +252 -0
- package/scripts/ensure-llmswitch-mode.mjs +95 -0
- package/scripts/gen-build-info.mjs +58 -4
- package/scripts/install-global.sh +1 -1
- package/scripts/install-release.sh +7 -0
- package/scripts/mock-provider/run-regressions.mjs +60 -14
- package/scripts/tests/apply-patch-loop.mjs +100 -9
- package/scripts/tests/golden-provider-cycle.mjs +12 -1
- package/scripts/tests/responses-provider-dry-run.mjs +15 -1
- package/scripts/tests/virtual-router-health.mjs +12 -5
- package/scripts/tools/capture-provider-goldens.mjs +75 -25
- package/scripts/tools/responses-golden-dry-run.mjs +17 -1
- package/scripts/tools/responses-provider-replay.mjs +17 -1
- package/scripts/tools/sync-ci-goldens.mjs +131 -0
- package/scripts/verification/samples/openai-chat-list-local-files.json +19 -796
- package/scripts/verify-e2e-toolcall.mjs +52 -0
- package/dist/providers/compat/config/index.d.ts +0 -1
- package/dist/providers/compat/config/index.js +0 -5
- package/dist/providers/compat/config/index.js.map +0 -1
- package/dist/providers/compat/iflow/index.d.ts +0 -27
- package/dist/providers/compat/iflow/index.js +0 -32
- package/dist/providers/compat/iflow/index.js.map +0 -1
- package/dist/providers/compat/lmstudio/index.d.ts +0 -4
- package/dist/providers/compat/lmstudio/index.js +0 -10
- package/dist/providers/compat/lmstudio/index.js.map +0 -1
- package/dist/providers/compat/passthrough/index.d.ts +0 -4
- package/dist/providers/compat/passthrough/index.js +0 -9
- package/dist/providers/compat/passthrough/index.js.map +0 -1
- package/dist/providers/compat/responses/index.d.ts +0 -1
- package/dist/providers/compat/responses/index.js +0 -8
- package/dist/providers/compat/responses/index.js.map +0 -1
- package/dist/providers/core/composite/compat/anthropic.d.ts +0 -3
- package/dist/providers/core/composite/compat/anthropic.js +0 -7
- package/dist/providers/core/composite/compat/anthropic.js.map +0 -1
- package/dist/providers/core/composite/compat/gemini.d.ts +0 -3
- package/dist/providers/core/composite/compat/gemini.js +0 -7
- package/dist/providers/core/composite/compat/gemini.js.map +0 -1
- package/dist/providers/core/composite/compat/openai-compat-aggregator.d.ts +0 -9
- package/dist/providers/core/composite/compat/openai-compat-aggregator.js +0 -135
- package/dist/providers/core/composite/compat/openai-compat-aggregator.js.map +0 -1
- package/dist/providers/core/composite/compat/responses.d.ts +0 -3
- package/dist/providers/core/composite/compat/responses.js +0 -91
- package/dist/providers/core/composite/compat/responses.js.map +0 -1
- package/dist/providers/core/composite/provider-composite.d.ts +0 -50
- package/dist/providers/core/composite/provider-composite.js +0 -235
- package/dist/providers/core/composite/provider-composite.js.map +0 -1
- package/scripts/tests/apply-patch-loop.mjs.bak +0 -363
|
@@ -73,7 +73,7 @@ export class RequestOpenAIToolsNormalizeFilter {
|
|
|
73
73
|
delete dst.function.strict;
|
|
74
74
|
}
|
|
75
75
|
catch { /* ignore */ }
|
|
76
|
-
// Switch schema for
|
|
76
|
+
// Switch schema for specific built-in tools at unified shaping point
|
|
77
77
|
try {
|
|
78
78
|
const name = String(dst.function.name || '').toLowerCase();
|
|
79
79
|
if (name === 'shell') {
|
|
@@ -101,6 +101,25 @@ export class RequestOpenAIToolsNormalizeFilter {
|
|
|
101
101
|
};
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
|
+
else if (name === 'apply_patch') {
|
|
105
|
+
dst.function.parameters = {
|
|
106
|
+
type: 'object',
|
|
107
|
+
properties: {
|
|
108
|
+
input: {
|
|
109
|
+
type: 'string',
|
|
110
|
+
description: 'Unified diff patch body between *** Begin Patch/*** End Patch.'
|
|
111
|
+
},
|
|
112
|
+
patch: {
|
|
113
|
+
type: 'string',
|
|
114
|
+
description: 'Alias of input for backwards compatibility.'
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
required: ['input'],
|
|
118
|
+
additionalProperties: false
|
|
119
|
+
};
|
|
120
|
+
dst.function.description =
|
|
121
|
+
'Use apply_patch to edit files. Provide the diff via the input field (*** Begin Patch ... *** End Patch).';
|
|
122
|
+
}
|
|
104
123
|
}
|
|
105
124
|
catch { /* ignore */ }
|
|
106
125
|
finalTools.push(dst);
|
|
@@ -63,6 +63,8 @@ function augmentApplyPatch(fn) {
|
|
|
63
63
|
const guidance = [
|
|
64
64
|
marker,
|
|
65
65
|
'Edit files by applying a unified diff patch. Return ONLY the patch text with *** Begin Patch/*** End Patch blocks.',
|
|
66
|
+
'Paths resolve relative to the active workspace root. Use forward-slash paths (e.g., packages/foo/file.ts) and switch to absolute paths only if you truly need to edit outside the workspace.',
|
|
67
|
+
'路径一律相对于当前工作区根目录解析;请写 packages/foo/... 这样的相对路径,跨工作区时再使用绝对路径。',
|
|
66
68
|
'Example:',
|
|
67
69
|
'*** Begin Patch',
|
|
68
70
|
'*** Update File: path/to/file.ts',
|
|
@@ -181,7 +183,9 @@ export function augmentAnthropicTools(tools) {
|
|
|
181
183
|
const marker = '[Codex ApplyPatch Guidance]';
|
|
182
184
|
const guidance = [
|
|
183
185
|
marker,
|
|
184
|
-
'Use unified diff patch with *** Begin Patch/End Patch. Return only the patch text.'
|
|
186
|
+
'Use unified diff patch with *** Begin Patch/End Patch. Return only the patch text.',
|
|
187
|
+
'All file paths must stay relative to the workspace root; never emit leading \'/\' or drive letters.',
|
|
188
|
+
'所有文件路径都必须相对当前工作区根目录,禁止输出以 / 或盘符开头的绝对路径。'
|
|
185
189
|
].join('\n');
|
|
186
190
|
copy.description = appendOnce(desc, guidance, marker);
|
|
187
191
|
}
|
|
@@ -216,7 +220,7 @@ export function buildSystemToolGuidance() {
|
|
|
216
220
|
lines.push(bullet('function.arguments must be a single JSON string. / arguments 必须是单个 JSON 字符串。'));
|
|
217
221
|
lines.push(bullet('shell: Place ALL intent into the command argv array only; do not invent extra keys. / shell 所有意图写入 command 数组,不要添加额外键名。'));
|
|
218
222
|
lines.push(bullet('File writes are FORBIDDEN via shell (no redirection, no here-doc, no sed -i, no ed -s, no tee). Use apply_patch ONLY. / 通过 shell 写文件一律禁止(不得使用重定向、heredoc、sed -i、ed -s、tee);必须使用 apply_patch。'));
|
|
219
|
-
lines.push(bullet('apply_patch: Provide a unified diff patch with *** Begin Patch/*** End Patch only. / 仅输出统一 diff
|
|
223
|
+
lines.push(bullet('apply_patch: Provide a unified diff patch with *** Begin Patch/*** End Patch only, and keep file paths relative to the workspace (no leading / or drive letters). / 仅输出统一 diff 补丁,且文件路径必须是相对路径(禁止以 / 或盘符开头)。'));
|
|
220
224
|
lines.push(bullet('apply_patch example / 示例:\n*** Begin Patch\n*** Update File: path/to/file.ts\n@@\n- old line\n+ new line\n*** End Patch'));
|
|
221
225
|
lines.push(bullet('update_plan: Keep exactly one step in_progress; others pending/completed. / 仅一个 in_progress 步骤。'));
|
|
222
226
|
lines.push(bullet('view_image: Path must be an image file (.png .jpg .jpeg .gif .webp .bmp .svg). / 仅图片路径。'));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { VirtualRouterError, VirtualRouterErrorCode } from './types.js';
|
|
2
2
|
const DEFAULT_CLASSIFIER = {
|
|
3
|
-
longContextThresholdTokens:
|
|
3
|
+
longContextThresholdTokens: 180000,
|
|
4
4
|
thinkingKeywords: ['think step', 'analysis', 'reasoning', '仔细分析', '深度思考'],
|
|
5
5
|
codingKeywords: ['apply_patch', 'write_file', 'create_file', 'shell', '修改文件', '写入文件'],
|
|
6
6
|
backgroundKeywords: ['background', 'context dump', '上下文'],
|
|
@@ -208,7 +208,7 @@ function normalizeProvider(providerId, raw) {
|
|
|
208
208
|
? provider.baseUrl.trim()
|
|
209
209
|
: '';
|
|
210
210
|
const headers = normalizeHeaders(provider.headers);
|
|
211
|
-
const compatibilityProfile = resolveCompatibilityProfile(provider);
|
|
211
|
+
const compatibilityProfile = resolveCompatibilityProfile(providerId, provider);
|
|
212
212
|
const responsesConfig = normalizeResponsesConfig(provider);
|
|
213
213
|
const processMode = normalizeProcessMode(provider.process);
|
|
214
214
|
return {
|
|
@@ -233,12 +233,21 @@ function normalizeResponsesConfig(provider) {
|
|
|
233
233
|
}
|
|
234
234
|
return undefined;
|
|
235
235
|
}
|
|
236
|
-
function resolveCompatibilityProfile(provider) {
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
return compat.trim();
|
|
236
|
+
function resolveCompatibilityProfile(providerId, provider) {
|
|
237
|
+
if (typeof provider.compatibilityProfile === 'string' && provider.compatibilityProfile.trim()) {
|
|
238
|
+
return provider.compatibilityProfile.trim();
|
|
240
239
|
}
|
|
241
|
-
|
|
240
|
+
const legacyFields = [];
|
|
241
|
+
if (typeof provider.compat === 'string') {
|
|
242
|
+
legacyFields.push('compat');
|
|
243
|
+
}
|
|
244
|
+
if (typeof provider.compatibility_profile === 'string') {
|
|
245
|
+
legacyFields.push('compatibility_profile');
|
|
246
|
+
}
|
|
247
|
+
if (legacyFields.length > 0) {
|
|
248
|
+
throw new VirtualRouterError(`Provider "${providerId}" uses legacy compatibility field(s): ${legacyFields.join(', ')}. Rename to "compatibilityProfile".`, VirtualRouterErrorCode.CONFIG_ERROR);
|
|
249
|
+
}
|
|
250
|
+
return 'compat:passthrough';
|
|
242
251
|
}
|
|
243
252
|
function normalizeProcessMode(value) {
|
|
244
253
|
if (typeof value !== 'string') {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DEFAULT_ROUTE, ROUTE_PRIORITY } from './types.js';
|
|
2
|
-
const DEFAULT_LONG_CONTEXT_THRESHOLD =
|
|
2
|
+
const DEFAULT_LONG_CONTEXT_THRESHOLD = 180000;
|
|
3
3
|
export class RoutingClassifier {
|
|
4
4
|
config;
|
|
5
5
|
constructor(config) {
|
|
@@ -10,55 +10,58 @@ export class RoutingClassifier {
|
|
|
10
10
|
};
|
|
11
11
|
}
|
|
12
12
|
classify(features) {
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
const lastToolCategory = features.lastAssistantToolCategory;
|
|
14
|
+
const reachedLongContext = features.estimatedTokens >= (this.config.longContextThresholdTokens ?? DEFAULT_LONG_CONTEXT_THRESHOLD);
|
|
15
|
+
const thinkingKeywordHit = features.hasThinkingKeyword ||
|
|
16
|
+
containsKeywords(features.userTextSample, this.config.thinkingKeywords ?? []);
|
|
17
|
+
const codingContinuation = lastToolCategory === 'write';
|
|
18
|
+
const thinkingContinuation = lastToolCategory === 'read';
|
|
19
|
+
const searchContinuation = lastToolCategory === 'search';
|
|
20
|
+
const toolsContinuation = lastToolCategory === 'other';
|
|
21
|
+
const evaluationMap = {
|
|
22
|
+
vision: {
|
|
16
23
|
triggered: features.hasVisionTool && features.hasImageAttachment,
|
|
17
24
|
reason: 'vision:requires-tool+image'
|
|
18
25
|
},
|
|
19
|
-
{
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
reason: 'websearch:web-tools-detected'
|
|
26
|
+
longcontext: {
|
|
27
|
+
triggered: reachedLongContext,
|
|
28
|
+
reason: 'longcontext:token-threshold'
|
|
23
29
|
},
|
|
24
|
-
{
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
reason: 'coding:coding-tools-detected'
|
|
30
|
+
websearch: {
|
|
31
|
+
triggered: features.hasWebTool || searchContinuation,
|
|
32
|
+
reason: searchContinuation ? 'websearch:last-tool-search' : 'websearch:web-tools-detected'
|
|
28
33
|
},
|
|
29
|
-
{
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
reason: 'tools:tool-request-detected'
|
|
34
|
+
coding: {
|
|
35
|
+
triggered: codingContinuation,
|
|
36
|
+
reason: 'coding:last-tool-write'
|
|
33
37
|
},
|
|
34
|
-
{
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
reason: 'longcontext:token-threshold'
|
|
38
|
+
thinking: {
|
|
39
|
+
triggered: thinkingContinuation || thinkingKeywordHit,
|
|
40
|
+
reason: thinkingContinuation ? 'thinking:last-tool-read' : 'thinking:keywords'
|
|
38
41
|
},
|
|
39
|
-
{
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
containsKeywords(features.userTextSample, this.config.thinkingKeywords ?? []),
|
|
43
|
-
reason: 'thinking:keywords'
|
|
42
|
+
tools: {
|
|
43
|
+
triggered: toolsContinuation || features.hasTools || features.hasToolCallResponses,
|
|
44
|
+
reason: toolsContinuation ? 'tools:last-tool-other' : 'tools:tool-request-detected'
|
|
44
45
|
},
|
|
45
|
-
{
|
|
46
|
-
route: 'background',
|
|
46
|
+
background: {
|
|
47
47
|
triggered: containsKeywords(features.userTextSample, this.config.backgroundKeywords ?? []),
|
|
48
48
|
reason: 'background:keywords'
|
|
49
49
|
}
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
50
|
+
};
|
|
51
|
+
for (const routeName of ROUTE_PRIORITY) {
|
|
52
|
+
const evaluation = evaluationMap[routeName];
|
|
53
|
+
if (evaluation && evaluation.triggered) {
|
|
54
|
+
const candidates = this.ensureDefaultCandidate([routeName]);
|
|
55
|
+
return this.buildResult(routeName, evaluation.reason, evaluationMap, candidates);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
const candidates = this.ensureDefaultCandidate([DEFAULT_ROUTE]);
|
|
59
|
+
return this.buildResult(DEFAULT_ROUTE, 'fallback:default', evaluationMap, candidates);
|
|
57
60
|
}
|
|
58
61
|
buildResult(routeName, chosenReason, evaluations, candidates) {
|
|
59
|
-
const diagnostics = evaluations
|
|
60
|
-
.filter((evaluation) => evaluation.triggered)
|
|
61
|
-
.map((evaluation) => evaluation.reason);
|
|
62
|
+
const diagnostics = Object.entries(evaluations)
|
|
63
|
+
.filter(([_, evaluation]) => evaluation.triggered)
|
|
64
|
+
.map(([_, evaluation]) => evaluation.reason);
|
|
62
65
|
const reasoningParts = [chosenReason, ...diagnostics.filter((reason) => reason !== chosenReason)];
|
|
63
66
|
return {
|
|
64
67
|
routeName,
|
package/node_modules/@jsonstudio/llms/dist/router/virtual-router/default-thinking-keywords.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const DEFAULT_THINKING_KEYWORDS: string[];
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type RoutingDecision, type RoutingDiagnostics, type RouterMetadataInput, type VirtualRouterConfig, type TargetMetadata, type ProviderFailureEvent, type ProviderErrorEvent } from './types.js';
|
|
2
|
+
import type { ProcessedRequest, StandardizedRequest } from '../../conversion/hub/types/standardized.js';
|
|
3
|
+
export declare class VirtualRouterEngine {
|
|
4
|
+
private routing;
|
|
5
|
+
private readonly providerRegistry;
|
|
6
|
+
private readonly healthManager;
|
|
7
|
+
private loadBalancer;
|
|
8
|
+
private classifier;
|
|
9
|
+
private routeStats;
|
|
10
|
+
private readonly debug;
|
|
11
|
+
private healthConfig;
|
|
12
|
+
initialize(config: VirtualRouterConfig): void;
|
|
13
|
+
route(request: StandardizedRequest | ProcessedRequest, metadata: RouterMetadataInput): {
|
|
14
|
+
target: TargetMetadata;
|
|
15
|
+
decision: RoutingDecision;
|
|
16
|
+
diagnostics: RoutingDiagnostics;
|
|
17
|
+
};
|
|
18
|
+
handleProviderFailure(event: ProviderFailureEvent): void;
|
|
19
|
+
handleProviderError(event: ProviderErrorEvent): void;
|
|
20
|
+
getStatus(): {
|
|
21
|
+
routes: Record<string, {
|
|
22
|
+
providers: string[];
|
|
23
|
+
hits: number;
|
|
24
|
+
lastUsedProvider?: string;
|
|
25
|
+
}>;
|
|
26
|
+
health: import("./types.js").ProviderHealthState[];
|
|
27
|
+
};
|
|
28
|
+
private validateConfig;
|
|
29
|
+
private selectProvider;
|
|
30
|
+
private incrementRouteStat;
|
|
31
|
+
private providerHealthConfig;
|
|
32
|
+
private resolveStickyKey;
|
|
33
|
+
private mapProviderError;
|
|
34
|
+
private deriveReason;
|
|
35
|
+
private buildRouteCandidates;
|
|
36
|
+
private sortByPriority;
|
|
37
|
+
private routeWeight;
|
|
38
|
+
private buildHitReason;
|
|
39
|
+
}
|
|
@@ -11,11 +11,14 @@ export class VirtualRouterEngine {
|
|
|
11
11
|
loadBalancer = new RouteLoadBalancer();
|
|
12
12
|
classifier = new RoutingClassifier({});
|
|
13
13
|
routeStats = new Map();
|
|
14
|
+
debug = console; // thin hook; host may monkey-patch for colored logging
|
|
15
|
+
healthConfig = null;
|
|
14
16
|
initialize(config) {
|
|
15
17
|
this.validateConfig(config);
|
|
16
18
|
this.routing = config.routing;
|
|
17
19
|
this.providerRegistry.load(config.providers);
|
|
18
20
|
this.healthManager.configure(config.health);
|
|
21
|
+
this.healthConfig = config.health ?? null;
|
|
19
22
|
this.healthManager.registerProviders(Object.keys(config.providers));
|
|
20
23
|
this.loadBalancer = new RouteLoadBalancer(config.loadBalancing);
|
|
21
24
|
this.classifier = new RoutingClassifier(config.classifier);
|
|
@@ -32,6 +35,8 @@ export class VirtualRouterEngine {
|
|
|
32
35
|
const target = this.providerRegistry.buildTarget(selection.providerKey);
|
|
33
36
|
this.healthManager.recordSuccess(selection.providerKey);
|
|
34
37
|
this.incrementRouteStat(selection.routeUsed, selection.providerKey);
|
|
38
|
+
const hitReason = this.buildHitReason(selection.routeUsed, classification, features);
|
|
39
|
+
this.debug?.log?.('[virtual-router-hit]', selection.routeUsed, selection.providerKey, target.modelId || '', hitReason ? `reason=${hitReason}` : '');
|
|
35
40
|
const didFallback = selection.routeUsed !== routeName || classification.fallback;
|
|
36
41
|
return {
|
|
37
42
|
target,
|
|
@@ -117,7 +122,7 @@ export class VirtualRouterEngine {
|
|
|
117
122
|
}
|
|
118
123
|
selectProvider(requestedRoute, metadata, classification) {
|
|
119
124
|
const candidates = this.buildRouteCandidates(requestedRoute, classification.candidates);
|
|
120
|
-
const stickyKey = metadata
|
|
125
|
+
const stickyKey = this.resolveStickyKey(metadata);
|
|
121
126
|
const attempted = [];
|
|
122
127
|
for (const routeName of candidates) {
|
|
123
128
|
const pool = this.routing[routeName];
|
|
@@ -147,7 +152,20 @@ export class VirtualRouterEngine {
|
|
|
147
152
|
stats.hits += 1;
|
|
148
153
|
stats.lastProvider = providerKey;
|
|
149
154
|
}
|
|
155
|
+
providerHealthConfig() {
|
|
156
|
+
return this.healthManager.getConfig();
|
|
157
|
+
}
|
|
158
|
+
resolveStickyKey(metadata) {
|
|
159
|
+
const resume = metadata.responsesResume;
|
|
160
|
+
if (resume && typeof resume.previousRequestId === 'string' && resume.previousRequestId.trim()) {
|
|
161
|
+
return resume.previousRequestId.trim();
|
|
162
|
+
}
|
|
163
|
+
return metadata.requestId;
|
|
164
|
+
}
|
|
150
165
|
mapProviderError(event) {
|
|
166
|
+
// NOTE: mapProviderError is the only place where VirtualRouter translates providerErrorCenter
|
|
167
|
+
// events into health signals. Classification is intentionally coarse; upstream providers
|
|
168
|
+
// are expected to set event.recoverable explicitly when they know an error is safe to retry.
|
|
151
169
|
if (!event || !event.runtime) {
|
|
152
170
|
return null;
|
|
153
171
|
}
|
|
@@ -162,19 +180,23 @@ export class VirtualRouterEngine {
|
|
|
162
180
|
const code = event.code?.toUpperCase() ?? 'ERR_UNKNOWN';
|
|
163
181
|
const stage = event.stage?.toLowerCase() ?? 'unknown';
|
|
164
182
|
const recoverable = event.recoverable === true;
|
|
183
|
+
// 默认策略:只有显式可恢复的错误才视为非致命;其余一律按致命处理。
|
|
184
|
+
// 注意:provider 层已经对 429 做了「连续 4 次升级为不可恢复」的判断,这里不再把所有 429 强行当作可恢复。
|
|
165
185
|
let fatal = !recoverable;
|
|
166
186
|
let reason = this.deriveReason(code, stage, statusCode);
|
|
167
187
|
let cooldownOverrideMs;
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
cooldownOverrideMs = Math.max(30_000, this.providerHealthConfig().cooldownMs);
|
|
171
|
-
reason = 'rate_limit';
|
|
172
|
-
}
|
|
173
|
-
else if (statusCode === 401 || statusCode === 403 || code.includes('AUTH')) {
|
|
188
|
+
// 401 / 402 / 500 / 524 以及所有未被标记为可恢复的错误一律视为不可恢复
|
|
189
|
+
if (statusCode === 401 || statusCode === 402 || statusCode === 403 || code.includes('AUTH')) {
|
|
174
190
|
fatal = true;
|
|
175
191
|
cooldownOverrideMs = Math.max(10 * 60_000, this.providerHealthConfig().fatalCooldownMs ?? 10 * 60_000);
|
|
176
192
|
reason = 'auth';
|
|
177
193
|
}
|
|
194
|
+
else if (statusCode === 429 && !recoverable) {
|
|
195
|
+
// 连续 429 已在 provider 层被升级为不可恢复:这里按致命限流处理(长冷却,等同熔断)
|
|
196
|
+
fatal = true;
|
|
197
|
+
cooldownOverrideMs = Math.max(10 * 60_000, this.providerHealthConfig().fatalCooldownMs ?? 10 * 60_000);
|
|
198
|
+
reason = 'rate_limit';
|
|
199
|
+
}
|
|
178
200
|
else if (statusCode && statusCode >= 500) {
|
|
179
201
|
fatal = true;
|
|
180
202
|
cooldownOverrideMs = Math.max(5 * 60_000, this.providerHealthConfig().fatalCooldownMs ?? 5 * 60_000);
|
|
@@ -193,7 +215,8 @@ export class VirtualRouterEngine {
|
|
|
193
215
|
statusCode,
|
|
194
216
|
errorCode: code,
|
|
195
217
|
retryable: recoverable,
|
|
196
|
-
affectsHealth
|
|
218
|
+
// 是否影响健康由 provider 层决定;这里仅在 event.affectsHealth !== false 时才计入健康状态
|
|
219
|
+
affectsHealth: event.affectsHealth !== false,
|
|
197
220
|
cooldownOverrideMs,
|
|
198
221
|
metadata: {
|
|
199
222
|
...event.runtime,
|
|
@@ -221,9 +244,6 @@ export class VirtualRouterEngine {
|
|
|
221
244
|
return 'client_error';
|
|
222
245
|
return 'unknown';
|
|
223
246
|
}
|
|
224
|
-
providerHealthConfig() {
|
|
225
|
-
return this.healthManager.getConfig();
|
|
226
|
-
}
|
|
227
247
|
buildRouteCandidates(requestedRoute, classificationCandidates) {
|
|
228
248
|
const normalized = requestedRoute || DEFAULT_ROUTE;
|
|
229
249
|
const baseList = classificationCandidates && classificationCandidates.length
|
|
@@ -257,4 +277,25 @@ export class VirtualRouterEngine {
|
|
|
257
277
|
const idx = ROUTE_PRIORITY.indexOf(routeName);
|
|
258
278
|
return idx >= 0 ? idx : ROUTE_PRIORITY.length;
|
|
259
279
|
}
|
|
280
|
+
buildHitReason(routeUsed, classification, features) {
|
|
281
|
+
const reasoning = classification.reasoning || '';
|
|
282
|
+
const primary = reasoning.split('|')[0] || '';
|
|
283
|
+
const lastToolName = features.lastAssistantToolName;
|
|
284
|
+
if (routeUsed === 'tools') {
|
|
285
|
+
if (lastToolName) {
|
|
286
|
+
return primary ? `${primary}(${lastToolName})` : `tools(${lastToolName})`;
|
|
287
|
+
}
|
|
288
|
+
return primary || 'tools';
|
|
289
|
+
}
|
|
290
|
+
if (routeUsed === 'thinking') {
|
|
291
|
+
return primary || 'thinking';
|
|
292
|
+
}
|
|
293
|
+
if (routeUsed === DEFAULT_ROUTE && classification.fallback) {
|
|
294
|
+
return primary || 'fallback:default';
|
|
295
|
+
}
|
|
296
|
+
if (primary) {
|
|
297
|
+
return primary;
|
|
298
|
+
}
|
|
299
|
+
return routeUsed ? `route:${routeUsed}` : 'route:unknown';
|
|
300
|
+
}
|
|
260
301
|
}
|