@jsonstudio/llms 0.6.1739 → 0.6.1890
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/compat/actions/deepseek-web-request.d.ts +3 -0
- package/dist/conversion/compat/actions/deepseek-web-request.js +350 -0
- package/dist/conversion/compat/actions/deepseek-web-response.d.ts +3 -0
- package/dist/conversion/compat/actions/deepseek-web-response.js +886 -0
- package/dist/conversion/compat/actions/gemini-cli-request.js +3 -1
- package/dist/conversion/compat/profiles/chat-deepseek-web.json +18 -0
- package/dist/conversion/hub/operation-table/semantic-mappers/anthropic-mapper.js +166 -2
- package/dist/conversion/hub/operation-table/semantic-mappers/gemini-mapper.js +169 -0
- package/dist/conversion/hub/operation-table/semantic-mappers/responses-mapper.js +6 -0
- package/dist/conversion/hub/pipeline/compat/compat-pipeline-executor.js +12 -0
- package/dist/conversion/hub/pipeline/compat/compat-profile-resolver.js +1 -0
- package/dist/conversion/hub/pipeline/compat/compat-types.d.ts +4 -0
- package/dist/conversion/hub/pipeline/hub-pipeline.js +365 -144
- package/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage1_client_remap/index.js +9 -0
- package/dist/conversion/hub/policy/policy-engine.d.ts +2 -0
- package/dist/conversion/hub/policy/policy-engine.js +8 -0
- package/dist/conversion/hub/process/chat-process.js +466 -16
- package/dist/conversion/hub/response/provider-response.js +0 -35
- package/dist/conversion/responses/responses-openai-bridge.d.ts +2 -0
- package/dist/conversion/responses/responses-openai-bridge.js +166 -8
- package/dist/conversion/shared/anthropic-message-utils.js +10 -1
- package/dist/conversion/shared/protocol-field-allowlists.d.ts +2 -2
- package/dist/conversion/shared/protocol-field-allowlists.js +4 -0
- package/dist/conversion/shared/tool-governor.js +102 -0
- package/dist/guidance/index.js +17 -0
- package/dist/router/virtual-router/bootstrap.js +46 -1
- package/dist/router/virtual-router/classifier.js +59 -4
- package/dist/router/virtual-router/engine/health/index.js +6 -6
- package/dist/router/virtual-router/engine/routing-state/store.js +16 -3
- package/dist/router/virtual-router/engine-logging.js +62 -24
- package/dist/router/virtual-router/engine-selection/route-utils.js +20 -20
- package/dist/router/virtual-router/engine-selection/tier-selection.js +2 -2
- package/dist/router/virtual-router/engine.d.ts +3 -1
- package/dist/router/virtual-router/engine.js +359 -39
- package/dist/router/virtual-router/features.js +2 -1
- package/dist/router/virtual-router/pre-command-file-resolver.d.ts +2 -0
- package/dist/router/virtual-router/pre-command-file-resolver.js +90 -0
- package/dist/router/virtual-router/provider-registry.js +3 -1
- package/dist/router/virtual-router/routing-instructions.d.ts +15 -1
- package/dist/router/virtual-router/routing-instructions.js +110 -151
- package/dist/router/virtual-router/routing-pre-command-actions.d.ts +3 -0
- package/dist/router/virtual-router/routing-pre-command-actions.js +26 -0
- package/dist/router/virtual-router/routing-pre-command-parser.d.ts +2 -0
- package/dist/router/virtual-router/routing-pre-command-parser.js +85 -0
- package/dist/router/virtual-router/routing-pre-command-state-codec.d.ts +3 -0
- package/dist/router/virtual-router/routing-pre-command-state-codec.js +24 -0
- package/dist/router/virtual-router/routing-stop-message-actions.d.ts +2 -0
- package/dist/router/virtual-router/routing-stop-message-actions.js +96 -0
- package/dist/router/virtual-router/routing-stop-message-parser.d.ts +3 -0
- package/dist/router/virtual-router/routing-stop-message-parser.js +142 -0
- package/dist/router/virtual-router/routing-stop-message-state-codec.d.ts +4 -0
- package/dist/router/virtual-router/routing-stop-message-state-codec.js +85 -0
- package/dist/router/virtual-router/sticky-session-store.js +206 -57
- package/dist/router/virtual-router/stop-message-stage-template-files.d.ts +12 -0
- package/dist/router/virtual-router/stop-message-stage-template-files.js +67 -0
- package/dist/router/virtual-router/stop-message-state-sync.d.ts +1 -1
- package/dist/router/virtual-router/stop-message-state-sync.js +5 -0
- package/dist/router/virtual-router/token-file-scanner.d.ts +9 -0
- package/dist/router/virtual-router/token-file-scanner.js +64 -3
- package/dist/router/virtual-router/tool-signals.d.ts +5 -0
- package/dist/router/virtual-router/tool-signals.js +42 -3
- package/dist/router/virtual-router/types.d.ts +19 -1
- package/dist/router/virtual-router/types.js +1 -0
- package/dist/servertool/clock/config.d.ts +1 -1
- package/dist/servertool/clock/config.js +27 -4
- package/dist/servertool/clock/state.js +41 -2
- package/dist/servertool/clock/task-store.d.ts +2 -2
- package/dist/servertool/clock/task-store.js +1 -1
- package/dist/servertool/clock/tasks.d.ts +3 -1
- package/dist/servertool/clock/tasks.js +209 -18
- package/dist/servertool/clock/types.d.ts +17 -0
- package/dist/servertool/continue-execution/log.d.ts +3 -0
- package/dist/servertool/continue-execution/log.js +13 -0
- package/dist/servertool/engine.js +414 -68
- package/dist/servertool/handlers/antigravity-thought-signature-bootstrap.js +6 -6
- package/dist/servertool/handlers/clock-auto.js +54 -71
- package/dist/servertool/handlers/clock.js +121 -6
- package/dist/servertool/handlers/continue-execution.d.ts +1 -0
- package/dist/servertool/handlers/continue-execution.js +91 -0
- package/dist/servertool/handlers/followup-request-builder.js +13 -0
- 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/stop-message-auto.js +386 -257
- package/dist/servertool/handlers/stop-message-stage-policy.d.ts +43 -0
- package/dist/servertool/handlers/stop-message-stage-policy.js +684 -0
- package/dist/servertool/handlers/vision.js +1 -1
- package/dist/servertool/log/progress-file.d.ts +14 -0
- package/dist/servertool/log/progress-file.js +88 -0
- package/dist/servertool/pre-command-hooks.d.ts +17 -0
- package/dist/servertool/pre-command-hooks.js +491 -0
- package/dist/servertool/registry.d.ts +23 -6
- package/dist/servertool/registry.js +66 -1
- package/dist/servertool/server-side-tools.d.ts +1 -0
- package/dist/servertool/server-side-tools.js +216 -14
- package/dist/servertool/stop-gateway-context.d.ts +14 -0
- package/dist/servertool/stop-gateway-context.js +167 -0
- package/dist/servertool/stop-message-compare-context.d.ts +24 -0
- package/dist/servertool/stop-message-compare-context.js +133 -0
- package/dist/servertool/types.d.ts +12 -0
- package/dist/sse/sse-to-json/anthropic-sse-to-json-converter.d.ts +1 -0
- package/dist/sse/sse-to-json/anthropic-sse-to-json-converter.js +36 -1
- package/dist/sse/sse-to-json/builders/anthropic-response-builder.js +3 -0
- package/dist/sse/sse-to-json/chat-sse-to-json-converter.d.ts +3 -0
- package/dist/sse/sse-to-json/chat-sse-to-json-converter.js +118 -1
- package/dist/tools/apply-patch/args-normalizer/default-actions.js +1 -1
- package/package.json +1 -1
|
@@ -302,16 +302,6 @@ export async function convertProviderResponse(options) {
|
|
|
302
302
|
// 始终返回完整的 ChatCompletion JSON,便于在 llms 内部直接解析,而不是拿到
|
|
303
303
|
// __sse_responses 可读流。
|
|
304
304
|
const wantsStream = isFollowup ? false : options.wantsStream;
|
|
305
|
-
try {
|
|
306
|
-
// eslint-disable-next-line no-console
|
|
307
|
-
console.log(`\x1b[38;5;33m[servertool][orchestrator][debug] requestId=${options.context.requestId} ` +
|
|
308
|
-
`protocol=${options.providerProtocol} endpoint=${options.entryEndpoint} ` +
|
|
309
|
-
`skipServerTools=${skipServerTools} hasInvoker=${Boolean(options.providerInvoker)} ` +
|
|
310
|
-
`hasReenter=${Boolean(options.reenterPipeline)}\x1b[0m`);
|
|
311
|
-
}
|
|
312
|
-
catch {
|
|
313
|
-
/* logging best-effort */
|
|
314
|
-
}
|
|
315
305
|
const displayModel = extractDisplayModel(options.context);
|
|
316
306
|
const clientFacingRequestId = extractClientFacingRequestId(options.context) ?? options.context.requestId;
|
|
317
307
|
const plan = PROVIDER_RESPONSE_REGISTRY[options.providerProtocol];
|
|
@@ -387,14 +377,6 @@ export async function convertProviderResponse(options) {
|
|
|
387
377
|
// 使用新的 ChatEnvelope 级别的 servertool 实现
|
|
388
378
|
let effectiveChatResponse = chatResponse;
|
|
389
379
|
if (!skipServerTools && options.reenterPipeline) {
|
|
390
|
-
try {
|
|
391
|
-
// eslint-disable-next-line no-console
|
|
392
|
-
console.log(`\x1b[38;5;33m[servertool][orchestrator] start requestId=${options.context.requestId} ` +
|
|
393
|
-
`protocol=${options.providerProtocol} endpoint=${options.entryEndpoint}\x1b[0m`);
|
|
394
|
-
}
|
|
395
|
-
catch {
|
|
396
|
-
/* logging best-effort */
|
|
397
|
-
}
|
|
398
380
|
const orchestration = await runServerToolOrchestration({
|
|
399
381
|
chat: chatResponse,
|
|
400
382
|
adapterContext: options.context,
|
|
@@ -406,15 +388,6 @@ export async function convertProviderResponse(options) {
|
|
|
406
388
|
reenterPipeline: options.reenterPipeline
|
|
407
389
|
});
|
|
408
390
|
if (orchestration.executed) {
|
|
409
|
-
const flowLabel = orchestration.flowId ?? 'servertool_flow';
|
|
410
|
-
try {
|
|
411
|
-
// eslint-disable-next-line no-console
|
|
412
|
-
console.log(`\x1b[38;5;33m[servertool][orchestrator] completed requestId=${options.context.requestId} ` +
|
|
413
|
-
`mode=${flowLabel}\x1b[0m`);
|
|
414
|
-
}
|
|
415
|
-
catch {
|
|
416
|
-
/* logging best-effort */
|
|
417
|
-
}
|
|
418
391
|
effectiveChatResponse = orchestration.chat;
|
|
419
392
|
recordStage(options.stageRecorder, 'chat_process.resp.stage5.servertool_orchestration', {
|
|
420
393
|
executed: true,
|
|
@@ -424,14 +397,6 @@ export async function convertProviderResponse(options) {
|
|
|
424
397
|
});
|
|
425
398
|
}
|
|
426
399
|
else {
|
|
427
|
-
try {
|
|
428
|
-
// eslint-disable-next-line no-console
|
|
429
|
-
console.log(`\x1b[38;5;33m[servertool][orchestrator] skipped requestId=${options.context.requestId} ` +
|
|
430
|
-
'reason=no_servertool_match\x1b[0m');
|
|
431
|
-
}
|
|
432
|
-
catch {
|
|
433
|
-
/* logging best-effort */
|
|
434
|
-
}
|
|
435
400
|
recordStage(options.stageRecorder, 'chat_process.resp.stage5.servertool_orchestration', {
|
|
436
401
|
executed: false,
|
|
437
402
|
inputShape: detectProviderResponseShape(chatResponse)
|
|
@@ -10,6 +10,8 @@ export interface ResponsesRequestContext extends Unknown {
|
|
|
10
10
|
input?: BridgeInputItem[];
|
|
11
11
|
include?: unknown;
|
|
12
12
|
store?: unknown;
|
|
13
|
+
serviceTier?: unknown;
|
|
14
|
+
truncation?: unknown;
|
|
13
15
|
toolChoice?: unknown;
|
|
14
16
|
parallelToolCalls?: boolean;
|
|
15
17
|
metadata?: JsonObject;
|
|
@@ -12,6 +12,7 @@ import { normalizeMessageReasoningTools } from '../shared/reasoning-tool-normali
|
|
|
12
12
|
import { createBridgeActionState, runBridgeActionPipeline } from '../shared/bridge-actions.js';
|
|
13
13
|
import { resolveBridgePolicy, resolvePolicyActions } from '../shared/bridge-policies.js';
|
|
14
14
|
import { buildResponsesOutputFromChat } from '../shared/responses-output-builder.js';
|
|
15
|
+
import { consumeResponsesPayloadSnapshot, consumeResponsesPassthrough } from '../shared/responses-reasoning-registry.js';
|
|
15
16
|
function isObject(v) {
|
|
16
17
|
return !!v && typeof v === 'object' && !Array.isArray(v);
|
|
17
18
|
}
|
|
@@ -50,11 +51,39 @@ function filterBridgeInputForUpstream(input, options) {
|
|
|
50
51
|
export function captureResponsesContext(payload, dto) {
|
|
51
52
|
const preservedInput = cloneBridgeEntries(payload.input);
|
|
52
53
|
ensureBridgeInstructions(payload);
|
|
54
|
+
const inheritedParameters = payload.parameters && typeof payload.parameters === 'object'
|
|
55
|
+
? { ...payload.parameters }
|
|
56
|
+
: {};
|
|
57
|
+
const topLevelParameterKeys = [
|
|
58
|
+
'temperature',
|
|
59
|
+
'top_p',
|
|
60
|
+
'max_tokens',
|
|
61
|
+
'max_output_tokens',
|
|
62
|
+
'seed',
|
|
63
|
+
'logit_bias',
|
|
64
|
+
'user',
|
|
65
|
+
'parallel_tool_calls',
|
|
66
|
+
'tool_choice',
|
|
67
|
+
'response_format',
|
|
68
|
+
'service_tier',
|
|
69
|
+
'truncation',
|
|
70
|
+
'include',
|
|
71
|
+
'store',
|
|
72
|
+
'prompt_cache_key',
|
|
73
|
+
'reasoning'
|
|
74
|
+
];
|
|
75
|
+
for (const key of topLevelParameterKeys) {
|
|
76
|
+
if (payload[key] !== undefined && inheritedParameters[key] === undefined) {
|
|
77
|
+
inheritedParameters[key] = payload[key];
|
|
78
|
+
}
|
|
79
|
+
}
|
|
53
80
|
const context = {
|
|
54
81
|
requestId: dto?.route?.requestId,
|
|
55
82
|
input: preservedInput,
|
|
56
83
|
include: payload.include,
|
|
57
84
|
store: payload.store,
|
|
85
|
+
serviceTier: payload.service_tier,
|
|
86
|
+
truncation: payload.truncation,
|
|
58
87
|
toolChoice: payload.tool_choice,
|
|
59
88
|
parallelToolCalls: typeof payload.parallel_tool_calls === 'boolean' ? payload.parallel_tool_calls : undefined,
|
|
60
89
|
metadata: (payload.metadata && typeof payload.metadata === 'object') ? payload.metadata : undefined,
|
|
@@ -62,8 +91,8 @@ export function captureResponsesContext(payload, dto) {
|
|
|
62
91
|
stream: typeof payload.stream === 'boolean' ? payload.stream : undefined,
|
|
63
92
|
isChatPayload: Array.isArray(payload.messages)
|
|
64
93
|
};
|
|
65
|
-
if (
|
|
66
|
-
context.parameters =
|
|
94
|
+
if (Object.keys(inheritedParameters).length) {
|
|
95
|
+
context.parameters = inheritedParameters;
|
|
67
96
|
}
|
|
68
97
|
if (typeof payload.instructions === 'string' && payload.instructions.trim().length) {
|
|
69
98
|
context.systemInstruction = payload.instructions;
|
|
@@ -331,11 +360,14 @@ export function buildResponsesRequestFromChat(payload, ctx, extras) {
|
|
|
331
360
|
out.tools = mergedTools;
|
|
332
361
|
}
|
|
333
362
|
const passthroughKeys = [
|
|
363
|
+
'temperature',
|
|
334
364
|
'tool_choice',
|
|
335
365
|
'parallel_tool_calls',
|
|
336
366
|
'response_format',
|
|
337
367
|
'user',
|
|
338
368
|
'top_p',
|
|
369
|
+
'prompt_cache_key',
|
|
370
|
+
'reasoning',
|
|
339
371
|
'logit_bias',
|
|
340
372
|
'seed'
|
|
341
373
|
];
|
|
@@ -473,6 +505,18 @@ export function buildResponsesRequestFromChat(payload, ctx, extras) {
|
|
|
473
505
|
else if (metadataExtraFields?.response_format !== undefined && out.response_format === undefined) {
|
|
474
506
|
out.response_format = metadataExtraFields.response_format;
|
|
475
507
|
}
|
|
508
|
+
if (ctx?.serviceTier !== undefined && out.service_tier === undefined) {
|
|
509
|
+
out.service_tier = ctx.serviceTier;
|
|
510
|
+
}
|
|
511
|
+
else if (metadataExtraFields?.service_tier !== undefined && out.service_tier === undefined) {
|
|
512
|
+
out.service_tier = metadataExtraFields.service_tier;
|
|
513
|
+
}
|
|
514
|
+
if (ctx?.truncation !== undefined && out.truncation === undefined) {
|
|
515
|
+
out.truncation = ctx.truncation;
|
|
516
|
+
}
|
|
517
|
+
else if (metadataExtraFields?.truncation !== undefined && out.truncation === undefined) {
|
|
518
|
+
out.truncation = metadataExtraFields.truncation;
|
|
519
|
+
}
|
|
476
520
|
if (ctx?.metadata && Object.keys(ctx.metadata).length) {
|
|
477
521
|
out.metadata = { ...ctx.metadata };
|
|
478
522
|
}
|
|
@@ -498,6 +542,12 @@ export function buildResponsesRequestFromChat(payload, ctx, extras) {
|
|
|
498
542
|
'parallel_tool_calls',
|
|
499
543
|
'tool_choice',
|
|
500
544
|
'response_format',
|
|
545
|
+
'service_tier',
|
|
546
|
+
'truncation',
|
|
547
|
+
'include',
|
|
548
|
+
'store',
|
|
549
|
+
'prompt_cache_key',
|
|
550
|
+
'reasoning',
|
|
501
551
|
'stream'
|
|
502
552
|
]);
|
|
503
553
|
// Back-compat: StandardizedRequest uses max_tokens; map it to Responses max_output_tokens.
|
|
@@ -575,6 +625,95 @@ function extractMetadataExtraFields(metadata) {
|
|
|
575
625
|
function isPlainObject(value) {
|
|
576
626
|
return Boolean(value && typeof value === 'object' && !Array.isArray(value));
|
|
577
627
|
}
|
|
628
|
+
function deepCloneRecord(value) {
|
|
629
|
+
try {
|
|
630
|
+
const structuredCloneImpl = globalThis.structuredClone;
|
|
631
|
+
if (typeof structuredCloneImpl === 'function') {
|
|
632
|
+
return structuredCloneImpl(value);
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
catch {
|
|
636
|
+
// ignore structuredClone failures
|
|
637
|
+
}
|
|
638
|
+
try {
|
|
639
|
+
return JSON.parse(JSON.stringify(value));
|
|
640
|
+
}
|
|
641
|
+
catch {
|
|
642
|
+
return { ...value };
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
function isMissingResponseField(value) {
|
|
646
|
+
if (value === undefined || value === null) {
|
|
647
|
+
return true;
|
|
648
|
+
}
|
|
649
|
+
if (Array.isArray(value)) {
|
|
650
|
+
return value.length === 0;
|
|
651
|
+
}
|
|
652
|
+
return false;
|
|
653
|
+
}
|
|
654
|
+
function mergeResponseOutputItems(baseOutput, sourceOutput) {
|
|
655
|
+
if (!Array.isArray(baseOutput) || !Array.isArray(sourceOutput)) {
|
|
656
|
+
return baseOutput;
|
|
657
|
+
}
|
|
658
|
+
const sourceById = new Map();
|
|
659
|
+
sourceOutput.forEach((entry) => {
|
|
660
|
+
if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {
|
|
661
|
+
return;
|
|
662
|
+
}
|
|
663
|
+
const id = typeof entry.id === 'string' ? entry.id.trim() : '';
|
|
664
|
+
if (!id.length) {
|
|
665
|
+
return;
|
|
666
|
+
}
|
|
667
|
+
sourceById.set(id, entry);
|
|
668
|
+
});
|
|
669
|
+
return baseOutput.map((entry, index) => {
|
|
670
|
+
if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {
|
|
671
|
+
return entry;
|
|
672
|
+
}
|
|
673
|
+
const baseItem = deepCloneRecord(entry);
|
|
674
|
+
const baseId = typeof baseItem.id === 'string' ? String(baseItem.id).trim() : '';
|
|
675
|
+
let sourceItem;
|
|
676
|
+
if (baseId.length) {
|
|
677
|
+
sourceItem = sourceById.get(baseId);
|
|
678
|
+
}
|
|
679
|
+
if (!sourceItem) {
|
|
680
|
+
const candidate = sourceOutput[index];
|
|
681
|
+
if (candidate && typeof candidate === 'object' && !Array.isArray(candidate)) {
|
|
682
|
+
sourceItem = candidate;
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
if (!sourceItem) {
|
|
686
|
+
return baseItem;
|
|
687
|
+
}
|
|
688
|
+
if (isMissingResponseField(baseItem.content) && sourceItem.content !== undefined) {
|
|
689
|
+
baseItem.content = deepCloneRecord({ value: sourceItem.content }).value;
|
|
690
|
+
}
|
|
691
|
+
if (isMissingResponseField(baseItem.summary) && sourceItem.summary !== undefined) {
|
|
692
|
+
baseItem.summary = deepCloneRecord({ value: sourceItem.summary }).value;
|
|
693
|
+
}
|
|
694
|
+
return baseItem;
|
|
695
|
+
});
|
|
696
|
+
}
|
|
697
|
+
function mergeResponseTopLevelFields(options) {
|
|
698
|
+
const merged = deepCloneRecord(options.base);
|
|
699
|
+
const source = options.source;
|
|
700
|
+
const sourceWins = options.sourceWinsKeys ?? [];
|
|
701
|
+
for (const key of sourceWins) {
|
|
702
|
+
if (source[key] !== undefined) {
|
|
703
|
+
merged[key] = deepCloneRecord({ value: source[key] }).value;
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
const passthroughKeys = ['metadata', 'temperature', 'top_p', 'prompt_cache_key', 'reasoning'];
|
|
707
|
+
for (const key of passthroughKeys) {
|
|
708
|
+
if (source[key] !== undefined && merged[key] === undefined) {
|
|
709
|
+
merged[key] = deepCloneRecord({ value: source[key] }).value;
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
if (merged.output !== undefined && source.output !== undefined) {
|
|
713
|
+
merged.output = mergeResponseOutputItems(merged.output, source.output);
|
|
714
|
+
}
|
|
715
|
+
return merged;
|
|
716
|
+
}
|
|
578
717
|
export function buildResponsesPayloadFromChat(payload, context) {
|
|
579
718
|
if (!payload || typeof payload !== 'object')
|
|
580
719
|
return payload;
|
|
@@ -584,6 +723,11 @@ export function buildResponsesPayloadFromChat(payload, context) {
|
|
|
584
723
|
if (response.object === 'response' && Array.isArray(response.output)) {
|
|
585
724
|
return response;
|
|
586
725
|
}
|
|
726
|
+
const snapshotLookupKey = resolveSnapshotLookupKey(response, context);
|
|
727
|
+
const snapshotPayload = snapshotLookupKey ? consumeResponsesPayloadSnapshot(snapshotLookupKey) : undefined;
|
|
728
|
+
const passthroughPayload = snapshotLookupKey ? consumeResponsesPassthrough(snapshotLookupKey) : undefined;
|
|
729
|
+
const sourceForRetention = (passthroughPayload && typeof passthroughPayload === 'object' ? passthroughPayload : undefined) ??
|
|
730
|
+
(snapshotPayload && typeof snapshotPayload === 'object' ? snapshotPayload : undefined);
|
|
587
731
|
const hasChoicesArray = Array.isArray(response.choices);
|
|
588
732
|
const choicesLength = hasChoicesArray ? response.choices.length : 0;
|
|
589
733
|
// Graceful fallback for provider payloads that do not contain a valid
|
|
@@ -634,10 +778,17 @@ export function buildResponsesPayloadFromChat(payload, context) {
|
|
|
634
778
|
else if (typeof context?.requestId === 'string') {
|
|
635
779
|
out.request_id = context.requestId;
|
|
636
780
|
}
|
|
637
|
-
|
|
638
|
-
|
|
781
|
+
const mergedFallback = sourceForRetention && typeof sourceForRetention === 'object'
|
|
782
|
+
? mergeResponseTopLevelFields({
|
|
783
|
+
base: out,
|
|
784
|
+
source: sourceForRetention,
|
|
785
|
+
sourceWinsKeys: ['metadata', 'temperature', 'top_p', 'prompt_cache_key', 'reasoning']
|
|
786
|
+
})
|
|
787
|
+
: out;
|
|
788
|
+
if (mergedFallback.metadata) {
|
|
789
|
+
stripInternalToolingMetadata(mergedFallback.metadata);
|
|
639
790
|
}
|
|
640
|
-
return
|
|
791
|
+
return mergedFallback;
|
|
641
792
|
}
|
|
642
793
|
const canonical = canonicalizeChatResponseTools(response);
|
|
643
794
|
const choices = Array.isArray(canonical?.choices) ? canonical.choices : [];
|
|
@@ -742,10 +893,17 @@ export function buildResponsesPayloadFromChat(payload, context) {
|
|
|
742
893
|
else if (typeof context?.requestId === 'string') {
|
|
743
894
|
out.request_id = context.requestId;
|
|
744
895
|
}
|
|
745
|
-
|
|
746
|
-
|
|
896
|
+
const merged = sourceForRetention && typeof sourceForRetention === 'object'
|
|
897
|
+
? mergeResponseTopLevelFields({
|
|
898
|
+
base: out,
|
|
899
|
+
source: sourceForRetention,
|
|
900
|
+
sourceWinsKeys: ['metadata', 'temperature', 'top_p', 'prompt_cache_key', 'reasoning']
|
|
901
|
+
})
|
|
902
|
+
: out;
|
|
903
|
+
if (merged.metadata) {
|
|
904
|
+
stripInternalToolingMetadata(merged.metadata);
|
|
747
905
|
}
|
|
748
|
-
return
|
|
906
|
+
return merged;
|
|
749
907
|
}
|
|
750
908
|
function normalizeResponsesToolCallArgumentsForClient(responsesPayload, context) {
|
|
751
909
|
const toolsRaw = Array.isArray(context?.toolsRaw) ? context?.toolsRaw : [];
|
|
@@ -182,7 +182,8 @@ const ANTHROPIC_TOP_LEVEL_FIELDS = new Set([
|
|
|
182
182
|
'max_output_tokens',
|
|
183
183
|
'metadata',
|
|
184
184
|
'stream',
|
|
185
|
-
'tool_choice'
|
|
185
|
+
'tool_choice',
|
|
186
|
+
'thinking'
|
|
186
187
|
]);
|
|
187
188
|
export function normalizeAnthropicToolName(value) {
|
|
188
189
|
if (typeof value !== 'string') {
|
|
@@ -951,6 +952,14 @@ export function buildAnthropicRequestFromOpenAIChat(chatReq) {
|
|
|
951
952
|
if (normalizedToolChoice !== undefined) {
|
|
952
953
|
out.tool_choice = normalizedToolChoice;
|
|
953
954
|
}
|
|
955
|
+
if (requestBody.thinking !== undefined) {
|
|
956
|
+
try {
|
|
957
|
+
out.thinking = JSON.parse(JSON.stringify(requestBody.thinking));
|
|
958
|
+
}
|
|
959
|
+
catch {
|
|
960
|
+
out.thinking = requestBody.thinking;
|
|
961
|
+
}
|
|
962
|
+
}
|
|
954
963
|
try {
|
|
955
964
|
if (requestBody.metadata && typeof requestBody.metadata === 'object') {
|
|
956
965
|
out.metadata = JSON.parse(JSON.stringify(requestBody.metadata));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export declare const OPENAI_CHAT_ALLOWED_FIELDS: readonly ["messages", "tools", "tool_outputs", "model", "temperature", "top_p", "top_k", "max_tokens", "frequency_penalty", "presence_penalty", "logit_bias", "response_format", "parallel_tool_calls", "tool_choice", "seed", "user", "metadata", "stop", "stop_sequences", "stream"];
|
|
2
2
|
export declare const ANTHROPIC_ALLOWED_FIELDS: readonly ["model", "messages", "tools", "system", "stop_sequences", "temperature", "top_p", "top_k", "max_tokens", "max_output_tokens", "metadata", "stream", "tool_choice"];
|
|
3
|
-
export declare const OPENAI_RESPONSES_ALLOWED_FIELDS: readonly ["id", "object", "created_at", "model", "status", "input", "instructions", "output", "output_text", "required_action", "response_id", "previous_response_id", "tool_outputs", "tools", "metadata", "include", "store", "user", "response_format", "temperature", "top_p", "top_k", "max_tokens", "max_output_tokens", "logit_bias", "seed", "parallel_tool_calls", "tool_choice", "stream", "instructions_is_raw"];
|
|
3
|
+
export declare const OPENAI_RESPONSES_ALLOWED_FIELDS: readonly ["id", "object", "created_at", "model", "status", "input", "instructions", "output", "output_text", "required_action", "response_id", "previous_response_id", "tool_outputs", "tools", "metadata", "include", "store", "user", "response_format", "temperature", "top_p", "top_k", "max_tokens", "max_output_tokens", "logit_bias", "seed", "parallel_tool_calls", "tool_choice", "prompt_cache_key", "reasoning", "stream", "instructions_is_raw"];
|
|
4
4
|
export declare const GEMINI_ALLOWED_FIELDS: readonly ["model", "contents", "systemInstruction", "system_instruction", "generationConfig", "generation_config", "safetySettings", "safety_settings", "metadata", "toolConfig", "tool_config", "tools", "tool_choice", "parallelToolCalls", "parallel_tool_calls", "responseMimeType", "response_mime_type", "stopSequences", "stop_sequences", "cachedContent", "prompt", "response", "candidates", "usageMetadata", "responseMetadata", "promptFeedback", "modelVersion", "client", "user", "stream"];
|
|
5
|
-
export declare const OPENAI_RESPONSES_PARAMETERS_WRAPPER_ALLOW_KEYS: readonly ["temperature", "top_p", "max_output_tokens", "seed", "logit_bias", "user", "parallel_tool_calls", "tool_choice", "response_format", "stream", "stop", "stop_sequences", "modalities", "top_k"];
|
|
5
|
+
export declare const OPENAI_RESPONSES_PARAMETERS_WRAPPER_ALLOW_KEYS: readonly ["temperature", "top_p", "max_output_tokens", "seed", "logit_bias", "user", "parallel_tool_calls", "tool_choice", "response_format", "prompt_cache_key", "reasoning", "stream", "stop", "stop_sequences", "modalities", "top_k"];
|
|
6
6
|
export declare const OPENAI_CHAT_PARAMETERS_WRAPPER_ALLOW_KEYS: readonly ["temperature", "top_p", "top_k", "max_tokens", "frequency_penalty", "presence_penalty", "logit_bias", "seed", "user", "parallel_tool_calls", "tool_choice", "response_format", "stream", "stop", "stop_sequences"];
|
|
7
7
|
export declare const ANTHROPIC_PARAMETERS_WRAPPER_ALLOW_KEYS: readonly ["stop_sequences", "temperature", "top_p", "top_k", "max_tokens", "max_output_tokens", "metadata", "stream", "tool_choice"];
|
|
@@ -64,6 +64,8 @@ export const OPENAI_RESPONSES_ALLOWED_FIELDS = [
|
|
|
64
64
|
'seed',
|
|
65
65
|
'parallel_tool_calls',
|
|
66
66
|
'tool_choice',
|
|
67
|
+
'prompt_cache_key',
|
|
68
|
+
'reasoning',
|
|
67
69
|
'stream',
|
|
68
70
|
'instructions_is_raw'
|
|
69
71
|
];
|
|
@@ -109,6 +111,8 @@ export const OPENAI_RESPONSES_PARAMETERS_WRAPPER_ALLOW_KEYS = [
|
|
|
109
111
|
'parallel_tool_calls',
|
|
110
112
|
'tool_choice',
|
|
111
113
|
'response_format',
|
|
114
|
+
'prompt_cache_key',
|
|
115
|
+
'reasoning',
|
|
112
116
|
'stream',
|
|
113
117
|
'stop',
|
|
114
118
|
'stop_sequences',
|
|
@@ -13,6 +13,100 @@ function isTruthyEnv(value) {
|
|
|
13
13
|
const v = typeof value === 'string' ? value.trim().toLowerCase() : '';
|
|
14
14
|
return v === '1' || v === 'true' || v === 'yes' || v === 'on';
|
|
15
15
|
}
|
|
16
|
+
function isApplyPatchPayloadCandidate(value) {
|
|
17
|
+
if (typeof value !== 'string')
|
|
18
|
+
return false;
|
|
19
|
+
const text = value.trim();
|
|
20
|
+
if (!text)
|
|
21
|
+
return false;
|
|
22
|
+
return (text.startsWith('*** Begin Patch') ||
|
|
23
|
+
text.startsWith('*** Update File:') ||
|
|
24
|
+
text.startsWith('*** Add File:') ||
|
|
25
|
+
text.startsWith('*** Delete File:') ||
|
|
26
|
+
text.startsWith('--- a/') ||
|
|
27
|
+
text.startsWith('--- '));
|
|
28
|
+
}
|
|
29
|
+
function extractApplyPatchPayloadFromExecArgs(rawArgs) {
|
|
30
|
+
const argsStr = repairArgumentsToString(rawArgs);
|
|
31
|
+
let parsed;
|
|
32
|
+
try {
|
|
33
|
+
parsed = JSON.parse(argsStr);
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
parsed = parseLenient(argsStr);
|
|
37
|
+
}
|
|
38
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
const obj = parsed;
|
|
42
|
+
const commandValue = obj.command ?? obj.cmd;
|
|
43
|
+
if (Array.isArray(commandValue)) {
|
|
44
|
+
const tokens = commandValue.map((entry) => (typeof entry === 'string' ? entry : String(entry ?? '')));
|
|
45
|
+
if (!tokens.length)
|
|
46
|
+
return null;
|
|
47
|
+
const commandToken = tokens[0]?.trim().toLowerCase() || '';
|
|
48
|
+
const isApplyPatchCommand = commandToken === 'apply_patch' || commandToken.endsWith('/apply_patch') || commandToken.endsWith('\\apply_patch');
|
|
49
|
+
if (!isApplyPatchCommand) {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
const patchText = tokens.slice(1).join('\n').trim();
|
|
53
|
+
return isApplyPatchPayloadCandidate(patchText) ? patchText : null;
|
|
54
|
+
}
|
|
55
|
+
if (typeof commandValue === 'string') {
|
|
56
|
+
const raw = commandValue.trim();
|
|
57
|
+
if (!raw)
|
|
58
|
+
return null;
|
|
59
|
+
if (!raw.toLowerCase().startsWith('apply_patch'))
|
|
60
|
+
return null;
|
|
61
|
+
const patchText = raw.slice('apply_patch'.length).trim();
|
|
62
|
+
return isApplyPatchPayloadCandidate(patchText) ? patchText : null;
|
|
63
|
+
}
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
function rewriteExecCommandApplyPatchCall(fn) {
|
|
67
|
+
if (!fn)
|
|
68
|
+
return false;
|
|
69
|
+
const currentName = typeof fn.name === 'string' ? String(fn.name).trim().toLowerCase() : '';
|
|
70
|
+
if (currentName !== 'exec_command')
|
|
71
|
+
return false;
|
|
72
|
+
const patch = extractApplyPatchPayloadFromExecArgs(fn.arguments);
|
|
73
|
+
if (!patch)
|
|
74
|
+
return false;
|
|
75
|
+
fn.name = 'apply_patch';
|
|
76
|
+
fn.arguments = JSON.stringify({ patch, input: '' });
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
const NESTED_APPLY_PATCH_POLICY_MARKER = '[Codex NestedApplyPatch Policy]';
|
|
80
|
+
function buildNestedApplyPatchPolicyNotice(rewriteCount) {
|
|
81
|
+
const count = Number.isFinite(rewriteCount) && rewriteCount > 0 ? Math.floor(rewriteCount) : 0;
|
|
82
|
+
return [
|
|
83
|
+
NESTED_APPLY_PATCH_POLICY_MARKER,
|
|
84
|
+
'Forbidden usage detected: apply_patch must NEVER be called via exec_command or shell (detected=' + count + ').',
|
|
85
|
+
'The call was auto-rewritten to apply_patch for compatibility this turn.',
|
|
86
|
+
'Next action rule: call apply_patch directly; do not nest apply_patch inside exec_command/shell.',
|
|
87
|
+
'禁止通过 exec_command/shell 嵌套调用 apply_patch;本轮已自动改写,后续必须直接调用 apply_patch。'
|
|
88
|
+
].join('\n');
|
|
89
|
+
}
|
|
90
|
+
function injectNestedApplyPatchPolicyNotice(messages, rewriteCount) {
|
|
91
|
+
if (!Array.isArray(messages) || rewriteCount <= 0) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const exists = messages.some((entry) => {
|
|
95
|
+
if (!entry || typeof entry !== 'object')
|
|
96
|
+
return false;
|
|
97
|
+
if (entry.role !== 'system')
|
|
98
|
+
return false;
|
|
99
|
+
const content = typeof entry.content === 'string' ? String(entry.content) : '';
|
|
100
|
+
return content.includes(NESTED_APPLY_PATCH_POLICY_MARKER);
|
|
101
|
+
});
|
|
102
|
+
if (exists) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
messages.push({
|
|
106
|
+
role: 'system',
|
|
107
|
+
content: buildNestedApplyPatchPolicyNotice(rewriteCount)
|
|
108
|
+
});
|
|
109
|
+
}
|
|
16
110
|
function tryWriteSnapshot(options, stage, data) {
|
|
17
111
|
try {
|
|
18
112
|
// 仅在 verbose 级别保存快照(环境变量)
|
|
@@ -238,6 +332,7 @@ export function normalizeApplyPatchToolCallsOnResponse(chat) {
|
|
|
238
332
|
for (const tc of tcs) {
|
|
239
333
|
try {
|
|
240
334
|
const fn = tc && tc.function ? tc.function : undefined;
|
|
335
|
+
rewriteExecCommandApplyPatchCall(fn);
|
|
241
336
|
const name = typeof fn?.name === 'string' ? String(fn.name).trim().toLowerCase() : '';
|
|
242
337
|
if (name !== 'apply_patch')
|
|
243
338
|
continue;
|
|
@@ -301,6 +396,7 @@ function normalizeSpecialToolCallsOnRequest(request) {
|
|
|
301
396
|
if (lastAssistantIndex === -1) {
|
|
302
397
|
return out;
|
|
303
398
|
}
|
|
399
|
+
let rewrittenNestedApplyPatchCount = 0;
|
|
304
400
|
for (let i = 0; i < messages.length; i += 1) {
|
|
305
401
|
const msg = messages[i];
|
|
306
402
|
if (!msg || typeof msg !== 'object')
|
|
@@ -313,6 +409,9 @@ function normalizeSpecialToolCallsOnRequest(request) {
|
|
|
313
409
|
for (const tc of tcs) {
|
|
314
410
|
try {
|
|
315
411
|
const fn = tc && tc.function ? tc.function : undefined;
|
|
412
|
+
if (rewriteExecCommandApplyPatchCall(fn)) {
|
|
413
|
+
rewrittenNestedApplyPatchCount += 1;
|
|
414
|
+
}
|
|
316
415
|
const name = typeof fn?.name === 'string' ? String(fn.name).trim().toLowerCase() : '';
|
|
317
416
|
const rawArgs = fn?.arguments;
|
|
318
417
|
// apply_patch 兼容:统一生成 { patch, input }
|
|
@@ -372,6 +471,9 @@ function normalizeSpecialToolCallsOnRequest(request) {
|
|
|
372
471
|
}
|
|
373
472
|
}
|
|
374
473
|
}
|
|
474
|
+
if (rewrittenNestedApplyPatchCount > 0) {
|
|
475
|
+
injectNestedApplyPatchPolicyNotice(messages, rewrittenNestedApplyPatchCount);
|
|
476
|
+
}
|
|
375
477
|
return out;
|
|
376
478
|
}
|
|
377
479
|
catch {
|
package/dist/guidance/index.js
CHANGED
|
@@ -71,6 +71,17 @@ function buildApplyPatchGuidanceText() {
|
|
|
71
71
|
].join('\n');
|
|
72
72
|
return { marker, text };
|
|
73
73
|
}
|
|
74
|
+
function augmentExecCommand(fn) {
|
|
75
|
+
const marker = '[Codex ExecCommand Guidance]';
|
|
76
|
+
const guidance = [
|
|
77
|
+
marker,
|
|
78
|
+
'FORBIDDEN: Do NOT call apply_patch via exec_command/shell. Use apply_patch tool directly.',
|
|
79
|
+
'If you need to edit files, call apply_patch with patch text only.',
|
|
80
|
+
'exec_command is only for shell commands that are NOT apply_patch.',
|
|
81
|
+
'禁止通过 exec_command/shell 嵌套调用 apply_patch;修改文件必须直接调用 apply_patch 工具。'
|
|
82
|
+
].join('\n');
|
|
83
|
+
fn.description = appendOnce(fn.description, guidance, marker);
|
|
84
|
+
}
|
|
74
85
|
function augmentShell(fn) {
|
|
75
86
|
const marker = '[Codex Shell Guidance]';
|
|
76
87
|
const guidance = [
|
|
@@ -184,6 +195,8 @@ export function augmentOpenAITools(tools) {
|
|
|
184
195
|
try {
|
|
185
196
|
if (n === 'shell')
|
|
186
197
|
augmentShell(fn);
|
|
198
|
+
else if (n === 'exec_command')
|
|
199
|
+
augmentExecCommand(fn);
|
|
187
200
|
else if (n === 'apply_patch') {
|
|
188
201
|
const { marker, text } = buildApplyPatchGuidanceText();
|
|
189
202
|
fn.description = appendOnce(fn.description, text, marker);
|
|
@@ -219,6 +232,9 @@ export function augmentAnthropicTools(tools) {
|
|
|
219
232
|
if (name) {
|
|
220
233
|
const n = name.trim();
|
|
221
234
|
try {
|
|
235
|
+
if (n === 'exec_command') {
|
|
236
|
+
augmentExecCommand(copy);
|
|
237
|
+
}
|
|
222
238
|
if (n === 'apply_patch') {
|
|
223
239
|
schema.properties.patch = {
|
|
224
240
|
type: 'string',
|
|
@@ -269,6 +285,7 @@ export function buildSystemToolGuidance() {
|
|
|
269
285
|
lines.push(bullet('function.arguments must be a single JSON string. / arguments 必须是单个 JSON 字符串。'));
|
|
270
286
|
lines.push(bullet('shell: Place ALL intent into the command argv array only; do not invent extra keys. / shell 所有意图写入 command 数组,不要添加额外键名。'));
|
|
271
287
|
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。'));
|
|
288
|
+
lines.push(bullet('NEVER wrap apply_patch inside exec_command/shell. Direct apply_patch tool call only. / 严禁在 exec_command/shell 中嵌套 apply_patch,必须直接调用 apply_patch。'));
|
|
272
289
|
lines.push(bullet('apply_patch: Before writing, always read the target file first and compute changes against the latest content using appropriate tools. / apply_patch 在写入前必须先通过合适的工具读取目标文件最新内容,并基于该内容生成变更。'));
|
|
273
290
|
lines.push(bullet('apply_patch: Send patch text only. Supported formats: "*** Begin Patch" OR GNU unified diff. "*** Update File" never implicitly creates files—use "*** Add File:" (or /dev/null diff). / apply_patch:仅发送补丁文本,支持 "*** Begin Patch" 或 GNU diff;"*** Update File" 不会隐式创建文件。'));
|
|
274
291
|
lines.push(bullet('apply_patch: For a given file, prefer one contiguous change block per call; if you need to touch non-adjacent regions, split them into multiple apply_patch calls. / apply_patch 修改同一文件时尽量只提交一段连续补丁,多个不相邻位置请拆成多次调用。'));
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DEFAULT_MODEL_CONTEXT_TOKENS, VirtualRouterError, VirtualRouterErrorCode } from './types.js';
|
|
2
|
-
import { scanOAuthTokenFiles } from './token-file-scanner.js';
|
|
2
|
+
import { scanDeepSeekAccountTokenFiles, scanOAuthTokenFiles } from './token-file-scanner.js';
|
|
3
3
|
const DEFAULT_CLASSIFIER = {
|
|
4
4
|
longContextThresholdTokens: 180000,
|
|
5
5
|
thinkingKeywords: ['think step', 'analysis', 'reasoning', '仔细分析', '深度思考'],
|
|
@@ -196,6 +196,7 @@ function buildProviderRuntimeEntries(providers) {
|
|
|
196
196
|
modelStreaming: normalizedProvider.modelStreaming,
|
|
197
197
|
modelContextTokens: normalizedProvider.modelContextTokens,
|
|
198
198
|
defaultContextTokens: normalizedProvider.defaultContextTokens,
|
|
199
|
+
...(normalizedProvider.deepseek ? { deepseek: normalizedProvider.deepseek } : {}),
|
|
199
200
|
...(normalizedProvider.serverToolsDisabled ? { serverToolsDisabled: true } : {})
|
|
200
201
|
};
|
|
201
202
|
}
|
|
@@ -304,6 +305,7 @@ function buildProviderProfiles(targetKeys, runtimeEntries) {
|
|
|
304
305
|
responsesConfig: runtime.responsesConfig,
|
|
305
306
|
streaming: streamingPref,
|
|
306
307
|
maxContextTokens: contextTokens,
|
|
308
|
+
...(runtime.deepseek ? { deepseek: runtime.deepseek } : {}),
|
|
307
309
|
...(runtime.serverToolsDisabled ? { serverToolsDisabled: true } : {})
|
|
308
310
|
};
|
|
309
311
|
targetRuntime[targetKey] = {
|
|
@@ -526,6 +528,7 @@ function normalizeProvider(providerId, raw) {
|
|
|
526
528
|
const streaming = resolveProviderStreamingPreference(provider, responsesNode);
|
|
527
529
|
const modelStreaming = normalizeModelStreaming(provider);
|
|
528
530
|
const { modelContextTokens, defaultContextTokens } = normalizeModelContextTokens(provider);
|
|
531
|
+
const deepseek = normalizeDeepSeekOptions(provider);
|
|
529
532
|
const serverToolsDisabled = provider.serverToolsDisabled === true ||
|
|
530
533
|
(typeof provider.serverToolsDisabled === 'string' &&
|
|
531
534
|
provider.serverToolsDisabled.trim().toLowerCase() === 'true') ||
|
|
@@ -545,6 +548,7 @@ function normalizeProvider(providerId, raw) {
|
|
|
545
548
|
modelStreaming,
|
|
546
549
|
modelContextTokens,
|
|
547
550
|
defaultContextTokens,
|
|
551
|
+
...(deepseek ? { deepseek } : {}),
|
|
548
552
|
...(serverToolsDisabled ? { serverToolsDisabled: true } : {})
|
|
549
553
|
};
|
|
550
554
|
}
|
|
@@ -631,6 +635,31 @@ function normalizeModelContextTokens(provider) {
|
|
|
631
635
|
defaultContextTokens: defaultCandidate
|
|
632
636
|
};
|
|
633
637
|
}
|
|
638
|
+
function normalizeDeepSeekOptions(provider) {
|
|
639
|
+
const direct = asRecord(provider.deepseek);
|
|
640
|
+
const ext = asRecord(asRecord(provider.extensions)?.deepseek);
|
|
641
|
+
const source = Object.keys(direct).length ? direct : ext;
|
|
642
|
+
if (!source || !Object.keys(source).length) {
|
|
643
|
+
return undefined;
|
|
644
|
+
}
|
|
645
|
+
const strictToolRequired = typeof source.strictToolRequired === 'boolean'
|
|
646
|
+
? source.strictToolRequired
|
|
647
|
+
: typeof source.strictToolRequired === 'string'
|
|
648
|
+
? source.strictToolRequired.trim().toLowerCase() === 'true'
|
|
649
|
+
: undefined;
|
|
650
|
+
const textToolFallback = typeof source.textToolFallback === 'boolean'
|
|
651
|
+
? source.textToolFallback
|
|
652
|
+
: typeof source.textToolFallback === 'string'
|
|
653
|
+
? source.textToolFallback.trim().toLowerCase() === 'true'
|
|
654
|
+
: undefined;
|
|
655
|
+
if (strictToolRequired === undefined && textToolFallback === undefined) {
|
|
656
|
+
return undefined;
|
|
657
|
+
}
|
|
658
|
+
return {
|
|
659
|
+
...(strictToolRequired !== undefined ? { strictToolRequired } : {}),
|
|
660
|
+
...(textToolFallback !== undefined ? { textToolFallback } : {})
|
|
661
|
+
};
|
|
662
|
+
}
|
|
634
663
|
function resolveStreamingPreference(model) {
|
|
635
664
|
return (coerceStreamingPreference(model.streaming) ??
|
|
636
665
|
coerceStreamingPreference(model.stream) ??
|
|
@@ -1029,6 +1058,22 @@ function extractProviderAuthEntries(providerId, raw) {
|
|
|
1029
1058
|
}
|
|
1030
1059
|
}
|
|
1031
1060
|
}
|
|
1061
|
+
// DeepSeek account 多 token 自动扫描:
|
|
1062
|
+
// - 仅在未显式声明多 key 时触发;
|
|
1063
|
+
// - 从 ~/.routecodex/auth/deepseek-account-*.json 自动发现多个账号;
|
|
1064
|
+
// - alias 直接取文件名后缀,路由目标 deepseek-web.<model> 会自动扩展到所有 alias。
|
|
1065
|
+
const baseRawType = String(baseTypeInfo.raw ?? baseTypeSource ?? '').trim().toLowerCase();
|
|
1066
|
+
if (baseType === 'apiKey' && baseRawType === 'deepseek-account' && !hasExplicitEntries) {
|
|
1067
|
+
const tokenFiles = scanDeepSeekAccountTokenFiles();
|
|
1068
|
+
for (const match of tokenFiles) {
|
|
1069
|
+
const authConfig = {
|
|
1070
|
+
...defaults,
|
|
1071
|
+
type: baseTypeSource ?? 'deepseek-account',
|
|
1072
|
+
tokenFile: match.filePath
|
|
1073
|
+
};
|
|
1074
|
+
pushEntry(match.alias, authConfig);
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1032
1077
|
if (!entries.length) {
|
|
1033
1078
|
const fallbackExtras = {
|
|
1034
1079
|
value: readOptionalString(auth.value),
|