@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
package/node_modules/@jsonstudio/llms/dist/conversion/hub/pipeline/compat/compat-profile-store.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
const builtinDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../compat/profiles');
|
|
6
|
+
const USER_COMPAT_DIR = (process.env.ROUTECODEX_COMPAT_DIR && process.env.ROUTECODEX_COMPAT_DIR.trim()) ||
|
|
7
|
+
path.join(os.homedir(), '.routecodex', 'compat');
|
|
8
|
+
let profileMap = null;
|
|
9
|
+
function normalizeProfiles(profiles) {
|
|
10
|
+
const map = new Map();
|
|
11
|
+
for (const profile of profiles) {
|
|
12
|
+
if (!profile || typeof profile !== 'object') {
|
|
13
|
+
continue;
|
|
14
|
+
}
|
|
15
|
+
const id = typeof profile.id === 'string' ? profile.id.trim() : '';
|
|
16
|
+
if (!id) {
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
map.set(id, {
|
|
20
|
+
...profile,
|
|
21
|
+
id
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
return map;
|
|
25
|
+
}
|
|
26
|
+
function loadProfilesFromDir(dir) {
|
|
27
|
+
try {
|
|
28
|
+
if (!fs.existsSync(dir)) {
|
|
29
|
+
return [];
|
|
30
|
+
}
|
|
31
|
+
const entries = fs.readdirSync(dir);
|
|
32
|
+
const configs = [];
|
|
33
|
+
for (const entry of entries) {
|
|
34
|
+
if (!entry.endsWith('.json')) {
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
const file = path.join(dir, entry);
|
|
38
|
+
try {
|
|
39
|
+
const text = fs.readFileSync(file, 'utf8');
|
|
40
|
+
const json = JSON.parse(text);
|
|
41
|
+
if (!json.id) {
|
|
42
|
+
json.id = entry.replace(/\.json$/i, '');
|
|
43
|
+
}
|
|
44
|
+
configs.push(json);
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
console.warn(`[compat] Failed to load ${file}: ${error instanceof Error ? error.message : String(error)}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return configs;
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return [];
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function buildProfileMap() {
|
|
57
|
+
const merged = new Map();
|
|
58
|
+
const builtinProfiles = normalizeProfiles(loadProfilesFromDir(builtinDir));
|
|
59
|
+
for (const [key, value] of builtinProfiles.entries()) {
|
|
60
|
+
merged.set(key, value);
|
|
61
|
+
}
|
|
62
|
+
const userProfiles = normalizeProfiles(loadProfilesFromDir(USER_COMPAT_DIR));
|
|
63
|
+
for (const [key, value] of userProfiles.entries()) {
|
|
64
|
+
merged.set(key, value);
|
|
65
|
+
}
|
|
66
|
+
return merged;
|
|
67
|
+
}
|
|
68
|
+
export function getCompatProfile(profileId) {
|
|
69
|
+
if (!profileId || !profileId.trim()) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
if (!profileMap) {
|
|
73
|
+
profileMap = buildProfileMap();
|
|
74
|
+
}
|
|
75
|
+
return profileMap.get(profileId.trim()) ?? null;
|
|
76
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { JsonObject, JsonValue } from '../../types/json.js';
|
|
2
|
+
export type CompatDirection = 'request' | 'response';
|
|
3
|
+
export interface CompatProfileConfig {
|
|
4
|
+
id: string;
|
|
5
|
+
protocol: string;
|
|
6
|
+
direction?: CompatDirection;
|
|
7
|
+
mappings?: MappingInstruction[];
|
|
8
|
+
filters?: FilterInstruction[];
|
|
9
|
+
request?: CompatStageConfig;
|
|
10
|
+
response?: CompatStageConfig;
|
|
11
|
+
}
|
|
12
|
+
export interface CompatStageConfig {
|
|
13
|
+
mappings?: MappingInstruction[];
|
|
14
|
+
filters?: FilterInstruction[];
|
|
15
|
+
}
|
|
16
|
+
export type MappingInstruction = {
|
|
17
|
+
action: 'remove';
|
|
18
|
+
path: string;
|
|
19
|
+
} | {
|
|
20
|
+
action: 'rename';
|
|
21
|
+
from: string;
|
|
22
|
+
to: string;
|
|
23
|
+
} | {
|
|
24
|
+
action: 'set';
|
|
25
|
+
path: string;
|
|
26
|
+
value: JsonValue;
|
|
27
|
+
} | {
|
|
28
|
+
action: 'stringify';
|
|
29
|
+
path: string;
|
|
30
|
+
fallback?: JsonValue;
|
|
31
|
+
} | {
|
|
32
|
+
action: 'set_default';
|
|
33
|
+
path: string;
|
|
34
|
+
value?: JsonValue;
|
|
35
|
+
valueSource?: 'timestamp_seconds' | 'chat_completion_id';
|
|
36
|
+
} | {
|
|
37
|
+
action: 'normalize_tool_choice';
|
|
38
|
+
path?: string;
|
|
39
|
+
objectReplacement?: string;
|
|
40
|
+
} | {
|
|
41
|
+
action: 'inject_instruction';
|
|
42
|
+
sourcePath: string;
|
|
43
|
+
targetPath?: string;
|
|
44
|
+
role?: string;
|
|
45
|
+
contentType?: string;
|
|
46
|
+
stripHtml?: boolean;
|
|
47
|
+
maxLengthEnv?: string[];
|
|
48
|
+
} | {
|
|
49
|
+
action: 'parse_json';
|
|
50
|
+
path: string;
|
|
51
|
+
fallback?: JsonValue;
|
|
52
|
+
} | {
|
|
53
|
+
action: 'convert_responses_output_to_choices';
|
|
54
|
+
};
|
|
55
|
+
export type FilterInstruction = {
|
|
56
|
+
action: 'rate_limit_text';
|
|
57
|
+
needle: string;
|
|
58
|
+
};
|
|
59
|
+
export interface CompatApplicationResult {
|
|
60
|
+
payload: JsonObject;
|
|
61
|
+
appliedProfile?: string;
|
|
62
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -44,6 +44,7 @@ export interface HubPipelineResult {
|
|
|
44
44
|
export declare class HubPipeline {
|
|
45
45
|
private readonly routerEngine;
|
|
46
46
|
private config;
|
|
47
|
+
private unsubscribeProviderErrors?;
|
|
47
48
|
constructor(config: HubPipelineConfig);
|
|
48
49
|
updateVirtualRouterConfig(nextConfig: VirtualRouterConfig): void;
|
|
49
50
|
private executeRequestStagePipeline;
|
|
@@ -55,6 +56,7 @@ export declare class HubPipeline {
|
|
|
55
56
|
private buildAdapterContext;
|
|
56
57
|
private maybeCreateStageRecorder;
|
|
57
58
|
private asJsonObject;
|
|
59
|
+
private pickRawRequestBody;
|
|
58
60
|
private normalizeRequest;
|
|
59
61
|
private convertProcessNodeResult;
|
|
60
62
|
private materializePayload;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Readable } from 'node:stream';
|
|
2
2
|
import { VirtualRouterEngine } from '../../../router/virtual-router/engine.js';
|
|
3
|
+
import { providerErrorCenter } from '../../../router/virtual-router/error-center.js';
|
|
3
4
|
import { defaultSseCodecRegistry } from '../../../sse/index.js';
|
|
4
5
|
import { ResponsesFormatAdapter } from '../format-adapters/responses-format-adapter.js';
|
|
5
6
|
import { ResponsesSemanticMapper } from '../semantic-mappers/responses-mapper.js';
|
|
@@ -18,13 +19,28 @@ import { runReqProcessStage1ToolGovernance } from './stages/req_process/req_proc
|
|
|
18
19
|
import { runReqProcessStage2RouteSelect } from './stages/req_process/req_process_stage2_route_select/index.js';
|
|
19
20
|
import { runReqOutboundStage1SemanticMap } from './stages/req_outbound/req_outbound_stage1_semantic_map/index.js';
|
|
20
21
|
import { runReqOutboundStage2FormatBuild } from './stages/req_outbound/req_outbound_stage2_format_build/index.js';
|
|
22
|
+
import { runReqOutboundStage3Compat } from './stages/req_outbound/req_outbound_stage3_compat/index.js';
|
|
21
23
|
export class HubPipeline {
|
|
22
24
|
routerEngine;
|
|
23
25
|
config;
|
|
26
|
+
unsubscribeProviderErrors;
|
|
24
27
|
constructor(config) {
|
|
25
28
|
this.config = config;
|
|
26
29
|
this.routerEngine = new VirtualRouterEngine();
|
|
27
30
|
this.routerEngine.initialize(config.virtualRouter);
|
|
31
|
+
try {
|
|
32
|
+
this.unsubscribeProviderErrors = providerErrorCenter.subscribe((event) => {
|
|
33
|
+
try {
|
|
34
|
+
this.routerEngine.handleProviderError(event);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// ignore subscriber errors
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
this.unsubscribeProviderErrors = undefined;
|
|
43
|
+
}
|
|
28
44
|
}
|
|
29
45
|
updateVirtualRouterConfig(nextConfig) {
|
|
30
46
|
if (!nextConfig || typeof nextConfig !== 'object') {
|
|
@@ -91,6 +107,10 @@ export class HubPipeline {
|
|
|
91
107
|
}
|
|
92
108
|
}
|
|
93
109
|
const workingRequest = processedRequest ?? standardizedRequest;
|
|
110
|
+
const normalizedMeta = normalized.metadata;
|
|
111
|
+
const responsesResume = normalizedMeta && typeof normalizedMeta.responsesResume === 'object'
|
|
112
|
+
? normalizedMeta.responsesResume
|
|
113
|
+
: undefined;
|
|
94
114
|
const metadataInput = {
|
|
95
115
|
requestId: normalized.id,
|
|
96
116
|
entryEndpoint: normalized.entryEndpoint,
|
|
@@ -99,7 +119,8 @@ export class HubPipeline {
|
|
|
99
119
|
direction: normalized.direction,
|
|
100
120
|
providerProtocol: normalized.providerProtocol,
|
|
101
121
|
routeHint: normalized.routeHint,
|
|
102
|
-
stage: normalized.stage
|
|
122
|
+
stage: normalized.stage,
|
|
123
|
+
responsesResume: responsesResume
|
|
103
124
|
};
|
|
104
125
|
const routing = runReqProcessStage2RouteSelect({
|
|
105
126
|
routerEngine: this.routerEngine,
|
|
@@ -108,7 +129,23 @@ export class HubPipeline {
|
|
|
108
129
|
normalizedMetadata: normalized.metadata,
|
|
109
130
|
stageRecorder: inboundRecorder
|
|
110
131
|
});
|
|
132
|
+
// Emit virtual router hit log for debugging (orange [virtual-router] ...)
|
|
133
|
+
try {
|
|
134
|
+
const routeName = routing.decision?.routeName;
|
|
135
|
+
const providerKey = routing.target?.providerKey;
|
|
136
|
+
const modelId = workingRequest.model;
|
|
137
|
+
const logger = (normalized.metadata && normalized.metadata.logger);
|
|
138
|
+
if (logger && typeof logger.logVirtualRouterHit === 'function' && routeName && providerKey) {
|
|
139
|
+
logger.logVirtualRouterHit(routeName, providerKey, typeof modelId === 'string' ? modelId : undefined);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
// logging must not break routing
|
|
144
|
+
}
|
|
111
145
|
const outboundAdapterContext = this.buildAdapterContext(normalized, routing.target);
|
|
146
|
+
if (routing.target?.compatibilityProfile) {
|
|
147
|
+
outboundAdapterContext.compatibilityProfile = routing.target.compatibilityProfile;
|
|
148
|
+
}
|
|
112
149
|
const outboundProtocol = outboundAdapterContext.providerProtocol;
|
|
113
150
|
const protocolSwitch = outboundProtocol !== normalized.providerProtocol;
|
|
114
151
|
const outboundHooks = protocolSwitch ? this.resolveProtocolHooks(outboundProtocol) : hooks;
|
|
@@ -122,35 +159,66 @@ export class HubPipeline {
|
|
|
122
159
|
const outboundEndpoint = resolveEndpointForProviderProtocol(outboundAdapterContext.providerProtocol);
|
|
123
160
|
const outboundRecorder = this.maybeCreateStageRecorder(outboundAdapterContext, outboundEndpoint);
|
|
124
161
|
const outboundStart = Date.now();
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
executionTime: outboundEnd - outboundStart,
|
|
146
|
-
startTime: outboundStart,
|
|
147
|
-
endTime: outboundEnd,
|
|
148
|
-
dataProcessed: {
|
|
149
|
-
messages: workingRequest.messages.length,
|
|
150
|
-
tools: workingRequest.tools?.length ?? 0
|
|
162
|
+
const isResponsesSubmit = normalized.entryEndpoint === '/v1/responses.submit_tool_outputs' &&
|
|
163
|
+
outboundProtocol === 'openai-responses';
|
|
164
|
+
let providerPayload;
|
|
165
|
+
if (isResponsesSubmit) {
|
|
166
|
+
providerPayload =
|
|
167
|
+
this.pickRawRequestBody(normalized.metadata) ?? normalized.payload;
|
|
168
|
+
const outboundEnd = Date.now();
|
|
169
|
+
nodeResults.push({
|
|
170
|
+
id: 'req_outbound',
|
|
171
|
+
success: true,
|
|
172
|
+
metadata: {
|
|
173
|
+
node: 'req_outbound',
|
|
174
|
+
executionTime: outboundEnd - outboundStart,
|
|
175
|
+
startTime: outboundStart,
|
|
176
|
+
endTime: outboundEnd,
|
|
177
|
+
dataProcessed: {
|
|
178
|
+
messages: 0,
|
|
179
|
+
tools: 0
|
|
180
|
+
},
|
|
181
|
+
bypass: 'responses-submit-passthrough'
|
|
151
182
|
}
|
|
152
|
-
}
|
|
153
|
-
}
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
const outboundStage1 = await runReqOutboundStage1SemanticMap({
|
|
187
|
+
request: workingRequest,
|
|
188
|
+
adapterContext: outboundAdapterContext,
|
|
189
|
+
semanticMapper: outboundSemanticMapper,
|
|
190
|
+
contextSnapshot: outboundContextSnapshot,
|
|
191
|
+
contextMetadataKey: outboundContextMetadataKey,
|
|
192
|
+
stageRecorder: outboundRecorder
|
|
193
|
+
});
|
|
194
|
+
let formattedPayload = await runReqOutboundStage2FormatBuild({
|
|
195
|
+
formatEnvelope: outboundStage1.formatEnvelope,
|
|
196
|
+
adapterContext: outboundAdapterContext,
|
|
197
|
+
formatAdapter: outboundFormatAdapter,
|
|
198
|
+
stageRecorder: outboundRecorder
|
|
199
|
+
});
|
|
200
|
+
formattedPayload = await runReqOutboundStage3Compat({
|
|
201
|
+
payload: formattedPayload,
|
|
202
|
+
adapterContext: outboundAdapterContext,
|
|
203
|
+
stageRecorder: outboundRecorder
|
|
204
|
+
});
|
|
205
|
+
providerPayload = formattedPayload;
|
|
206
|
+
const outboundEnd = Date.now();
|
|
207
|
+
nodeResults.push({
|
|
208
|
+
id: 'req_outbound',
|
|
209
|
+
success: true,
|
|
210
|
+
metadata: {
|
|
211
|
+
node: 'req_outbound',
|
|
212
|
+
executionTime: outboundEnd - outboundStart,
|
|
213
|
+
startTime: outboundStart,
|
|
214
|
+
endTime: outboundEnd,
|
|
215
|
+
dataProcessed: {
|
|
216
|
+
messages: workingRequest.messages.length,
|
|
217
|
+
tools: workingRequest.tools?.length ?? 0
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
}
|
|
154
222
|
const metadata = {
|
|
155
223
|
...normalized.metadata,
|
|
156
224
|
entryEndpoint: normalized.entryEndpoint,
|
|
@@ -271,6 +339,9 @@ export class HubPipeline {
|
|
|
271
339
|
if (typeof metadata.assignedModelId === 'string') {
|
|
272
340
|
adapterContext.modelId = metadata.assignedModelId;
|
|
273
341
|
}
|
|
342
|
+
if (target?.compatibilityProfile && typeof target.compatibilityProfile === 'string') {
|
|
343
|
+
adapterContext.compatibilityProfile = target.compatibilityProfile;
|
|
344
|
+
}
|
|
274
345
|
return adapterContext;
|
|
275
346
|
}
|
|
276
347
|
maybeCreateStageRecorder(context, endpoint) {
|
|
@@ -292,6 +363,16 @@ export class HubPipeline {
|
|
|
292
363
|
}
|
|
293
364
|
return value;
|
|
294
365
|
}
|
|
366
|
+
pickRawRequestBody(metadata) {
|
|
367
|
+
if (!metadata || typeof metadata !== 'object') {
|
|
368
|
+
return undefined;
|
|
369
|
+
}
|
|
370
|
+
const raw = metadata.__raw_request_body;
|
|
371
|
+
if (!raw || typeof raw !== 'object') {
|
|
372
|
+
return undefined;
|
|
373
|
+
}
|
|
374
|
+
return raw;
|
|
375
|
+
}
|
|
295
376
|
async normalizeRequest(request) {
|
|
296
377
|
if (!request || typeof request !== 'object') {
|
|
297
378
|
throw new Error('HubPipeline requires request payload');
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { AdapterContext } from '../../../../types/chat-envelope.js';
|
|
2
|
+
import type { StageRecorder } from '../../../../format-adapters/index.js';
|
|
3
|
+
import type { JsonObject } from '../../../../types/json.js';
|
|
4
|
+
export type ProviderPayload = JsonObject;
|
|
5
|
+
export declare function runReqOutboundStage3Compat(options: {
|
|
6
|
+
payload: ProviderPayload;
|
|
7
|
+
adapterContext: AdapterContext;
|
|
8
|
+
stageRecorder?: StageRecorder;
|
|
9
|
+
}): Promise<ProviderPayload>;
|
|
10
|
+
export declare function runRespInboundStageCompatResponse(options: {
|
|
11
|
+
payload: ProviderPayload;
|
|
12
|
+
adapterContext: AdapterContext;
|
|
13
|
+
stageRecorder?: StageRecorder;
|
|
14
|
+
}): ProviderPayload;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { applyRequestCompat, applyResponseCompat } from '../../../compat/compat-engine.js';
|
|
2
|
+
function pickCompatProfile(adapterContext) {
|
|
3
|
+
const candidate = adapterContext.compatibilityProfile;
|
|
4
|
+
return typeof candidate === 'string' && candidate.trim() ? candidate.trim() : undefined;
|
|
5
|
+
}
|
|
6
|
+
export async function runReqOutboundStage3Compat(options) {
|
|
7
|
+
const profile = pickCompatProfile(options.adapterContext);
|
|
8
|
+
const result = applyRequestCompat(profile, options.payload);
|
|
9
|
+
options.stageRecorder?.record('req_outbound_stage3_compat', {
|
|
10
|
+
applied: Boolean(result.appliedProfile),
|
|
11
|
+
profile: result.appliedProfile || profile || 'passthrough'
|
|
12
|
+
});
|
|
13
|
+
return result.payload;
|
|
14
|
+
}
|
|
15
|
+
export function runRespInboundStageCompatResponse(options) {
|
|
16
|
+
const profile = pickCompatProfile(options.adapterContext);
|
|
17
|
+
const result = applyResponseCompat(profile, options.payload);
|
|
18
|
+
options.stageRecorder?.record('resp_inbound_stage_compat', {
|
|
19
|
+
applied: Boolean(result.appliedProfile),
|
|
20
|
+
profile: result.appliedProfile || profile || 'passthrough'
|
|
21
|
+
});
|
|
22
|
+
return result.payload;
|
|
23
|
+
}
|
|
@@ -15,6 +15,7 @@ export function runRespOutboundStage1ClientRemap(options) {
|
|
|
15
15
|
clientPayload = buildResponsesPayloadFromChat(options.payload, {
|
|
16
16
|
requestId: options.requestId
|
|
17
17
|
});
|
|
18
|
+
mergeOriginalResponsesPayload(clientPayload, options.adapterContext);
|
|
18
19
|
}
|
|
19
20
|
recordStage(options.stageRecorder, 'resp_outbound_stage1_client_remap', clientPayload);
|
|
20
21
|
return clientPayload;
|
|
@@ -41,3 +42,36 @@ function resolveAliasMapFromContext(adapterContext) {
|
|
|
41
42
|
}
|
|
42
43
|
return Object.keys(map).length ? map : undefined;
|
|
43
44
|
}
|
|
45
|
+
function mergeOriginalResponsesPayload(payload, adapterContext) {
|
|
46
|
+
if (!adapterContext) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const raw = adapterContext.__raw_responses_payload;
|
|
50
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
if (payload.required_action == null && raw.required_action != null) {
|
|
55
|
+
payload.required_action = JSON.parse(JSON.stringify(raw.required_action));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
/* ignore clone errors */
|
|
60
|
+
}
|
|
61
|
+
const rawStatus = typeof raw.status === 'string' ? raw.status : undefined;
|
|
62
|
+
if (rawStatus === 'requires_action') {
|
|
63
|
+
payload.status = 'requires_action';
|
|
64
|
+
}
|
|
65
|
+
// 如果桥接后的 payload 没有 usage,而原始 Responses 载荷带有 usage,则回填原始 usage,
|
|
66
|
+
// 确保 token usage 不在工具/桥接路径中丢失。
|
|
67
|
+
const payloadUsage = payload.usage;
|
|
68
|
+
const rawUsage = raw.usage;
|
|
69
|
+
if ((payloadUsage == null || typeof payloadUsage !== 'object') && rawUsage && typeof rawUsage === 'object') {
|
|
70
|
+
try {
|
|
71
|
+
payload.usage = JSON.parse(JSON.stringify(rawUsage));
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
payload.usage = rawUsage;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -44,7 +44,10 @@ async function applyRequestToolGovernance(request, context) {
|
|
|
44
44
|
model: request.model,
|
|
45
45
|
profile: providerProtocol,
|
|
46
46
|
stream: inboundStreamIntent,
|
|
47
|
-
toolFilterHints: metadataToolHints
|
|
47
|
+
toolFilterHints: metadataToolHints,
|
|
48
|
+
rawPayload: context.metadata?.__raw_request_body && typeof context.metadata.__raw_request_body === 'object'
|
|
49
|
+
? context.metadata.__raw_request_body
|
|
50
|
+
: undefined
|
|
48
51
|
});
|
|
49
52
|
const governed = normalizeRecord(governedPayload);
|
|
50
53
|
const providerStreamIntent = typeof governed.stream === 'boolean' ? governed.stream : undefined;
|
|
@@ -6,10 +6,12 @@ import { OpenAIChatResponseMapper, ResponsesResponseMapper, AnthropicResponseMap
|
|
|
6
6
|
import { runRespInboundStage1SseDecode } from '../pipeline/stages/resp_inbound/resp_inbound_stage1_sse_decode/index.js';
|
|
7
7
|
import { runRespInboundStage2FormatParse } from '../pipeline/stages/resp_inbound/resp_inbound_stage2_format_parse/index.js';
|
|
8
8
|
import { runRespInboundStage3SemanticMap } from '../pipeline/stages/resp_inbound/resp_inbound_stage3_semantic_map/index.js';
|
|
9
|
+
import { runRespInboundStageCompatResponse } from '../pipeline/stages/req_outbound/req_outbound_stage3_compat/index.js';
|
|
9
10
|
import { runRespProcessStage1ToolGovernance } from '../pipeline/stages/resp_process/resp_process_stage1_tool_governance/index.js';
|
|
10
11
|
import { runRespProcessStage2Finalize } from '../pipeline/stages/resp_process/resp_process_stage2_finalize/index.js';
|
|
11
12
|
import { runRespOutboundStage1ClientRemap } from '../pipeline/stages/resp_outbound/resp_outbound_stage1_client_remap/index.js';
|
|
12
13
|
import { runRespOutboundStage2SseStream } from '../pipeline/stages/resp_outbound/resp_outbound_stage2_sse_stream/index.js';
|
|
14
|
+
import { recordResponsesResponse } from '../../shared/responses-conversation-store.js';
|
|
13
15
|
function resolveChatReasoningMode(entryEndpoint) {
|
|
14
16
|
const envRaw = (process.env.ROUTECODEX_CHAT_REASONING_MODE || process.env.RCC_CHAT_REASONING_MODE || '').trim().toLowerCase();
|
|
15
17
|
const map = {
|
|
@@ -105,6 +107,30 @@ export async function convertProviderResponse(options) {
|
|
|
105
107
|
formatAdapter,
|
|
106
108
|
stageRecorder: options.stageRecorder
|
|
107
109
|
});
|
|
110
|
+
if (options.providerProtocol === 'openai-responses') {
|
|
111
|
+
try {
|
|
112
|
+
recordResponsesResponse({
|
|
113
|
+
requestId: options.context.requestId,
|
|
114
|
+
response: formatEnvelope.payload
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
// ignore conversation capture errors
|
|
119
|
+
}
|
|
120
|
+
if (formatEnvelope.payload && typeof formatEnvelope.payload === 'object') {
|
|
121
|
+
try {
|
|
122
|
+
options.context.__raw_responses_payload = JSON.parse(JSON.stringify(formatEnvelope.payload));
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
/* best-effort clone */
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
formatEnvelope.payload = runRespInboundStageCompatResponse({
|
|
130
|
+
payload: formatEnvelope.payload,
|
|
131
|
+
adapterContext: options.context,
|
|
132
|
+
stageRecorder: options.stageRecorder
|
|
133
|
+
});
|
|
108
134
|
const chatResponse = await runRespInboundStage3SemanticMap({
|
|
109
135
|
adapterContext: options.context,
|
|
110
136
|
formatEnvelope,
|
package/node_modules/@jsonstudio/llms/dist/conversion/responses/responses-openai-bridge.d.ts
CHANGED
|
@@ -48,6 +48,7 @@ export declare function buildResponsesRequestFromChat(payload: Record<string, un
|
|
|
48
48
|
bridgeHistory?: BridgeInputBuildResult;
|
|
49
49
|
systemInstruction?: string;
|
|
50
50
|
}): BuildResponsesRequestResult;
|
|
51
|
+
export declare function ensureResponsesApplyPatchArguments(input?: BridgeInputItem[]): void;
|
|
51
52
|
export declare function buildResponsesPayloadFromChat(payload: unknown, context?: ResponsesRequestContext): Record<string, unknown> | unknown;
|
|
52
53
|
export declare function extractRequestIdFromResponse(response: any): string | undefined;
|
|
53
54
|
export { buildChatResponseFromResponses } from '../shared/responses-response-utils.js';
|
|
@@ -18,6 +18,7 @@ function isObject(v) {
|
|
|
18
18
|
// --- Public bridge functions ---
|
|
19
19
|
export function captureResponsesContext(payload, dto) {
|
|
20
20
|
const preservedInput = cloneBridgeEntries(payload.input);
|
|
21
|
+
ensureResponsesApplyPatchArguments(preservedInput);
|
|
21
22
|
ensureBridgeInstructions(payload);
|
|
22
23
|
const context = {
|
|
23
24
|
requestId: dto?.route?.requestId,
|
|
@@ -298,6 +299,76 @@ export function buildResponsesRequestFromChat(payload, ctx, extras) {
|
|
|
298
299
|
ensureBridgeInstructions(out);
|
|
299
300
|
return { request: out, originalSystemMessages };
|
|
300
301
|
}
|
|
302
|
+
export function ensureResponsesApplyPatchArguments(input) {
|
|
303
|
+
if (!Array.isArray(input) || !input.length) {
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
for (const entry of input) {
|
|
307
|
+
if (!entry || typeof entry !== 'object')
|
|
308
|
+
continue;
|
|
309
|
+
const type = typeof entry.type === 'string' ? entry.type.toLowerCase() : '';
|
|
310
|
+
if (type !== 'function_call')
|
|
311
|
+
continue;
|
|
312
|
+
const name = (typeof entry.name === 'string' && entry.name.trim()) ||
|
|
313
|
+
(entry.function && typeof entry.function === 'object' && typeof entry.function.name === 'string' && entry.function.name.trim()) ||
|
|
314
|
+
'';
|
|
315
|
+
if (name !== 'apply_patch')
|
|
316
|
+
continue;
|
|
317
|
+
let normalized;
|
|
318
|
+
try {
|
|
319
|
+
normalized = normalizeApplyPatchArguments(entry.arguments ?? entry.function?.arguments);
|
|
320
|
+
}
|
|
321
|
+
catch {
|
|
322
|
+
// best-effort: do not fail the whole request due to a malformed historical tool call
|
|
323
|
+
normalized = undefined;
|
|
324
|
+
}
|
|
325
|
+
if (normalized === undefined) {
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
entry.arguments = normalized;
|
|
329
|
+
if (entry.function && typeof entry.function === 'object') {
|
|
330
|
+
entry.function.arguments = normalized;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
function normalizeApplyPatchArguments(source) {
|
|
335
|
+
let parsed;
|
|
336
|
+
if (typeof source === 'string' && source.trim()) {
|
|
337
|
+
try {
|
|
338
|
+
parsed = JSON.parse(source);
|
|
339
|
+
}
|
|
340
|
+
catch {
|
|
341
|
+
parsed = { patch: source };
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
else if (source && typeof source === 'object') {
|
|
345
|
+
parsed = { ...source };
|
|
346
|
+
}
|
|
347
|
+
else if (source === undefined) {
|
|
348
|
+
parsed = {};
|
|
349
|
+
}
|
|
350
|
+
else {
|
|
351
|
+
return typeof source === 'string' ? source : undefined;
|
|
352
|
+
}
|
|
353
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
354
|
+
return typeof source === 'string' ? source : undefined;
|
|
355
|
+
}
|
|
356
|
+
const patchText = typeof parsed.patch === 'string' && parsed.patch.trim().length
|
|
357
|
+
? parsed.patch
|
|
358
|
+
: typeof parsed.input === 'string' && parsed.input.trim().length
|
|
359
|
+
? parsed.input
|
|
360
|
+
: undefined;
|
|
361
|
+
if (patchText) {
|
|
362
|
+
parsed.patch = patchText;
|
|
363
|
+
parsed.input = patchText;
|
|
364
|
+
}
|
|
365
|
+
try {
|
|
366
|
+
return JSON.stringify(parsed);
|
|
367
|
+
}
|
|
368
|
+
catch {
|
|
369
|
+
return typeof source === 'string' ? source : undefined;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
301
372
|
function readToolCallIdStyleFromContext(ctx) {
|
|
302
373
|
if (!ctx) {
|
|
303
374
|
return undefined;
|
package/node_modules/@jsonstudio/llms/dist/conversion/shared/responses-conversation-store.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
type AnyRecord = Record<string, unknown>;
|
|
2
|
+
interface CaptureContextArgs {
|
|
3
|
+
requestId?: string;
|
|
4
|
+
payload: AnyRecord;
|
|
5
|
+
context: AnyRecord;
|
|
6
|
+
}
|
|
7
|
+
interface RecordResponseArgs {
|
|
8
|
+
requestId?: string;
|
|
9
|
+
response: AnyRecord;
|
|
10
|
+
}
|
|
11
|
+
interface ResumeOptions {
|
|
12
|
+
requestId?: string;
|
|
13
|
+
}
|
|
14
|
+
interface ResumeResult {
|
|
15
|
+
payload: AnyRecord;
|
|
16
|
+
meta: AnyRecord;
|
|
17
|
+
}
|
|
18
|
+
declare class ResponsesConversationStore {
|
|
19
|
+
private requestMap;
|
|
20
|
+
private responseIndex;
|
|
21
|
+
rebindRequestId(oldId: string | undefined, newId: string | undefined): void;
|
|
22
|
+
captureRequestContext(args: CaptureContextArgs): void;
|
|
23
|
+
recordResponse(args: RecordResponseArgs): void;
|
|
24
|
+
resumeConversation(responseId: string, submitPayload: AnyRecord, options?: ResumeOptions): ResumeResult;
|
|
25
|
+
clearRequest(requestId?: string): void;
|
|
26
|
+
private cleanupEntry;
|
|
27
|
+
private prune;
|
|
28
|
+
}
|
|
29
|
+
declare const store: ResponsesConversationStore;
|
|
30
|
+
export declare function captureResponsesRequestContext(args: CaptureContextArgs): void;
|
|
31
|
+
export declare function recordResponsesResponse(args: RecordResponseArgs): void;
|
|
32
|
+
export declare function resumeResponsesConversation(responseId: string, submitPayload: AnyRecord, options?: ResumeOptions): ResumeResult;
|
|
33
|
+
export declare function clearResponsesConversationByRequestId(requestId?: string): void;
|
|
34
|
+
export declare function rebindResponsesConversationRequestId(oldId?: string, newId?: string): void;
|
|
35
|
+
export { store as responsesConversationStore };
|