@jsonstudio/llms 0.6.954 → 0.6.1164
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/hub/operation-table/operation-table-runner.d.ts +18 -0
- package/dist/conversion/hub/operation-table/operation-table-runner.js +158 -0
- package/dist/conversion/hub/operation-table/semantic-mappers/anthropic-mapper.d.ts +8 -0
- package/dist/conversion/hub/operation-table/semantic-mappers/anthropic-mapper.js +303 -0
- package/dist/conversion/hub/operation-table/semantic-mappers/chat-mapper.d.ts +8 -0
- package/dist/conversion/hub/operation-table/semantic-mappers/chat-mapper.js +413 -0
- package/dist/conversion/hub/operation-table/semantic-mappers/gemini-mapper.d.ts +7 -0
- package/dist/conversion/hub/operation-table/semantic-mappers/gemini-mapper.js +841 -0
- package/dist/conversion/hub/operation-table/semantic-mappers/responses-mapper.d.ts +21 -0
- package/dist/conversion/hub/operation-table/semantic-mappers/responses-mapper.js +535 -0
- package/dist/conversion/hub/ops/operations.d.ts +19 -0
- package/dist/conversion/hub/ops/operations.js +126 -0
- package/dist/conversion/hub/pipeline/hub-pipeline.d.ts +9 -0
- package/dist/conversion/hub/pipeline/hub-pipeline.js +489 -19
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage2_semantic_map/index.js +6 -0
- package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage1_semantic_map/index.js +11 -0
- package/dist/conversion/hub/policy/policy-engine.js +41 -9
- package/dist/conversion/hub/policy/protocol-spec.d.ts +25 -0
- package/dist/conversion/hub/policy/protocol-spec.js +73 -23
- package/dist/conversion/hub/process/chat-process.js +252 -41
- package/dist/conversion/hub/response/provider-response.js +175 -2
- package/dist/conversion/hub/response/response-runtime.js +1 -1
- package/dist/conversion/hub/semantic-mappers/anthropic-mapper.d.ts +1 -8
- package/dist/conversion/hub/semantic-mappers/anthropic-mapper.js +1 -365
- package/dist/conversion/hub/semantic-mappers/chat-mapper.d.ts +1 -8
- package/dist/conversion/hub/semantic-mappers/chat-mapper.js +1 -467
- package/dist/conversion/hub/semantic-mappers/gemini-mapper.d.ts +1 -7
- package/dist/conversion/hub/semantic-mappers/gemini-mapper.js +1 -903
- package/dist/conversion/hub/semantic-mappers/responses-mapper.d.ts +1 -21
- package/dist/conversion/hub/semantic-mappers/responses-mapper.js +1 -593
- package/dist/conversion/hub/tool-surface/tool-surface-engine.d.ts +18 -0
- package/dist/conversion/hub/tool-surface/tool-surface-engine.js +571 -0
- package/dist/conversion/responses/responses-openai-bridge.js +14 -2
- package/dist/conversion/shared/bridge-message-utils.js +2 -8
- package/dist/conversion/shared/bridge-policies.js +5 -105
- package/dist/conversion/shared/gemini-tool-utils.js +89 -15
- package/dist/conversion/shared/protocol-field-allowlists.d.ts +7 -0
- package/dist/conversion/shared/protocol-field-allowlists.js +145 -0
- package/dist/conversion/shared/reasoning-tool-normalizer.js +4 -2
- package/dist/conversion/shared/snapshot-hooks.js +166 -3
- package/dist/conversion/shared/text-markup-normalizer.d.ts +2 -0
- package/dist/conversion/shared/text-markup-normalizer.js +345 -9
- package/dist/conversion/shared/thought-signature-validator.d.ts +52 -0
- package/dist/conversion/shared/thought-signature-validator.js +170 -0
- package/dist/conversion/shared/tool-argument-repairer.d.ts +39 -0
- package/dist/conversion/shared/tool-argument-repairer.js +56 -0
- package/dist/conversion/shared/tool-call-id-manager.d.ts +113 -0
- package/dist/conversion/shared/tool-call-id-manager.js +231 -0
- package/dist/conversion/shared/tool-canonicalizer.js +2 -11
- package/dist/router/virtual-router/bootstrap.js +54 -5
- package/dist/router/virtual-router/engine-selection.js +132 -42
- package/dist/router/virtual-router/engine.d.ts +3 -0
- package/dist/router/virtual-router/engine.js +142 -33
- package/dist/router/virtual-router/health-weighted.d.ts +25 -0
- package/dist/router/virtual-router/health-weighted.js +63 -0
- package/dist/router/virtual-router/load-balancer.d.ts +2 -0
- package/dist/router/virtual-router/load-balancer.js +45 -16
- package/dist/router/virtual-router/routing-instructions.js +17 -1
- package/dist/router/virtual-router/sticky-session-store.js +136 -24
- package/dist/router/virtual-router/stop-message-file-resolver.d.ts +1 -0
- package/dist/router/virtual-router/stop-message-file-resolver.js +74 -0
- package/dist/router/virtual-router/stop-message-state-sync.d.ts +15 -0
- package/dist/router/virtual-router/stop-message-state-sync.js +57 -0
- package/dist/router/virtual-router/types.d.ts +70 -0
- package/dist/servertool/clock/config.d.ts +7 -0
- package/dist/servertool/clock/config.js +27 -0
- package/dist/servertool/clock/daemon.d.ts +3 -0
- package/dist/servertool/clock/daemon.js +79 -0
- package/dist/servertool/clock/io.d.ts +2 -0
- package/dist/servertool/clock/io.js +13 -0
- package/dist/servertool/clock/paths.d.ts +4 -0
- package/dist/servertool/clock/paths.js +25 -0
- package/dist/servertool/clock/session-store.d.ts +3 -0
- package/dist/servertool/clock/session-store.js +56 -0
- package/dist/servertool/clock/state.d.ts +5 -0
- package/dist/servertool/clock/state.js +62 -0
- package/dist/servertool/clock/task-store.d.ts +5 -0
- package/dist/servertool/clock/task-store.js +4 -0
- package/dist/servertool/clock/tasks.d.ts +17 -0
- package/dist/servertool/clock/tasks.js +221 -0
- package/dist/servertool/clock/types.d.ts +36 -0
- package/dist/servertool/clock/types.js +1 -0
- package/dist/servertool/engine.d.ts +2 -0
- package/dist/servertool/engine.js +161 -7
- package/dist/servertool/followup-shadow.d.ts +16 -0
- package/dist/servertool/followup-shadow.js +145 -0
- package/dist/servertool/handlers/apply-patch-guard.js +1 -265
- package/dist/servertool/handlers/clock-auto.d.ts +1 -0
- package/dist/servertool/handlers/clock-auto.js +160 -0
- package/dist/servertool/handlers/clock.d.ts +1 -0
- package/dist/servertool/handlers/clock.js +197 -0
- package/dist/servertool/handlers/exec-command-guard.js +7 -555
- package/dist/servertool/handlers/followup-request-builder.d.ts +15 -7
- package/dist/servertool/handlers/followup-request-builder.js +248 -28
- package/dist/servertool/handlers/gemini-empty-reply-continue.js +62 -169
- package/dist/servertool/handlers/iflow-model-error-retry.js +18 -28
- package/dist/servertool/handlers/recursive-detection-guard.d.ts +1 -0
- package/dist/servertool/handlers/recursive-detection-guard.js +333 -0
- package/dist/servertool/handlers/stop-message-auto.js +47 -175
- package/dist/servertool/handlers/vision.d.ts +7 -1
- package/dist/servertool/handlers/vision.js +61 -117
- package/dist/servertool/handlers/web-search.d.ts +7 -1
- package/dist/servertool/handlers/web-search.js +122 -105
- package/dist/servertool/reenter-backend.d.ts +23 -0
- package/dist/servertool/reenter-backend.js +18 -0
- package/dist/servertool/server-side-tools.d.ts +3 -2
- package/dist/servertool/server-side-tools.js +64 -10
- package/dist/servertool/types.d.ts +92 -3
- package/dist/sse/json-to-sse/event-generators/responses.js +3 -21
- package/dist/sse/shared/serializers/responses-event-serializer.d.ts +8 -0
- package/dist/sse/shared/serializers/responses-event-serializer.js +19 -0
- package/dist/sse/shared/writer.js +24 -7
- package/dist/tools/apply-patch/execution-capturer.js +3 -1
- package/dist/tools/apply-patch/json/parse-loose.d.ts +3 -0
- package/dist/tools/apply-patch/json/parse-loose.js +139 -0
- package/dist/tools/apply-patch/patch-text/context-diff.d.ts +1 -0
- package/dist/tools/apply-patch/patch-text/context-diff.js +173 -0
- package/dist/tools/apply-patch/patch-text/git-diff.d.ts +1 -0
- package/dist/tools/apply-patch/patch-text/git-diff.js +138 -0
- package/dist/tools/apply-patch/patch-text/looks-like-patch.d.ts +1 -0
- package/dist/tools/apply-patch/patch-text/looks-like-patch.js +13 -0
- package/dist/tools/apply-patch/patch-text/normalize.d.ts +3 -0
- package/dist/tools/apply-patch/patch-text/normalize.js +262 -0
- package/dist/tools/apply-patch/structured/coercion.d.ts +3 -0
- package/dist/tools/apply-patch/structured/coercion.js +82 -0
- package/dist/tools/apply-patch/validation/shared.d.ts +3 -0
- package/dist/tools/apply-patch/validation/shared.js +6 -0
- package/dist/tools/apply-patch/validator.d.ts +2 -2
- package/dist/tools/apply-patch/validator.js +6 -556
- package/package.json +1 -1
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Argument Repairer
|
|
3
|
+
*
|
|
4
|
+
* Tool calls require `function.arguments` to be a JSON string. Models often emit JSON-ish
|
|
5
|
+
* payloads (single quotes, fenced blocks, comments, trailing commas, etc.).
|
|
6
|
+
*
|
|
7
|
+
* This module provides a deterministic, best-effort repair surface that returns a JSON string
|
|
8
|
+
* or `{}` and never throws.
|
|
9
|
+
*/
|
|
10
|
+
import { repairArgumentsToString } from './jsonish.js';
|
|
11
|
+
export class ToolArgumentRepairer {
|
|
12
|
+
repairToString(args) {
|
|
13
|
+
return repairArgumentsToString(args);
|
|
14
|
+
}
|
|
15
|
+
validateAndRepair(toolName, args) {
|
|
16
|
+
const repaired = this.repairToString(args);
|
|
17
|
+
try {
|
|
18
|
+
JSON.parse(repaired);
|
|
19
|
+
return {
|
|
20
|
+
repaired,
|
|
21
|
+
success: true
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
return {
|
|
26
|
+
repaired,
|
|
27
|
+
success: false,
|
|
28
|
+
error: error instanceof Error ? error.message : String(error)
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* 批量修复工具参数
|
|
34
|
+
*
|
|
35
|
+
* @param toolCalls - 工具调用列表
|
|
36
|
+
* @returns 修复后的工具调用列表
|
|
37
|
+
*/
|
|
38
|
+
repairToolCalls(toolCalls) {
|
|
39
|
+
return toolCalls.map((call) => ({
|
|
40
|
+
name: call.name,
|
|
41
|
+
arguments: this.repairToString(call.arguments)
|
|
42
|
+
}));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* 快捷函数:修复工具参数
|
|
47
|
+
*/
|
|
48
|
+
export function repairToolArguments(args) {
|
|
49
|
+
return new ToolArgumentRepairer().repairToString(args);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* 快捷函数:验证并修复工具参数
|
|
53
|
+
*/
|
|
54
|
+
export function validateToolArguments(toolName, args) {
|
|
55
|
+
return new ToolArgumentRepairer().validateAndRepair(toolName, args);
|
|
56
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Call ID Manager
|
|
3
|
+
*
|
|
4
|
+
* 提供统一的工具调用 ID 生成、规范化和风格管理功能。
|
|
5
|
+
* 支持 'fc' (function call) 和 'preserve' 两种风格。
|
|
6
|
+
*/
|
|
7
|
+
import type { JsonObject } from '../hub/types/json.js';
|
|
8
|
+
export type ToolCallIdStyle = 'fc' | 'preserve';
|
|
9
|
+
export interface ToolCallIdManagerOptions {
|
|
10
|
+
/**
|
|
11
|
+
* ID 风格
|
|
12
|
+
* - 'fc': 使用 fc_ 前缀的短 ID(如 fc_abc123)
|
|
13
|
+
* - 'preserve': 保留原始 ID
|
|
14
|
+
*/
|
|
15
|
+
style?: ToolCallIdStyle;
|
|
16
|
+
/**
|
|
17
|
+
* ID 前缀(仅用于 'fc' 风格)
|
|
18
|
+
* 默认 'fc_'
|
|
19
|
+
*/
|
|
20
|
+
prefix?: string;
|
|
21
|
+
/**
|
|
22
|
+
* ID 长度(仅用于 'fc' 风格)
|
|
23
|
+
* 默认 8
|
|
24
|
+
*/
|
|
25
|
+
idLength?: number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* 工具调用 ID 管理器
|
|
29
|
+
*/
|
|
30
|
+
export declare class ToolCallIdManager {
|
|
31
|
+
private options;
|
|
32
|
+
private counter;
|
|
33
|
+
constructor(options?: ToolCallIdManagerOptions);
|
|
34
|
+
/**
|
|
35
|
+
* 生成新的工具调用 ID
|
|
36
|
+
*/
|
|
37
|
+
generateId(): string;
|
|
38
|
+
/**
|
|
39
|
+
* 规范化工具调用 ID
|
|
40
|
+
*
|
|
41
|
+
* @param id - 原始 ID
|
|
42
|
+
* @returns 规范化后的 ID
|
|
43
|
+
*/
|
|
44
|
+
normalizeId(id: string | undefined | null): string;
|
|
45
|
+
/**
|
|
46
|
+
* 规范化工具调用 ID(带别名注册)
|
|
47
|
+
*
|
|
48
|
+
* @param id - 原始 ID
|
|
49
|
+
* @param aliasMap - 别名映射(用于 preserve 风格)
|
|
50
|
+
* @returns 规范化后的 ID
|
|
51
|
+
*/
|
|
52
|
+
normalizeIdWithAlias(id: string | undefined | null, aliasMap?: Map<string, string>): string;
|
|
53
|
+
/**
|
|
54
|
+
* 批量规范化工具调用 ID
|
|
55
|
+
*
|
|
56
|
+
* @param ids - ID 列表
|
|
57
|
+
* @returns 规范化后的 ID 列表
|
|
58
|
+
*/
|
|
59
|
+
normalizeIds(ids: (string | undefined | null)[]): string[];
|
|
60
|
+
/**
|
|
61
|
+
* 检查 ID 是否为有效的 fc_ 风格
|
|
62
|
+
*/
|
|
63
|
+
isValidFcStyle(id: string): boolean;
|
|
64
|
+
/**
|
|
65
|
+
* 从 ID 中提取基础部分(移除前缀)
|
|
66
|
+
*/
|
|
67
|
+
extractBaseId(id: string): string;
|
|
68
|
+
/**
|
|
69
|
+
* 重置计数器
|
|
70
|
+
*/
|
|
71
|
+
resetCounter(): void;
|
|
72
|
+
/**
|
|
73
|
+
* 获取当前配置
|
|
74
|
+
*/
|
|
75
|
+
getOptions(): ToolCallIdManagerOptions;
|
|
76
|
+
/**
|
|
77
|
+
* 更新配置
|
|
78
|
+
*/
|
|
79
|
+
updateOptions(options: Partial<ToolCallIdManagerOptions>): void;
|
|
80
|
+
/**
|
|
81
|
+
* 生成 UUID(用于 preserve 风格)
|
|
82
|
+
*/
|
|
83
|
+
private generateUUID;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* 规范化工具调用 ID 值
|
|
87
|
+
*
|
|
88
|
+
* @param value - ID 值(可能是字符串或其他类型)
|
|
89
|
+
* @param forceGenerate - 如果为 true,总是生成新 ID
|
|
90
|
+
* @returns 规范化后的 ID 字符串
|
|
91
|
+
*/
|
|
92
|
+
export declare function normalizeIdValue(value: unknown, forceGenerate?: boolean): string;
|
|
93
|
+
/**
|
|
94
|
+
* 从对象中提取工具调用 ID
|
|
95
|
+
*
|
|
96
|
+
* @param obj - 包含 ID 的对象
|
|
97
|
+
* @returns 提取的 ID
|
|
98
|
+
*/
|
|
99
|
+
export declare function extractToolCallId(obj: unknown): string | undefined;
|
|
100
|
+
/**
|
|
101
|
+
* 创建工具调用 ID 转换器(用于 Responses 格式)
|
|
102
|
+
*
|
|
103
|
+
* @param style - ID 风格
|
|
104
|
+
* @returns 转换器函数
|
|
105
|
+
*/
|
|
106
|
+
export declare function createToolCallIdTransformer(style: ToolCallIdStyle): ((id: string) => string) | null;
|
|
107
|
+
/**
|
|
108
|
+
* 在消息列表中强制应用工具调用 ID 风格
|
|
109
|
+
*
|
|
110
|
+
* @param messages - 消息列表
|
|
111
|
+
* @param transformer - ID 转换器
|
|
112
|
+
*/
|
|
113
|
+
export declare function enforceToolCallIdStyle(messages: JsonObject[], transformer: (id: string) => string): void;
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Call ID Manager
|
|
3
|
+
*
|
|
4
|
+
* 提供统一的工具调用 ID 生成、规范化和风格管理功能。
|
|
5
|
+
* 支持 'fc' (function call) 和 'preserve' 两种风格。
|
|
6
|
+
*/
|
|
7
|
+
const DEFAULT_OPTIONS = {
|
|
8
|
+
style: 'fc',
|
|
9
|
+
prefix: 'fc_',
|
|
10
|
+
idLength: 8
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* 工具调用 ID 管理器
|
|
14
|
+
*/
|
|
15
|
+
export class ToolCallIdManager {
|
|
16
|
+
options;
|
|
17
|
+
counter = 0;
|
|
18
|
+
constructor(options) {
|
|
19
|
+
this.options = { ...DEFAULT_OPTIONS, ...options };
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* 生成新的工具调用 ID
|
|
23
|
+
*/
|
|
24
|
+
generateId() {
|
|
25
|
+
if (this.options.style === 'fc') {
|
|
26
|
+
return `${this.options.prefix}${this.counter++}`;
|
|
27
|
+
}
|
|
28
|
+
// preserve 风格:使用 UUID
|
|
29
|
+
return this.generateUUID();
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* 规范化工具调用 ID
|
|
33
|
+
*
|
|
34
|
+
* @param id - 原始 ID
|
|
35
|
+
* @returns 规范化后的 ID
|
|
36
|
+
*/
|
|
37
|
+
normalizeId(id) {
|
|
38
|
+
if (!id) {
|
|
39
|
+
return this.generateId();
|
|
40
|
+
}
|
|
41
|
+
const trimmed = id.trim();
|
|
42
|
+
if (!trimmed) {
|
|
43
|
+
return this.generateId();
|
|
44
|
+
}
|
|
45
|
+
if (this.options.style === 'fc') {
|
|
46
|
+
// fc 风格:提取或生成 fc_ 风格 ID
|
|
47
|
+
const fcMatch = trimmed.match(/fc_([a-z0-9]+)/i);
|
|
48
|
+
if (fcMatch) {
|
|
49
|
+
return `fc_${fcMatch[1]}`;
|
|
50
|
+
}
|
|
51
|
+
// 如果不是 fc_ 风格,生成新的 fc_ ID
|
|
52
|
+
return this.generateId();
|
|
53
|
+
}
|
|
54
|
+
// preserve 风格:保留原始 ID
|
|
55
|
+
return trimmed;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* 规范化工具调用 ID(带别名注册)
|
|
59
|
+
*
|
|
60
|
+
* @param id - 原始 ID
|
|
61
|
+
* @param aliasMap - 别名映射(用于 preserve 风格)
|
|
62
|
+
* @returns 规范化后的 ID
|
|
63
|
+
*/
|
|
64
|
+
normalizeIdWithAlias(id, aliasMap) {
|
|
65
|
+
if (!id) {
|
|
66
|
+
return this.generateId();
|
|
67
|
+
}
|
|
68
|
+
const trimmed = id.trim();
|
|
69
|
+
if (!trimmed) {
|
|
70
|
+
return this.generateId();
|
|
71
|
+
}
|
|
72
|
+
if (this.options.style === 'fc') {
|
|
73
|
+
return this.normalizeId(id);
|
|
74
|
+
}
|
|
75
|
+
// preserve 风格:检查是否已有别名
|
|
76
|
+
if (aliasMap && aliasMap.has(trimmed)) {
|
|
77
|
+
return aliasMap.get(trimmed);
|
|
78
|
+
}
|
|
79
|
+
// 没有别名,保留原始 ID
|
|
80
|
+
return trimmed;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* 批量规范化工具调用 ID
|
|
84
|
+
*
|
|
85
|
+
* @param ids - ID 列表
|
|
86
|
+
* @returns 规范化后的 ID 列表
|
|
87
|
+
*/
|
|
88
|
+
normalizeIds(ids) {
|
|
89
|
+
return ids.map(id => this.normalizeId(id));
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* 检查 ID 是否为有效的 fc_ 风格
|
|
93
|
+
*/
|
|
94
|
+
isValidFcStyle(id) {
|
|
95
|
+
return /^fc_[a-z0-9]+$/i.test(id);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* 从 ID 中提取基础部分(移除前缀)
|
|
99
|
+
*/
|
|
100
|
+
extractBaseId(id) {
|
|
101
|
+
if (this.options.style === 'fc') {
|
|
102
|
+
const match = id.match(/^fc_(.+)$/i);
|
|
103
|
+
return match ? match[1] : id;
|
|
104
|
+
}
|
|
105
|
+
return id;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* 重置计数器
|
|
109
|
+
*/
|
|
110
|
+
resetCounter() {
|
|
111
|
+
this.counter = 0;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* 获取当前配置
|
|
115
|
+
*/
|
|
116
|
+
getOptions() {
|
|
117
|
+
return { ...this.options };
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* 更新配置
|
|
121
|
+
*/
|
|
122
|
+
updateOptions(options) {
|
|
123
|
+
this.options = { ...this.options, ...options };
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* 生成 UUID(用于 preserve 风格)
|
|
127
|
+
*/
|
|
128
|
+
generateUUID() {
|
|
129
|
+
// 简单的 UUID 生成(生产环境建议使用 crypto.randomUUID())
|
|
130
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
|
131
|
+
const r = Math.random() * 16 | 0;
|
|
132
|
+
const v = c === 'x' ? r : (r & 0x3 | 0x8);
|
|
133
|
+
return v.toString(16);
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* 规范化工具调用 ID 值
|
|
139
|
+
*
|
|
140
|
+
* @param value - ID 值(可能是字符串或其他类型)
|
|
141
|
+
* @param forceGenerate - 如果为 true,总是生成新 ID
|
|
142
|
+
* @returns 规范化后的 ID 字符串
|
|
143
|
+
*/
|
|
144
|
+
export function normalizeIdValue(value, forceGenerate = false) {
|
|
145
|
+
if (forceGenerate) {
|
|
146
|
+
const manager = new ToolCallIdManager();
|
|
147
|
+
return manager.generateId();
|
|
148
|
+
}
|
|
149
|
+
if (typeof value === 'string' && value.trim()) {
|
|
150
|
+
return value.trim();
|
|
151
|
+
}
|
|
152
|
+
// 生成默认 ID
|
|
153
|
+
const manager = new ToolCallIdManager();
|
|
154
|
+
return manager.generateId();
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* 从对象中提取工具调用 ID
|
|
158
|
+
*
|
|
159
|
+
* @param obj - 包含 ID 的对象
|
|
160
|
+
* @returns 提取的 ID
|
|
161
|
+
*/
|
|
162
|
+
export function extractToolCallId(obj) {
|
|
163
|
+
if (!obj || typeof obj !== 'object') {
|
|
164
|
+
return undefined;
|
|
165
|
+
}
|
|
166
|
+
const record = obj;
|
|
167
|
+
// 按优先级查找:tool_call_id > call_id > id > tool_use_id
|
|
168
|
+
const id = record.tool_call_id ??
|
|
169
|
+
record.call_id ??
|
|
170
|
+
record.id ??
|
|
171
|
+
record.tool_use_id;
|
|
172
|
+
return typeof id === 'string' ? id : undefined;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* 创建工具调用 ID 转换器(用于 Responses 格式)
|
|
176
|
+
*
|
|
177
|
+
* @param style - ID 风格
|
|
178
|
+
* @returns 转换器函数
|
|
179
|
+
*/
|
|
180
|
+
export function createToolCallIdTransformer(style) {
|
|
181
|
+
const manager = new ToolCallIdManager({ style });
|
|
182
|
+
const aliasMap = new Map();
|
|
183
|
+
if (style === 'fc') {
|
|
184
|
+
return (id) => manager.normalizeId(id);
|
|
185
|
+
}
|
|
186
|
+
if (style === 'preserve') {
|
|
187
|
+
return (id) => {
|
|
188
|
+
const normalized = manager.normalizeIdWithAlias(id, aliasMap);
|
|
189
|
+
// 如果 ID 是新的,注册别名
|
|
190
|
+
if (!aliasMap.has(id)) {
|
|
191
|
+
aliasMap.set(id, normalized);
|
|
192
|
+
}
|
|
193
|
+
return normalized;
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* 在消息列表中强制应用工具调用 ID 风格
|
|
200
|
+
*
|
|
201
|
+
* @param messages - 消息列表
|
|
202
|
+
* @param transformer - ID 转换器
|
|
203
|
+
*/
|
|
204
|
+
export function enforceToolCallIdStyle(messages, transformer) {
|
|
205
|
+
if (!messages || !Array.isArray(messages)) {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
for (const message of messages) {
|
|
209
|
+
if (!message || typeof message !== 'object')
|
|
210
|
+
continue;
|
|
211
|
+
const role = message.role;
|
|
212
|
+
// 处理 assistant 消息的 tool_calls
|
|
213
|
+
if (role === 'assistant' && Array.isArray(message.tool_calls)) {
|
|
214
|
+
for (const call of message.tool_calls) {
|
|
215
|
+
if (!call || typeof call !== 'object')
|
|
216
|
+
continue;
|
|
217
|
+
const id = extractToolCallId(call);
|
|
218
|
+
if (id) {
|
|
219
|
+
call.id = transformer(id);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
// 处理 tool 消息的 tool_call_id
|
|
224
|
+
if (role === 'tool') {
|
|
225
|
+
const id = extractToolCallId(message);
|
|
226
|
+
if (id) {
|
|
227
|
+
message.tool_call_id = transformer(id);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
@@ -1,17 +1,8 @@
|
|
|
1
1
|
// Minimal canonicalizer to ensure tool_calls invariants without altering semantics
|
|
2
|
+
import { repairToolArguments } from './tool-argument-repairer.js';
|
|
2
3
|
function isObject(v) {
|
|
3
4
|
return !!v && typeof v === 'object' && !Array.isArray(v);
|
|
4
5
|
}
|
|
5
|
-
function repairArgumentsToString(args) {
|
|
6
|
-
if (typeof args === 'string')
|
|
7
|
-
return args;
|
|
8
|
-
try {
|
|
9
|
-
return JSON.stringify(args ?? {});
|
|
10
|
-
}
|
|
11
|
-
catch {
|
|
12
|
-
return String(args);
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
6
|
export function canonicalizeChatResponseTools(payload) {
|
|
16
7
|
try {
|
|
17
8
|
const out = isObject(payload) ? JSON.parse(JSON.stringify(payload)) : payload;
|
|
@@ -36,7 +27,7 @@ export function canonicalizeChatResponseTools(payload) {
|
|
|
36
27
|
try {
|
|
37
28
|
const fn = tc && tc.function ? tc.function : undefined;
|
|
38
29
|
if (fn)
|
|
39
|
-
fn.arguments =
|
|
30
|
+
fn.arguments = repairToolArguments(fn.arguments);
|
|
40
31
|
}
|
|
41
32
|
catch { /* ignore */ }
|
|
42
33
|
}
|
|
@@ -30,6 +30,7 @@ export function bootstrapVirtualRouterConfig(input) {
|
|
|
30
30
|
const webSearch = normalizeWebSearch(section.webSearch, routingSource);
|
|
31
31
|
validateWebSearchRouting(webSearch, routingSource);
|
|
32
32
|
const execCommandGuard = normalizeExecCommandGuard(section.execCommandGuard);
|
|
33
|
+
const clock = normalizeClock(section.clock);
|
|
33
34
|
const { runtimeEntries, aliasIndex, modelIndex } = buildProviderRuntimeEntries(providersSource);
|
|
34
35
|
const { routing, targetKeys } = expandRoutingTable(routingSource, aliasIndex);
|
|
35
36
|
if (!routing.default || routing.default.length === 0) {
|
|
@@ -67,7 +68,8 @@ export function bootstrapVirtualRouterConfig(input) {
|
|
|
67
68
|
health,
|
|
68
69
|
contextRouting,
|
|
69
70
|
...(webSearch ? { webSearch } : {}),
|
|
70
|
-
...(execCommandGuard ? { execCommandGuard } : {})
|
|
71
|
+
...(execCommandGuard ? { execCommandGuard } : {}),
|
|
72
|
+
...(clock ? { clock } : {})
|
|
71
73
|
};
|
|
72
74
|
return {
|
|
73
75
|
config,
|
|
@@ -90,7 +92,31 @@ function extractVirtualRouterSection(input) {
|
|
|
90
92
|
const contextRouting = normalizeContextRouting(section.contextRouting ?? root.contextRouting);
|
|
91
93
|
const webSearch = section.webSearch ?? root.webSearch;
|
|
92
94
|
const execCommandGuard = section.execCommandGuard ?? root.execCommandGuard;
|
|
93
|
-
|
|
95
|
+
const clock = section.clock ?? root.clock;
|
|
96
|
+
return { providers, routing, classifier, loadBalancing, health, contextRouting, webSearch, execCommandGuard, clock };
|
|
97
|
+
}
|
|
98
|
+
function normalizeClock(raw) {
|
|
99
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
|
102
|
+
const record = raw;
|
|
103
|
+
const enabled = record.enabled === true ||
|
|
104
|
+
(typeof record.enabled === 'string' && record.enabled.trim().toLowerCase() === 'true') ||
|
|
105
|
+
(typeof record.enabled === 'number' && record.enabled === 1);
|
|
106
|
+
if (!enabled) {
|
|
107
|
+
return undefined;
|
|
108
|
+
}
|
|
109
|
+
const out = { enabled: true };
|
|
110
|
+
if (typeof record.retentionMs === 'number' && Number.isFinite(record.retentionMs) && record.retentionMs >= 0) {
|
|
111
|
+
out.retentionMs = Math.floor(record.retentionMs);
|
|
112
|
+
}
|
|
113
|
+
if (typeof record.dueWindowMs === 'number' && Number.isFinite(record.dueWindowMs) && record.dueWindowMs >= 0) {
|
|
114
|
+
out.dueWindowMs = Math.floor(record.dueWindowMs);
|
|
115
|
+
}
|
|
116
|
+
if (typeof record.tickMs === 'number' && Number.isFinite(record.tickMs) && record.tickMs >= 0) {
|
|
117
|
+
out.tickMs = Math.floor(record.tickMs);
|
|
118
|
+
}
|
|
119
|
+
return out;
|
|
94
120
|
}
|
|
95
121
|
function buildProviderRuntimeEntries(providers) {
|
|
96
122
|
const runtimeEntries = {};
|
|
@@ -1130,9 +1156,32 @@ function normalizeLoadBalancing(input) {
|
|
|
1130
1156
|
weightsEntries[key] = value;
|
|
1131
1157
|
}
|
|
1132
1158
|
}
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1159
|
+
const healthWeightedRaw = asRecord(record.healthWeighted);
|
|
1160
|
+
const healthWeighted = Object.keys(healthWeightedRaw).length > 0
|
|
1161
|
+
? {
|
|
1162
|
+
...(typeof healthWeightedRaw.enabled === 'boolean' ? { enabled: healthWeightedRaw.enabled } : {}),
|
|
1163
|
+
...(typeof healthWeightedRaw.recoverToBestOnRetry === 'boolean'
|
|
1164
|
+
? { recoverToBestOnRetry: healthWeightedRaw.recoverToBestOnRetry }
|
|
1165
|
+
: {}),
|
|
1166
|
+
...(typeof healthWeightedRaw.baseWeight === 'number' && Number.isFinite(healthWeightedRaw.baseWeight)
|
|
1167
|
+
? { baseWeight: healthWeightedRaw.baseWeight }
|
|
1168
|
+
: {}),
|
|
1169
|
+
...(typeof healthWeightedRaw.minMultiplier === 'number' && Number.isFinite(healthWeightedRaw.minMultiplier)
|
|
1170
|
+
? { minMultiplier: healthWeightedRaw.minMultiplier }
|
|
1171
|
+
: {}),
|
|
1172
|
+
...(typeof healthWeightedRaw.beta === 'number' && Number.isFinite(healthWeightedRaw.beta)
|
|
1173
|
+
? { beta: healthWeightedRaw.beta }
|
|
1174
|
+
: {}),
|
|
1175
|
+
...(typeof healthWeightedRaw.halfLifeMs === 'number' && Number.isFinite(healthWeightedRaw.halfLifeMs)
|
|
1176
|
+
? { halfLifeMs: healthWeightedRaw.halfLifeMs }
|
|
1177
|
+
: {})
|
|
1178
|
+
}
|
|
1179
|
+
: undefined;
|
|
1180
|
+
return {
|
|
1181
|
+
strategy,
|
|
1182
|
+
...(Object.keys(weightsEntries).length ? { weights: weightsEntries } : {}),
|
|
1183
|
+
...(healthWeighted ? { healthWeighted } : {})
|
|
1184
|
+
};
|
|
1136
1185
|
}
|
|
1137
1186
|
function coerceRatio(value) {
|
|
1138
1187
|
if (typeof value === 'number' && Number.isFinite(value)) {
|