@jsonstudio/llms 0.6.2979 → 0.6.3238
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/dist/conversion/args-mapping.js +8 -0
- package/dist/conversion/{shared/bridge-actions.js → bridge-actions.js} +2 -1
- package/dist/conversion/{shared/bridge-id-utils.js → bridge-id-utils.js} +1 -1
- package/dist/conversion/{shared/bridge-instructions.js → bridge-instructions.js} +1 -1
- package/dist/conversion/{shared/bridge-message-utils.d.ts → bridge-message-utils.d.ts} +1 -1
- package/dist/conversion/{shared/bridge-message-utils.js → bridge-message-utils.js} +5 -149
- package/dist/conversion/{shared/bridge-metadata.js → bridge-metadata.js} +1 -1
- package/dist/conversion/{shared/bridge-policies.js → bridge-policies.js} +1 -1
- package/dist/conversion/codecs/gemini-openai-codec.js +27 -8
- package/dist/conversion/codecs/responses-openai-codec.js +1 -1
- package/dist/conversion/{shared/compaction-detect.d.ts → compaction-detect.d.ts} +1 -1
- package/dist/conversion/compaction-detect.js +4 -0
- package/dist/conversion/compat/actions/apply-patch-fixer.js +2 -2
- package/dist/conversion/compat/actions/deepseek-web-response.d.ts +0 -1
- package/dist/conversion/compat/actions/deepseek-web-response.js +15 -405
- package/dist/conversion/compat/actions/harvest-tool-calls-from-text.js +1 -1
- package/dist/conversion/compat/actions/lmstudio-responses-fc-ids.js +1 -1
- package/dist/conversion/compat/actions/qwen-transform.js +74 -2
- package/dist/conversion/compat/actions/snapshot.js +1 -1
- package/dist/conversion/compat/antigravity-session-signature.js +36 -0
- package/dist/conversion/compat/profiles/chat-deepseek-web.json +0 -22
- package/dist/conversion/compat/profiles/chat-glm.json +251 -72
- package/dist/conversion/compat/profiles/chat-iflow.json +174 -39
- package/dist/conversion/compat/profiles/chat-lmstudio.json +43 -14
- package/dist/conversion/hub/operation-table/operation-table-runner.js +2 -2
- package/dist/conversion/hub/operation-table/semantic-mappers/anthropic-mapper.js +1 -1
- package/dist/conversion/hub/operation-table/semantic-mappers/archive/chat-mapper.archive.d.ts +8 -0
- package/dist/conversion/hub/operation-table/semantic-mappers/archive/chat-mapper.archive.js +404 -0
- package/dist/conversion/hub/operation-table/semantic-mappers/chat-mapper.js +5 -381
- package/dist/conversion/hub/operation-table/semantic-mappers/gemini-mapper.js +2 -2
- package/dist/conversion/hub/operation-table/semantic-mappers/responses-mapper.js +2 -8
- package/dist/conversion/hub/pipeline/hub-pipeline.d.ts +1 -0
- package/dist/conversion/hub/pipeline/hub-pipeline.js +50 -3
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage2_semantic_map/index.d.ts +1 -1
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage2_semantic_map/index.js +62 -0
- package/dist/conversion/hub/pipeline/stages/req_process/req_process_stage2_route_select/index.js +3 -1
- package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage1_sse_decode/index.js +1 -1
- package/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage1_client_remap/chat-process-semantics-bridge.d.ts +1 -1
- package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage1_tool_governance/index.js +42 -29
- package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage2_finalize/index.js +12 -0
- package/dist/conversion/hub/policy/protocol-spec.js +1 -1
- package/dist/conversion/hub/process/chat-process-clock-reminders.js +1 -1
- package/dist/conversion/hub/process/chat-process-clock-tools.js +1 -1
- package/dist/conversion/hub/process/chat-process-continue-execution.js +1 -1
- package/dist/conversion/hub/process/chat-process-servertool-orchestration.js +1 -1
- package/dist/conversion/hub/process/chat-process-web-search.js +1 -1
- package/dist/conversion/hub/response/provider-response.js +14 -5
- package/dist/conversion/hub/response/response-mappers.js +23 -1
- package/dist/conversion/hub/response/response-runtime.js +28 -5
- package/dist/conversion/hub/snapshot-recorder.js +3 -92
- package/dist/conversion/hub/tool-governance/engine.d.ts +8 -0
- package/dist/conversion/hub/tool-governance/engine.js +40 -193
- package/dist/conversion/hub/tool-governance/rules.js +73 -69
- package/dist/conversion/hub/tool-surface/tool-surface-engine.js +1 -1
- package/dist/conversion/index.d.ts +1 -2
- package/dist/conversion/index.js +1 -2
- package/dist/conversion/{shared/jsonish.js → jsonish.js} +1 -1
- package/dist/conversion/{shared/mcp-injection.js → mcp-injection.js} +1 -1
- package/dist/conversion/media.js +4 -0
- package/dist/conversion/{shared/metadata-passthrough.d.ts → metadata-passthrough.d.ts} +1 -1
- package/dist/conversion/{shared/metadata-passthrough.js → metadata-passthrough.js} +2 -2
- package/dist/conversion/payload-budget.js +47 -0
- package/dist/conversion/protocol-field-allowlists.d.ts +7 -0
- package/dist/conversion/protocol-field-allowlists.js +9 -0
- package/dist/conversion/{shared/protocol-state.d.ts → protocol-state.d.ts} +2 -2
- package/dist/conversion/{shared/protocol-state.js → protocol-state.js} +2 -2
- package/dist/conversion/{shared/errors.d.ts → provider-protocol-error.d.ts} +0 -3
- package/dist/conversion/provider-protocol-error.js +25 -0
- package/dist/conversion/responses/responses-openai-bridge/response-payload.js +8 -5
- package/dist/conversion/responses/responses-openai-bridge/types.d.ts +1 -1
- package/dist/conversion/responses/responses-openai-bridge.d.ts +1 -1
- package/dist/conversion/responses/responses-openai-bridge.js +43 -10
- package/dist/conversion/{shared/runtime-metadata.d.ts → runtime-metadata.d.ts} +1 -1
- package/dist/conversion/{shared/runtime-metadata.js → runtime-metadata.js} +2 -2
- package/dist/conversion/shared/anthropic-message-utils.js +19 -8
- package/dist/conversion/shared/chat-request-filters.d.ts +3 -4
- package/dist/conversion/shared/chat-request-filters.js +22 -78
- package/dist/conversion/shared/gemini-tool-utils.d.ts +1 -1
- package/dist/conversion/shared/openai-finalizer.js +1 -0
- package/dist/conversion/shared/openai-message-normalize.js +2 -2
- package/dist/conversion/shared/reasoning-normalizer.js +6 -0
- package/dist/conversion/shared/reasoning-utils.js +5 -2
- package/dist/conversion/shared/responses-conversation-store.js +1 -1
- package/dist/conversion/shared/responses-output-builder.js +55 -11
- package/dist/conversion/shared/responses-reasoning-registry.d.ts +14 -2
- package/dist/conversion/shared/responses-reasoning-registry.js +34 -6
- package/dist/conversion/shared/responses-response-utils.js +99 -9
- package/dist/conversion/shared/responses-tool-utils.js +1 -1
- package/dist/conversion/shared/text-markup-normalizer/normalize.d.ts +1 -1
- package/dist/conversion/shared/text-markup-normalizer.d.ts +2 -2
- package/dist/conversion/shared/text-markup-normalizer.js +1 -1
- package/dist/conversion/shared/tool-filter-pipeline.js +1 -1
- package/dist/conversion/shared/tool-governor.js +3 -3
- package/dist/conversion/shared/tool-mapping.d.ts +1 -1
- package/dist/conversion/{shared/snapshot-utils.d.ts → snapshot-utils.d.ts} +11 -0
- package/dist/conversion/{shared/snapshot-utils.js → snapshot-utils.js} +14 -23
- package/dist/conversion/types/text-markup-normalizer.d.ts +13 -0
- package/dist/conversion/types/text-markup-normalizer.js +1 -0
- package/dist/filters/special/request-tools-normalize.js +1 -1
- package/dist/filters/special/response-tool-text-canonicalize.js +2 -2
- package/dist/native/router_hotpath_napi.node +0 -0
- package/dist/quota/quota-manager.js +31 -59
- package/dist/quota/quota-state.js +14 -7
- package/dist/router/virtual-router/bootstrap/profile-builder.d.ts +1 -0
- package/dist/router/virtual-router/bootstrap/profile-builder.js +13 -0
- package/dist/router/virtual-router/bootstrap/provider-normalization.d.ts +2 -0
- package/dist/router/virtual-router/bootstrap/provider-normalization.js +4 -1
- package/dist/router/virtual-router/bootstrap/streaming-helpers.d.ts +7 -0
- package/dist/router/virtual-router/bootstrap/streaming-helpers.js +44 -0
- package/dist/router/virtual-router/bootstrap.js +2 -0
- package/dist/router/virtual-router/engine/routing-state/store.d.ts +1 -2
- package/dist/router/virtual-router/engine/routing-state/store.js +2 -2
- package/dist/router/virtual-router/engine-legacy/config.d.ts +11 -0
- package/dist/router/virtual-router/engine-legacy/config.js +108 -0
- package/dist/router/virtual-router/engine-legacy/direct-model.d.ts +10 -0
- package/dist/router/virtual-router/engine-legacy/direct-model.js +38 -0
- package/dist/router/virtual-router/engine-legacy/health.d.ts +13 -0
- package/dist/router/virtual-router/engine-legacy/health.js +104 -0
- package/dist/router/virtual-router/engine-legacy/helpers.d.ts +16 -0
- package/dist/router/virtual-router/engine-legacy/helpers.js +226 -0
- package/dist/router/virtual-router/engine-legacy/route-finalize.d.ts +9 -0
- package/dist/router/virtual-router/engine-legacy/route-finalize.js +84 -0
- package/dist/router/virtual-router/engine-legacy/route-selection.d.ts +17 -0
- package/dist/router/virtual-router/engine-legacy/route-selection.js +205 -0
- package/dist/router/virtual-router/engine-legacy/route-state-allowlist.d.ts +3 -0
- package/dist/router/virtual-router/engine-legacy/route-state-allowlist.js +36 -0
- package/dist/router/virtual-router/engine-legacy/route-state.d.ts +12 -0
- package/dist/router/virtual-router/engine-legacy/route-state.js +386 -0
- package/dist/router/virtual-router/engine-legacy/route-utils.d.ts +19 -0
- package/dist/router/virtual-router/engine-legacy/route-utils.js +212 -0
- package/dist/router/virtual-router/engine-legacy/routing.d.ts +8 -0
- package/dist/router/virtual-router/engine-legacy/routing.js +8 -0
- package/dist/router/virtual-router/engine-legacy/selection-core.d.ts +28 -0
- package/dist/router/virtual-router/engine-legacy/selection-core.js +112 -0
- package/dist/router/virtual-router/engine-legacy/selection-state.d.ts +16 -0
- package/dist/router/virtual-router/engine-legacy/selection-state.js +187 -0
- package/dist/router/virtual-router/engine-legacy/state-accessors.d.ts +21 -0
- package/dist/router/virtual-router/engine-legacy/state-accessors.js +118 -0
- package/dist/router/virtual-router/engine-legacy.d.ts +123 -0
- package/dist/router/virtual-router/engine-legacy.js +194 -0
- package/dist/router/virtual-router/engine-logging.d.ts +2 -0
- package/dist/router/virtual-router/engine-logging.js +7 -2
- package/dist/router/virtual-router/engine-selection/key-parsing.js +0 -3
- package/dist/router/virtual-router/engine-selection/native-chat-request-filter-semantics.d.ts +1 -0
- package/dist/router/virtual-router/engine-selection/native-chat-request-filter-semantics.js +54 -0
- package/dist/router/virtual-router/engine-selection/native-hub-bridge-policy-semantics.d.ts +10 -0
- package/dist/router/virtual-router/engine-selection/native-hub-bridge-policy-semantics.js +67 -0
- package/dist/router/virtual-router/engine-selection/native-hub-pipeline-governance-semantics.d.ts +30 -0
- package/dist/router/virtual-router/engine-selection/native-hub-pipeline-governance-semantics.js +202 -0
- package/dist/router/virtual-router/engine-selection/native-hub-pipeline-semantic-mappers.d.ts +2 -0
- package/dist/router/virtual-router/engine-selection/native-hub-pipeline-semantic-mappers.js +83 -0
- package/dist/router/virtual-router/engine-selection/native-router-hotpath-loader.js +43 -2
- package/dist/router/virtual-router/engine-selection/native-shared-conversion-semantics.d.ts +75 -0
- package/dist/router/virtual-router/engine-selection/native-shared-conversion-semantics.js +205 -0
- package/dist/router/virtual-router/engine-selection/native-snapshot-hooks.d.ts +3 -0
- package/dist/router/virtual-router/engine-selection/native-snapshot-hooks.js +109 -0
- package/dist/router/virtual-router/engine-selection/native-virtual-router-engine-proxy.d.ts +16 -0
- package/dist/router/virtual-router/engine-selection/native-virtual-router-engine-proxy.js +14 -0
- package/dist/router/virtual-router/engine-selection/native-virtual-router-routing-instructions-semantics.d.ts +2 -0
- package/dist/router/virtual-router/engine-selection/native-virtual-router-routing-instructions-semantics.js +86 -0
- package/dist/router/virtual-router/engine-selection/tier-selection-quota-integration.js +100 -0
- package/dist/router/virtual-router/engine-selection/tier-selection-select.js +99 -0
- package/dist/router/virtual-router/engine.d.ts +22 -105
- package/dist/router/virtual-router/engine.js +274 -1641
- package/dist/router/virtual-router/load-balancer.d.ts +8 -0
- package/dist/router/virtual-router/load-balancer.js +65 -2
- package/dist/router/virtual-router/provider-registry.js +2 -0
- package/dist/router/virtual-router/routing-instructions/clean.d.ts +3 -0
- package/dist/router/virtual-router/routing-instructions/clean.js +34 -0
- package/dist/router/virtual-router/routing-instructions/parse.d.ts +18 -0
- package/dist/router/virtual-router/routing-instructions/parse.js +377 -0
- package/dist/router/virtual-router/routing-instructions/state.d.ts +4 -0
- package/dist/router/virtual-router/routing-instructions/state.js +245 -0
- package/dist/router/virtual-router/routing-instructions/types.d.ts +70 -0
- package/dist/router/virtual-router/routing-instructions/types.js +2 -0
- package/dist/router/virtual-router/routing-instructions.d.ts +5 -89
- package/dist/router/virtual-router/routing-instructions.js +4 -655
- package/dist/router/virtual-router/sticky-session-store.d.ts +4 -0
- package/dist/router/virtual-router/sticky-session-store.js +19 -81
- package/dist/router/virtual-router/tool-signals.js +21 -3
- package/dist/router/virtual-router/types.d.ts +4 -0
- package/dist/servertool/clock/session-scope.js +32 -1
- package/dist/servertool/engine.js +79 -8
- package/dist/servertool/handlers/antigravity-thought-signature-bootstrap.js +1 -1
- package/dist/servertool/handlers/clock-auto.js +1 -1
- package/dist/servertool/handlers/clock.js +1 -1
- package/dist/servertool/handlers/compaction-detect.d.ts +1 -1
- package/dist/servertool/handlers/compaction-detect.js +1 -1
- package/dist/servertool/handlers/gemini-empty-reply-continue.js +1 -1
- package/dist/servertool/handlers/iflow-model-error-retry.js +1 -1
- package/dist/servertool/handlers/recursive-detection-guard.js +1 -1
- package/dist/servertool/handlers/review.js +1 -1
- package/dist/servertool/handlers/stop-message-auto/iflow-followup.js +1 -1
- package/dist/servertool/handlers/stop-message-auto/runtime-utils.js +1 -1
- package/dist/servertool/handlers/stop-message-auto.js +1 -1
- package/dist/servertool/handlers/vision.js +1 -1
- package/dist/servertool/handlers/web-search.js +1 -1
- package/dist/servertool/reenter-backend.js +1 -1
- package/dist/servertool/server-side-tools.js +2 -2
- package/dist/servertool/stop-gateway-context.js +1 -1
- package/dist/servertool/stop-message-compare-context.js +1 -1
- package/dist/sse/json-to-sse/event-generators/responses.d.ts +4 -0
- package/dist/sse/json-to-sse/event-generators/responses.js +95 -1
- package/dist/sse/json-to-sse/sequencers/responses-sequencer.js +6 -4
- package/dist/sse/sse-to-json/builders/response-builder.d.ts +8 -0
- package/dist/sse/sse-to-json/builders/response-builder.js +162 -4
- package/dist/sse/sse-to-json/responses-sse-to-json-converter.js +2 -0
- package/dist/sse/types/responses-types.d.ts +6 -2
- package/dist/tools/apply-patch/structured/coercion.js +5 -0
- package/dist/tools/args-json.js +29 -0
- package/package.json +8 -5
- package/dist/conversion/shared/args-mapping.js +0 -77
- package/dist/conversion/shared/compaction-detect.js +0 -4
- package/dist/conversion/shared/errors.js +0 -31
- package/dist/conversion/shared/media.js +0 -4
- package/dist/conversion/shared/payload-budget.js +0 -165
- package/dist/conversion/shared/protocol-field-allowlists.d.ts +0 -7
- package/dist/conversion/shared/protocol-field-allowlists.js +0 -149
- package/dist/conversion/shared/snapshot-hooks.d.ts +0 -11
- package/dist/conversion/shared/snapshot-hooks.js +0 -503
- package/dist/conversion/shared/text-markup-normalizer/extractors-apply-patch.d.ts +0 -2
- package/dist/conversion/shared/text-markup-normalizer/extractors-apply-patch.js +0 -129
- package/dist/conversion/shared/text-markup-normalizer/extractors-json.d.ts +0 -4
- package/dist/conversion/shared/text-markup-normalizer/extractors-json.js +0 -637
- package/dist/conversion/shared/text-markup-normalizer/extractors-shared.d.ts +0 -21
- package/dist/conversion/shared/text-markup-normalizer/extractors-shared.js +0 -177
- package/dist/conversion/shared/text-markup-normalizer/extractors-transcript.d.ts +0 -5
- package/dist/conversion/shared/text-markup-normalizer/extractors-transcript.js +0 -385
- package/dist/conversion/shared/text-markup-normalizer/extractors-xml.d.ts +0 -10
- package/dist/conversion/shared/text-markup-normalizer/extractors-xml.js +0 -602
- package/dist/conversion/shared/text-markup-normalizer/extractors.d.ts +0 -5
- package/dist/conversion/shared/text-markup-normalizer/extractors.js +0 -4
- package/dist/conversion/shared/tool-canonicalizer.d.ts +0 -2
- package/dist/conversion/shared/tool-canonicalizer.js +0 -38
- /package/dist/conversion/{shared/args-mapping.d.ts → args-mapping.d.ts} +0 -0
- /package/dist/conversion/{shared/bridge-actions.d.ts → bridge-actions.d.ts} +0 -0
- /package/dist/conversion/{shared/bridge-id-utils.d.ts → bridge-id-utils.d.ts} +0 -0
- /package/dist/conversion/{shared/bridge-instructions.d.ts → bridge-instructions.d.ts} +0 -0
- /package/dist/conversion/{shared/bridge-metadata.d.ts → bridge-metadata.d.ts} +0 -0
- /package/dist/conversion/{shared/bridge-policies.d.ts → bridge-policies.d.ts} +0 -0
- /package/dist/conversion/{shared/jsonish.d.ts → jsonish.d.ts} +0 -0
- /package/dist/conversion/{shared/mcp-injection.d.ts → mcp-injection.d.ts} +0 -0
- /package/dist/conversion/{shared/media.d.ts → media.d.ts} +0 -0
- /package/dist/conversion/{shared/payload-budget.d.ts → payload-budget.d.ts} +0 -0
- /package/dist/conversion/{shared → types}/bridge-message-types.d.ts +0 -0
- /package/dist/conversion/{shared → types}/bridge-message-types.js +0 -0
|
@@ -1,503 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs/promises';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import os from 'node:os';
|
|
4
|
-
const DEFAULT_SNAPSHOT_ROOT = path.join(os.homedir(), '.routecodex', 'codex-samples');
|
|
5
|
-
const DEFAULT_ERRORSAMPLES_ROOT = path.join(os.homedir(), '.routecodex', 'errorsamples');
|
|
6
|
-
const PENDING_PROVIDER_DIR = '__pending__';
|
|
7
|
-
const POLICY_VIOLATIONS_DIR = '__policy_violations__';
|
|
8
|
-
function resolveSnapshotRoot() {
|
|
9
|
-
const envOverride = process.env.RCC_SNAPSHOT_DIR ||
|
|
10
|
-
process.env.ROUTECODEX_SNAPSHOT_DIR;
|
|
11
|
-
if (envOverride && envOverride.trim()) {
|
|
12
|
-
return path.resolve(envOverride.trim());
|
|
13
|
-
}
|
|
14
|
-
return DEFAULT_SNAPSHOT_ROOT;
|
|
15
|
-
}
|
|
16
|
-
function resolveErrorsamplesRoot() {
|
|
17
|
-
const envOverride = process.env.ROUTECODEX_ERRORSAMPLES_DIR ||
|
|
18
|
-
process.env.ROUTECODEX_ERROR_SAMPLES_DIR;
|
|
19
|
-
if (envOverride && String(envOverride).trim()) {
|
|
20
|
-
return path.resolve(String(envOverride).trim());
|
|
21
|
-
}
|
|
22
|
-
return DEFAULT_ERRORSAMPLES_ROOT;
|
|
23
|
-
}
|
|
24
|
-
function safeErrorsampleName(name) {
|
|
25
|
-
return String(name || 'sample').replace(/[^\w.-]/g, '_');
|
|
26
|
-
}
|
|
27
|
-
async function cleanupZeroByteJsonFiles(dir) {
|
|
28
|
-
let entries = [];
|
|
29
|
-
try {
|
|
30
|
-
entries = await fs.readdir(dir);
|
|
31
|
-
}
|
|
32
|
-
catch {
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
const candidates = entries.filter((name) => name.endsWith('.json'));
|
|
36
|
-
if (candidates.length === 0) {
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
await Promise.allSettled(candidates.map(async (name) => {
|
|
40
|
-
const full = path.join(dir, name);
|
|
41
|
-
try {
|
|
42
|
-
const st = await fs.stat(full);
|
|
43
|
-
if (!st.isFile() || st.size > 0) {
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
await fs.unlink(full);
|
|
47
|
-
}
|
|
48
|
-
catch {
|
|
49
|
-
// ignore cleanup failures
|
|
50
|
-
}
|
|
51
|
-
}));
|
|
52
|
-
}
|
|
53
|
-
async function writeUniqueErrorsampleFile(dir, baseName, contents) {
|
|
54
|
-
const parsed = path.parse(baseName);
|
|
55
|
-
const ext = parsed.ext || '.json';
|
|
56
|
-
const stem = parsed.name || 'sample';
|
|
57
|
-
const tmpDir = path.join(dir, '_tmp');
|
|
58
|
-
try {
|
|
59
|
-
await fs.mkdir(tmpDir, { recursive: true });
|
|
60
|
-
}
|
|
61
|
-
catch {
|
|
62
|
-
// ignore; fallback to direct writes
|
|
63
|
-
}
|
|
64
|
-
for (let i = 0; i < 32; i += 1) {
|
|
65
|
-
const suffix = `${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
66
|
-
const fileName = `${stem}_${suffix}${ext}`;
|
|
67
|
-
try {
|
|
68
|
-
const dest = path.join(dir, fileName);
|
|
69
|
-
const tmp = path.join(tmpDir, `${fileName}.tmp`);
|
|
70
|
-
await fs.writeFile(tmp, contents, { encoding: 'utf-8', flag: 'wx' });
|
|
71
|
-
await fs.rename(tmp, dest);
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
catch (error) {
|
|
75
|
-
if (toErrorCode(error) === 'EEXIST') {
|
|
76
|
-
continue;
|
|
77
|
-
}
|
|
78
|
-
throw error;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
// last resort (best-effort overwrite into a timestamped file)
|
|
82
|
-
const fallback = `${stem}_${Date.now()}_${Math.random().toString(36).slice(2, 8)}${ext}`;
|
|
83
|
-
await fs.writeFile(path.join(dir, fallback), contents, { encoding: 'utf-8' });
|
|
84
|
-
}
|
|
85
|
-
function resolveSnapshotFolder(endpoint) {
|
|
86
|
-
const lowered = (endpoint || '').trim().toLowerCase();
|
|
87
|
-
if (lowered.includes('/v1/responses') || lowered.includes('/responses.submit')) {
|
|
88
|
-
return 'openai-responses';
|
|
89
|
-
}
|
|
90
|
-
if (lowered.includes('/v1/messages')) {
|
|
91
|
-
return 'anthropic-messages';
|
|
92
|
-
}
|
|
93
|
-
return 'openai-chat';
|
|
94
|
-
}
|
|
95
|
-
function sanitizeToken(value, fallback) {
|
|
96
|
-
if (typeof value !== 'string') {
|
|
97
|
-
return fallback;
|
|
98
|
-
}
|
|
99
|
-
const trimmed = value.trim();
|
|
100
|
-
if (!trimmed) {
|
|
101
|
-
return fallback;
|
|
102
|
-
}
|
|
103
|
-
return trimmed.replace(/[^A-Za-z0-9_.-]/g, '_') || fallback;
|
|
104
|
-
}
|
|
105
|
-
function channelSuffix(channel) {
|
|
106
|
-
if (!channel) {
|
|
107
|
-
return '';
|
|
108
|
-
}
|
|
109
|
-
const token = sanitizeToken(channel, '');
|
|
110
|
-
return token ? `_${token}` : '';
|
|
111
|
-
}
|
|
112
|
-
function readStringField(value) {
|
|
113
|
-
return typeof value === 'string' && value.trim().length ? value.trim() : undefined;
|
|
114
|
-
}
|
|
115
|
-
function extractNestedProviderKey(value) {
|
|
116
|
-
if (!value || typeof value !== 'object') {
|
|
117
|
-
return undefined;
|
|
118
|
-
}
|
|
119
|
-
const obj = value;
|
|
120
|
-
const direct = readStringField(obj.providerKey) ||
|
|
121
|
-
readStringField(obj.providerId) ||
|
|
122
|
-
readStringField(obj.profileId);
|
|
123
|
-
if (direct) {
|
|
124
|
-
return direct;
|
|
125
|
-
}
|
|
126
|
-
const target = obj.target;
|
|
127
|
-
if (target && typeof target === 'object') {
|
|
128
|
-
const tk = readStringField(target.providerKey);
|
|
129
|
-
if (tk) {
|
|
130
|
-
return tk;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
const meta = obj.meta;
|
|
134
|
-
if (meta && typeof meta === 'object') {
|
|
135
|
-
const m = meta;
|
|
136
|
-
const fromMeta = readStringField(m.providerKey) ||
|
|
137
|
-
readStringField(m.providerId);
|
|
138
|
-
if (fromMeta) {
|
|
139
|
-
return fromMeta;
|
|
140
|
-
}
|
|
141
|
-
const ctx = m.context;
|
|
142
|
-
if (ctx && typeof ctx === 'object') {
|
|
143
|
-
const c = ctx;
|
|
144
|
-
const fromCtx = readStringField(c.providerKey) ||
|
|
145
|
-
readStringField(c.providerId) ||
|
|
146
|
-
readStringField(c.profileId);
|
|
147
|
-
if (fromCtx) {
|
|
148
|
-
return fromCtx;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
return undefined;
|
|
153
|
-
}
|
|
154
|
-
function extractNestedGroupRequestId(value) {
|
|
155
|
-
if (!value || typeof value !== 'object') {
|
|
156
|
-
return undefined;
|
|
157
|
-
}
|
|
158
|
-
const obj = value;
|
|
159
|
-
const direct = readStringField(obj.clientRequestId) ||
|
|
160
|
-
readStringField(obj.groupRequestId);
|
|
161
|
-
if (direct) {
|
|
162
|
-
return direct;
|
|
163
|
-
}
|
|
164
|
-
const meta = obj.meta;
|
|
165
|
-
if (meta && typeof meta === 'object') {
|
|
166
|
-
const m = meta;
|
|
167
|
-
const fromMeta = readStringField(m.clientRequestId) ||
|
|
168
|
-
readStringField(m.groupRequestId);
|
|
169
|
-
if (fromMeta) {
|
|
170
|
-
return fromMeta;
|
|
171
|
-
}
|
|
172
|
-
const ctx = m.context;
|
|
173
|
-
if (ctx && typeof ctx === 'object') {
|
|
174
|
-
const c = ctx;
|
|
175
|
-
const fromCtx = readStringField(c.clientRequestId) ||
|
|
176
|
-
readStringField(c.groupRequestId);
|
|
177
|
-
if (fromCtx) {
|
|
178
|
-
return fromCtx;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
return undefined;
|
|
183
|
-
}
|
|
184
|
-
function extractNestedEntryEndpoint(value) {
|
|
185
|
-
if (!value || typeof value !== 'object') {
|
|
186
|
-
return undefined;
|
|
187
|
-
}
|
|
188
|
-
const obj = value;
|
|
189
|
-
const direct = readStringField(obj.entryEndpoint) ||
|
|
190
|
-
readStringField(obj.entry_endpoint);
|
|
191
|
-
if (direct) {
|
|
192
|
-
return direct;
|
|
193
|
-
}
|
|
194
|
-
const meta = obj.meta;
|
|
195
|
-
if (meta && typeof meta === 'object') {
|
|
196
|
-
const m = meta;
|
|
197
|
-
const fromMeta = readStringField(m.entryEndpoint) ||
|
|
198
|
-
readStringField(m.entry_endpoint);
|
|
199
|
-
if (fromMeta) {
|
|
200
|
-
return fromMeta;
|
|
201
|
-
}
|
|
202
|
-
const ctx = m.context;
|
|
203
|
-
if (ctx && typeof ctx === 'object') {
|
|
204
|
-
const c = ctx;
|
|
205
|
-
const fromCtx = readStringField(c.entryEndpoint) ||
|
|
206
|
-
readStringField(c.entry_endpoint);
|
|
207
|
-
if (fromCtx) {
|
|
208
|
-
return fromCtx;
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
const metadata = obj.metadata;
|
|
213
|
-
if (metadata && typeof metadata === 'object') {
|
|
214
|
-
const md = metadata;
|
|
215
|
-
const fromMetadata = readStringField(md.entryEndpoint) ||
|
|
216
|
-
readStringField(md.entry_endpoint);
|
|
217
|
-
if (fromMetadata) {
|
|
218
|
-
return fromMetadata;
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
const runtime = obj.runtime;
|
|
222
|
-
if (runtime && typeof runtime === 'object') {
|
|
223
|
-
const r = runtime;
|
|
224
|
-
const fromRuntime = readStringField(r.entryEndpoint) ||
|
|
225
|
-
readStringField(r.entry_endpoint);
|
|
226
|
-
if (fromRuntime) {
|
|
227
|
-
return fromRuntime;
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
return undefined;
|
|
231
|
-
}
|
|
232
|
-
function toErrorCode(error) {
|
|
233
|
-
if (!error || typeof error !== 'object') {
|
|
234
|
-
return undefined;
|
|
235
|
-
}
|
|
236
|
-
const code = error.code;
|
|
237
|
-
return typeof code === 'string' && code.trim() ? code : undefined;
|
|
238
|
-
}
|
|
239
|
-
function readNumberField(value) {
|
|
240
|
-
return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
|
|
241
|
-
}
|
|
242
|
-
function isHubPolicyStage(stage) {
|
|
243
|
-
return typeof stage === 'string' && stage.startsWith('hub_policy.');
|
|
244
|
-
}
|
|
245
|
-
function isHubToolSurfaceStage(stage) {
|
|
246
|
-
return typeof stage === 'string' && stage.startsWith('hub_toolsurface.');
|
|
247
|
-
}
|
|
248
|
-
function hasPolicyViolations(value) {
|
|
249
|
-
if (!value || typeof value !== 'object') {
|
|
250
|
-
return false;
|
|
251
|
-
}
|
|
252
|
-
const obj = value;
|
|
253
|
-
const violations = obj.violations;
|
|
254
|
-
if (Array.isArray(violations) && violations.length > 0) {
|
|
255
|
-
return true;
|
|
256
|
-
}
|
|
257
|
-
const summary = obj.summary;
|
|
258
|
-
if (summary && typeof summary === 'object') {
|
|
259
|
-
const total = readNumberField(summary.totalViolations);
|
|
260
|
-
if (typeof total === 'number' && total > 0) {
|
|
261
|
-
return true;
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
return false;
|
|
265
|
-
}
|
|
266
|
-
function hasToolSurfaceDiff(value) {
|
|
267
|
-
if (!value || typeof value !== 'object') {
|
|
268
|
-
return false;
|
|
269
|
-
}
|
|
270
|
-
const obj = value;
|
|
271
|
-
const diffCount = readNumberField(obj.diffCount);
|
|
272
|
-
if (typeof diffCount === 'number' && diffCount > 0) {
|
|
273
|
-
return true;
|
|
274
|
-
}
|
|
275
|
-
// Response-side tool surface mismatch detection records expected/detected protocol
|
|
276
|
-
// without a numeric diffCount; treat any protocol mismatch as a diff.
|
|
277
|
-
const expected = readStringField(obj.expectedProtocol);
|
|
278
|
-
const detected = readStringField(obj.detectedProtocol);
|
|
279
|
-
if (expected && detected && expected !== detected) {
|
|
280
|
-
return true;
|
|
281
|
-
}
|
|
282
|
-
return false;
|
|
283
|
-
}
|
|
284
|
-
function hasPolicyEnforcementChanges(value) {
|
|
285
|
-
if (!value || typeof value !== 'object') {
|
|
286
|
-
return false;
|
|
287
|
-
}
|
|
288
|
-
const obj = value;
|
|
289
|
-
const removed = obj.removedTopLevelKeys;
|
|
290
|
-
if (Array.isArray(removed) && removed.length > 0) {
|
|
291
|
-
return true;
|
|
292
|
-
}
|
|
293
|
-
const flattened = obj.flattenedWrappers;
|
|
294
|
-
if (Array.isArray(flattened) && flattened.length > 0) {
|
|
295
|
-
return true;
|
|
296
|
-
}
|
|
297
|
-
return false;
|
|
298
|
-
}
|
|
299
|
-
async function writeUniqueFile(dir, baseName, contents) {
|
|
300
|
-
const parsed = path.parse(baseName);
|
|
301
|
-
const ext = parsed.ext || '.json';
|
|
302
|
-
const stem = parsed.name || 'snapshot';
|
|
303
|
-
const tmpPrefix = `.__tmp_${stem}_${process.pid}_${Date.now()}`;
|
|
304
|
-
for (let i = 0; i < 64; i += 1) {
|
|
305
|
-
const name = i === 0 ? `${stem}${ext}` : `${stem}_${i}${ext}`;
|
|
306
|
-
try {
|
|
307
|
-
const dest = path.join(dir, name);
|
|
308
|
-
const tmp = path.join(dir, `${tmpPrefix}_${Math.random().toString(36).slice(2, 8)}${ext}`);
|
|
309
|
-
await fs.writeFile(tmp, contents, { encoding: 'utf-8', flag: 'wx' });
|
|
310
|
-
try {
|
|
311
|
-
await fs.link(tmp, dest);
|
|
312
|
-
await fs.unlink(tmp).catch(() => { });
|
|
313
|
-
return;
|
|
314
|
-
}
|
|
315
|
-
catch (error) {
|
|
316
|
-
await fs.unlink(tmp).catch(() => { });
|
|
317
|
-
if (toErrorCode(error) === 'EEXIST') {
|
|
318
|
-
continue;
|
|
319
|
-
}
|
|
320
|
-
throw error;
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
catch (error) {
|
|
324
|
-
if (toErrorCode(error) === 'EEXIST') {
|
|
325
|
-
continue;
|
|
326
|
-
}
|
|
327
|
-
throw error;
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
const fallback = `${stem}_${Date.now()}_${Math.random().toString(36).slice(2, 8)}${ext}`;
|
|
331
|
-
const dest = path.join(dir, fallback);
|
|
332
|
-
const tmp = path.join(dir, `${tmpPrefix}_${Math.random().toString(36).slice(2, 8)}${ext}`);
|
|
333
|
-
await fs.writeFile(tmp, contents, { encoding: 'utf-8', flag: 'wx' });
|
|
334
|
-
try {
|
|
335
|
-
await fs.link(tmp, dest);
|
|
336
|
-
}
|
|
337
|
-
finally {
|
|
338
|
-
await fs.unlink(tmp).catch(() => { });
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
const requestProviderIndex = globalThis
|
|
342
|
-
.__routecodexSnapshotProviderIndex ||
|
|
343
|
-
new Map();
|
|
344
|
-
globalThis
|
|
345
|
-
.__routecodexSnapshotProviderIndex = requestProviderIndex;
|
|
346
|
-
async function mergeDirs(src, dest) {
|
|
347
|
-
await fs.mkdir(dest, { recursive: true });
|
|
348
|
-
let entries = [];
|
|
349
|
-
try {
|
|
350
|
-
entries = await fs.readdir(src);
|
|
351
|
-
}
|
|
352
|
-
catch {
|
|
353
|
-
return;
|
|
354
|
-
}
|
|
355
|
-
for (const name of entries) {
|
|
356
|
-
const from = path.join(src, name);
|
|
357
|
-
const to = path.join(dest, name);
|
|
358
|
-
try {
|
|
359
|
-
await fs.rename(from, to);
|
|
360
|
-
}
|
|
361
|
-
catch (error) {
|
|
362
|
-
if (toErrorCode(error) === 'EEXIST') {
|
|
363
|
-
// avoid overwriting; keep both
|
|
364
|
-
const parsed = path.parse(name);
|
|
365
|
-
const ext = parsed.ext || '';
|
|
366
|
-
const stem = parsed.name || 'snapshot';
|
|
367
|
-
const suffix = `${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
368
|
-
try {
|
|
369
|
-
await fs.rename(from, path.join(dest, `${stem}_${suffix}${ext}`));
|
|
370
|
-
}
|
|
371
|
-
catch {
|
|
372
|
-
// ignore move failure
|
|
373
|
-
}
|
|
374
|
-
continue;
|
|
375
|
-
}
|
|
376
|
-
// ignore other move failures
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
try {
|
|
380
|
-
await fs.rmdir(src);
|
|
381
|
-
}
|
|
382
|
-
catch {
|
|
383
|
-
// ignore
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
async function promotePendingDir(options) {
|
|
387
|
-
if (!options.groupRequestToken || options.providerToken === PENDING_PROVIDER_DIR) {
|
|
388
|
-
return;
|
|
389
|
-
}
|
|
390
|
-
const pending = path.join(options.root, options.folder, PENDING_PROVIDER_DIR, options.groupRequestToken);
|
|
391
|
-
const dest = path.join(options.root, options.folder, options.providerToken, options.groupRequestToken);
|
|
392
|
-
try {
|
|
393
|
-
await fs.access(pending);
|
|
394
|
-
}
|
|
395
|
-
catch {
|
|
396
|
-
return;
|
|
397
|
-
}
|
|
398
|
-
await fs.mkdir(path.dirname(dest), { recursive: true });
|
|
399
|
-
try {
|
|
400
|
-
await fs.rename(pending, dest);
|
|
401
|
-
}
|
|
402
|
-
catch {
|
|
403
|
-
// if rename fails (already exists / cross-device), merge
|
|
404
|
-
await mergeDirs(pending, dest);
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
async function writeSnapshotFile(options, rootOverride) {
|
|
408
|
-
const root = rootOverride || resolveSnapshotRoot();
|
|
409
|
-
const folder = resolveSnapshotFolder(extractNestedEntryEndpoint(options.data) || options.endpoint);
|
|
410
|
-
const stageToken = sanitizeToken(options.stage, 'snapshot');
|
|
411
|
-
const groupRequestToken = sanitizeToken(options.groupRequestId ||
|
|
412
|
-
extractNestedGroupRequestId(options.data) ||
|
|
413
|
-
options.requestId, `req_${Date.now()}`);
|
|
414
|
-
const providerFromOptions = readStringField(options.providerKey);
|
|
415
|
-
const providerFromData = extractNestedProviderKey(options.data);
|
|
416
|
-
const knownProvider = requestProviderIndex.get(groupRequestToken);
|
|
417
|
-
const providerToken = sanitizeToken(providerFromOptions || providerFromData || knownProvider || PENDING_PROVIDER_DIR, PENDING_PROVIDER_DIR);
|
|
418
|
-
if (!knownProvider && providerToken !== PENDING_PROVIDER_DIR) {
|
|
419
|
-
requestProviderIndex.set(groupRequestToken, providerToken);
|
|
420
|
-
await promotePendingDir({ root, folder, groupRequestToken, providerToken });
|
|
421
|
-
}
|
|
422
|
-
const dir = path.join(root, folder, providerToken, groupRequestToken);
|
|
423
|
-
await fs.mkdir(dir, { recursive: true });
|
|
424
|
-
// Write a stable runtime marker for this request folder (best-effort).
|
|
425
|
-
try {
|
|
426
|
-
const metaPath = path.join(dir, '__runtime.json');
|
|
427
|
-
const payload = JSON.stringify({
|
|
428
|
-
timestamp: new Date().toISOString(),
|
|
429
|
-
versions: {
|
|
430
|
-
routecodex: process.env.ROUTECODEX_VERSION,
|
|
431
|
-
routecodexBuildTime: process.env.ROUTECODEX_BUILD_TIME,
|
|
432
|
-
llmswitchCore: process.env.ROUTECODEX_LLMSWITCH_CORE_VERSION,
|
|
433
|
-
node: process.version
|
|
434
|
-
}
|
|
435
|
-
}, null, 2);
|
|
436
|
-
await fs.writeFile(metaPath, payload, { encoding: 'utf-8', flag: 'wx' }).catch(() => { });
|
|
437
|
-
}
|
|
438
|
-
catch {
|
|
439
|
-
// ignore
|
|
440
|
-
}
|
|
441
|
-
const spacing = options.verbosity === 'minimal' ? undefined : 2;
|
|
442
|
-
const payload = spacing !== undefined
|
|
443
|
-
? JSON.stringify(options.data, null, spacing)
|
|
444
|
-
: JSON.stringify(options.data);
|
|
445
|
-
const fileName = `${stageToken}${channelSuffix(options.channel)}.json`;
|
|
446
|
-
await writeUniqueFile(dir, fileName, payload);
|
|
447
|
-
}
|
|
448
|
-
export async function writeSnapshotViaHooks(options) {
|
|
449
|
-
const stage = sanitizeToken(options.stage, 'snapshot');
|
|
450
|
-
// 1) Normal snapshots (always).
|
|
451
|
-
try {
|
|
452
|
-
await writeSnapshotFile({ ...options, stage });
|
|
453
|
-
}
|
|
454
|
-
catch {
|
|
455
|
-
// snapshot writes must never block callers
|
|
456
|
-
}
|
|
457
|
-
// 2) Policy violations snapshots (copy-on-violation only).
|
|
458
|
-
// This allows leaving observe mode always on without drowning normal codex-samples traffic.
|
|
459
|
-
try {
|
|
460
|
-
if (isHubPolicyStage(stage) &&
|
|
461
|
-
(hasPolicyViolations(options.data) || hasPolicyEnforcementChanges(options.data))) {
|
|
462
|
-
const base = resolveSnapshotRoot();
|
|
463
|
-
const policyRoot = path.join(base, POLICY_VIOLATIONS_DIR);
|
|
464
|
-
await writeSnapshotFile({ ...options, stage }, policyRoot);
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
catch {
|
|
468
|
-
// never block callers
|
|
469
|
-
}
|
|
470
|
-
// 3) Tool surface diffs (copy-on-diff only) → ~/.routecodex/errorsamples/tool-surface/
|
|
471
|
-
try {
|
|
472
|
-
if (isHubToolSurfaceStage(stage) && hasToolSurfaceDiff(options.data)) {
|
|
473
|
-
const root = resolveErrorsamplesRoot();
|
|
474
|
-
const dir = path.join(root, safeErrorsampleName('tool-surface'));
|
|
475
|
-
await fs.mkdir(dir, { recursive: true });
|
|
476
|
-
// Best-effort cleanup: when the process exits abruptly, an in-flight async
|
|
477
|
-
// write can leave behind 0-byte placeholder files. Keep the observable
|
|
478
|
-
// directory clean so operators can tail it.
|
|
479
|
-
await cleanupZeroByteJsonFiles(dir);
|
|
480
|
-
const stamp = new Date().toISOString();
|
|
481
|
-
const payload = {
|
|
482
|
-
kind: 'hub_toolsurface_diff',
|
|
483
|
-
timestamp: stamp,
|
|
484
|
-
endpoint: options.endpoint,
|
|
485
|
-
stage,
|
|
486
|
-
requestId: options.requestId,
|
|
487
|
-
providerKey: options.providerKey,
|
|
488
|
-
groupRequestId: options.groupRequestId,
|
|
489
|
-
runtime: {
|
|
490
|
-
routecodexVersion: process.env.ROUTECODEX_VERSION,
|
|
491
|
-
routecodexBuildTime: process.env.ROUTECODEX_BUILD_TIME,
|
|
492
|
-
llmswitchCore: process.env.ROUTECODEX_LLMSWITCH_CORE_VERSION,
|
|
493
|
-
node: process.version
|
|
494
|
-
},
|
|
495
|
-
observation: options.data
|
|
496
|
-
};
|
|
497
|
-
await writeUniqueErrorsampleFile(dir, `${safeErrorsampleName(stage)}.json`, JSON.stringify(payload, null, 2));
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
catch {
|
|
501
|
-
// never block callers
|
|
502
|
-
}
|
|
503
|
-
}
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
import { isStructuredApplyPatchPayload } from '../../../tools/apply-patch-structured.js';
|
|
2
|
-
import { genToolCallId } from './extractors-shared.js';
|
|
3
|
-
function extractStructuredApplyPatchPayloads(text) {
|
|
4
|
-
const payloads = [];
|
|
5
|
-
try {
|
|
6
|
-
const fenceRe = /```(?:json|apply_patch|toon)?\s*([\s\S]*?)\s*```/gi;
|
|
7
|
-
let fm;
|
|
8
|
-
while ((fm = fenceRe.exec(text)) !== null) {
|
|
9
|
-
const body = fm[1] || '';
|
|
10
|
-
try {
|
|
11
|
-
const parsed = JSON.parse(body);
|
|
12
|
-
if (isStructuredApplyPatchPayload(parsed)) {
|
|
13
|
-
payloads.push(parsed);
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
catch {
|
|
17
|
-
/* ignore invalid JSON */
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
if (!payloads.length && typeof text === 'string' && text.includes('"changes"')) {
|
|
21
|
-
try {
|
|
22
|
-
const parsed = JSON.parse(text);
|
|
23
|
-
if (isStructuredApplyPatchPayload(parsed)) {
|
|
24
|
-
payloads.push(parsed);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
catch {
|
|
28
|
-
/* ignore */
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
catch {
|
|
33
|
-
/* ignore */
|
|
34
|
-
}
|
|
35
|
-
return payloads;
|
|
36
|
-
}
|
|
37
|
-
function normalizeRawApplyPatchBlock(raw) {
|
|
38
|
-
try {
|
|
39
|
-
const lines = String(raw || '')
|
|
40
|
-
.split(/\r?\n/)
|
|
41
|
-
.map((line) => line.replace(/\r/g, ''));
|
|
42
|
-
while (lines.length > 0 && !lines[0].trim()) {
|
|
43
|
-
lines.shift();
|
|
44
|
-
}
|
|
45
|
-
while (lines.length > 0 && !lines[lines.length - 1].trim()) {
|
|
46
|
-
lines.pop();
|
|
47
|
-
}
|
|
48
|
-
if (!lines.length)
|
|
49
|
-
return '';
|
|
50
|
-
const indents = lines
|
|
51
|
-
.filter((line) => line.trim().length > 0)
|
|
52
|
-
.map((line) => {
|
|
53
|
-
const m = line.match(/^[ \t]*/);
|
|
54
|
-
return m ? m[0].length : 0;
|
|
55
|
-
});
|
|
56
|
-
const minIndent = indents.length ? Math.min(...indents) : 0;
|
|
57
|
-
if (minIndent <= 0) {
|
|
58
|
-
return lines.join('\n').trim();
|
|
59
|
-
}
|
|
60
|
-
return lines
|
|
61
|
-
.map((line) => line.replace(new RegExp(`^[ \\t]{0,${minIndent}}`), ''))
|
|
62
|
-
.join('\n')
|
|
63
|
-
.trim();
|
|
64
|
-
}
|
|
65
|
-
catch {
|
|
66
|
-
return String(raw || '').trim();
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
function extractRawApplyPatchBlocks(text) {
|
|
70
|
-
const out = [];
|
|
71
|
-
try {
|
|
72
|
-
if (typeof text !== 'string' || !text)
|
|
73
|
-
return out;
|
|
74
|
-
const seen = new Set();
|
|
75
|
-
const blockRe = /\*\*\*\s*Begin Patch(?:\s*\*\*\*)?[\s\S]*?\*\*\*\s*End Patch(?:\s*\*\*\*)?/gi;
|
|
76
|
-
let m;
|
|
77
|
-
while ((m = blockRe.exec(text)) !== null) {
|
|
78
|
-
const normalized = normalizeRawApplyPatchBlock(String(m[0] || ''));
|
|
79
|
-
if (!normalized)
|
|
80
|
-
continue;
|
|
81
|
-
// Avoid turning incidental prose into apply_patch.
|
|
82
|
-
if (!/\*\*\*\s*(?:Add|Update|Delete)\s+File:/i.test(normalized))
|
|
83
|
-
continue;
|
|
84
|
-
if (seen.has(normalized))
|
|
85
|
-
continue;
|
|
86
|
-
seen.add(normalized);
|
|
87
|
-
out.push(normalized);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
catch {
|
|
91
|
-
/* ignore */
|
|
92
|
-
}
|
|
93
|
-
return out;
|
|
94
|
-
}
|
|
95
|
-
export function extractApplyPatchCallsFromText(text) {
|
|
96
|
-
try {
|
|
97
|
-
if (typeof text !== 'string' || !text)
|
|
98
|
-
return null;
|
|
99
|
-
const payloads = extractStructuredApplyPatchPayloads(text);
|
|
100
|
-
const patchBlocks = extractRawApplyPatchBlocks(text);
|
|
101
|
-
if (!payloads.length && !patchBlocks.length)
|
|
102
|
-
return null;
|
|
103
|
-
const out = [];
|
|
104
|
-
for (const payload of payloads) {
|
|
105
|
-
let argsStr = '{}';
|
|
106
|
-
try {
|
|
107
|
-
argsStr = JSON.stringify(payload);
|
|
108
|
-
}
|
|
109
|
-
catch {
|
|
110
|
-
argsStr = '{"changes":[]}';
|
|
111
|
-
}
|
|
112
|
-
out.push({ id: genToolCallId(), name: 'apply_patch', args: argsStr });
|
|
113
|
-
}
|
|
114
|
-
for (const patch of patchBlocks) {
|
|
115
|
-
let argsStr = '{}';
|
|
116
|
-
try {
|
|
117
|
-
argsStr = JSON.stringify({ patch, input: patch });
|
|
118
|
-
}
|
|
119
|
-
catch {
|
|
120
|
-
argsStr = '{"patch":""}';
|
|
121
|
-
}
|
|
122
|
-
out.push({ id: genToolCallId(), name: 'apply_patch', args: argsStr });
|
|
123
|
-
}
|
|
124
|
-
return out;
|
|
125
|
-
}
|
|
126
|
-
catch {
|
|
127
|
-
return null;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import { type TextMarkupNormalizeOptions, type ToolCallLite } from './extractors-shared.js';
|
|
2
|
-
export declare function tryParseJsonWithModelRepairs(raw: string): unknown | null;
|
|
3
|
-
export declare function salvageToolArgsFromRawText(toolName: string, rawArgs: string): Record<string, unknown> | null;
|
|
4
|
-
export declare function extractJsonToolCallsFromText(text: string, options?: TextMarkupNormalizeOptions): ToolCallLite[] | null;
|