@jsonstudio/llms 0.6.3409 → 0.6.3539

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.
Files changed (82) hide show
  1. package/dist/conversion/codecs/anthropic-openai-codec.d.ts +12 -3
  2. package/dist/conversion/codecs/anthropic-openai-codec.js +32 -92
  3. package/dist/conversion/codecs/gemini-openai-codec.d.ts +6 -5
  4. package/dist/conversion/codecs/gemini-openai-codec.js +48 -685
  5. package/dist/conversion/codecs/openai-openai-codec.d.ts +1 -1
  6. package/dist/conversion/codecs/openai-openai-codec.js +34 -100
  7. package/dist/conversion/codecs/responses-openai-codec.d.ts +1 -1
  8. package/dist/conversion/codecs/responses-openai-codec.js +47 -159
  9. package/dist/conversion/compat/actions/anthropic-claude-code-system-prompt.d.ts +2 -6
  10. package/dist/conversion/compat/actions/anthropic-claude-code-system-prompt.js +29 -245
  11. package/dist/conversion/compat/actions/anthropic-claude-code-user-id.d.ts +3 -0
  12. package/dist/conversion/compat/actions/anthropic-claude-code-user-id.js +30 -0
  13. package/dist/conversion/compat/actions/antigravity-thought-signature-prepare.js +21 -232
  14. package/dist/conversion/compat/actions/deepseek-web-request.js +41 -276
  15. package/dist/conversion/compat/actions/deepseek-web-response.js +64 -859
  16. package/dist/conversion/compat/actions/gemini-cli-request.d.ts +1 -1
  17. package/dist/conversion/compat/actions/gemini-cli-request.js +20 -613
  18. package/dist/conversion/compat/actions/gemini-web-search.d.ts +1 -15
  19. package/dist/conversion/compat/actions/gemini-web-search.js +22 -69
  20. package/dist/conversion/compat/actions/glm-tool-extraction.d.ts +3 -2
  21. package/dist/conversion/compat/actions/glm-tool-extraction.js +28 -257
  22. package/dist/conversion/compat/actions/iflow-tool-text-fallback.d.ts +0 -8
  23. package/dist/conversion/compat/actions/iflow-tool-text-fallback.js +24 -206
  24. package/dist/conversion/compat/actions/qwen-transform.d.ts +3 -2
  25. package/dist/conversion/compat/actions/qwen-transform.js +30 -271
  26. package/dist/conversion/compat/actions/tool-text-request-guidance.js +3 -173
  27. package/dist/conversion/compat/actions/universal-shape-filter.d.ts +6 -23
  28. package/dist/conversion/compat/actions/universal-shape-filter.js +4 -383
  29. package/dist/conversion/hub/pipeline/compat/native-adapter-context.js +1 -0
  30. package/dist/conversion/pipeline/codecs/v2/anthropic-openai-pipeline.d.ts +1 -2
  31. package/dist/conversion/pipeline/codecs/v2/anthropic-openai-pipeline.js +50 -104
  32. package/dist/conversion/pipeline/codecs/v2/openai-openai-pipeline.js +12 -10
  33. package/dist/conversion/pipeline/codecs/v2/responses-openai-pipeline.d.ts +0 -2
  34. package/dist/conversion/pipeline/codecs/v2/responses-openai-pipeline.js +46 -67
  35. package/dist/conversion/pipeline/codecs/v2/shared/openai-chat-helpers.js +15 -40
  36. package/dist/conversion/responses/responses-openai-bridge/response-payload.js +47 -348
  37. package/dist/conversion/responses/responses-openai-bridge.js +129 -611
  38. package/dist/conversion/shared/chat-output-normalizer.js +6 -0
  39. package/dist/conversion/shared/chat-request-filters.js +1 -1
  40. package/dist/conversion/shared/output-content-normalizer.js +10 -0
  41. package/dist/conversion/shared/responses-conversation-store.js +22 -135
  42. package/dist/conversion/shared/responses-output-builder.d.ts +0 -2
  43. package/dist/conversion/shared/responses-output-builder.js +28 -318
  44. package/dist/conversion/shared/responses-response-utils.js +35 -86
  45. package/dist/conversion/shared/streaming-text-extractor.d.ts +1 -2
  46. package/dist/conversion/shared/streaming-text-extractor.js +13 -14
  47. package/dist/native/router_hotpath_napi.node +0 -0
  48. package/dist/router/virtual-router/bootstrap/routing-config.js +11 -3
  49. package/dist/router/virtual-router/engine-legacy.d.ts +3 -3
  50. package/dist/router/virtual-router/engine-legacy.js +15 -7
  51. package/dist/router/virtual-router/engine-selection/native-compat-action-semantics.d.ts +16 -0
  52. package/dist/router/virtual-router/engine-selection/native-compat-action-semantics.js +434 -46
  53. package/dist/router/virtual-router/engine-selection/native-hub-bridge-action-semantics.d.ts +83 -0
  54. package/dist/router/virtual-router/engine-selection/native-hub-bridge-action-semantics.js +295 -0
  55. package/dist/router/virtual-router/engine-selection/native-hub-pipeline-req-outbound-semantics.d.ts +1 -0
  56. package/dist/router/virtual-router/engine-selection/native-hub-pipeline-resp-semantics.d.ts +7 -0
  57. package/dist/router/virtual-router/engine-selection/native-hub-pipeline-resp-semantics.js +8 -1
  58. package/dist/router/virtual-router/engine-selection/native-router-hotpath-loader.js +383 -298
  59. package/dist/router/virtual-router/engine-selection/native-shared-conversion-semantics.d.ts +20 -0
  60. package/dist/router/virtual-router/engine-selection/native-shared-conversion-semantics.js +201 -0
  61. package/dist/router/virtual-router/engine-selection/native-virtual-router-routing-instructions-semantics.d.ts +1 -0
  62. package/dist/router/virtual-router/engine-selection/native-virtual-router-routing-instructions-semantics.js +37 -0
  63. package/dist/router/virtual-router/engine.js +0 -38
  64. package/dist/router/virtual-router/features.js +44 -3
  65. package/dist/router/virtual-router/routing-instructions/parse.d.ts +0 -12
  66. package/dist/router/virtual-router/routing-instructions/parse.js +9 -389
  67. package/dist/router/virtual-router/stop-message-state-sync.d.ts +3 -6
  68. package/dist/router/virtual-router/stop-message-state-sync.js +50 -21
  69. package/dist/sse/sse-to-json/anthropic-sse-to-json-converter.d.ts +1 -0
  70. package/dist/sse/sse-to-json/anthropic-sse-to-json-converter.js +26 -0
  71. package/dist/sse/sse-to-json/builders/anthropic-response-builder.js +12 -2
  72. package/package.json +1 -1
  73. package/dist/router/virtual-router/engine-legacy/route-finalize.d.ts +0 -9
  74. package/dist/router/virtual-router/engine-legacy/route-finalize.js +0 -84
  75. package/dist/router/virtual-router/engine-legacy/route-selection.d.ts +0 -17
  76. package/dist/router/virtual-router/engine-legacy/route-selection.js +0 -205
  77. package/dist/router/virtual-router/engine-legacy/route-state-allowlist.d.ts +0 -3
  78. package/dist/router/virtual-router/engine-legacy/route-state-allowlist.js +0 -36
  79. package/dist/router/virtual-router/engine-legacy/route-state.d.ts +0 -12
  80. package/dist/router/virtual-router/engine-legacy/route-state.js +0 -386
  81. package/dist/router/virtual-router/engine-legacy/routing.d.ts +0 -8
  82. package/dist/router/virtual-router/engine-legacy/routing.js +0 -8
@@ -1,281 +1,40 @@
1
- const MODEL_MAP = {
2
- 'gpt-3.5-turbo': 'qwen-turbo',
3
- 'gpt-4': 'qwen3-coder-plus',
4
- 'gpt-4-turbo': 'qwen3-coder-plus',
5
- 'gpt-4o': 'qwen3-coder-plus'
6
- };
7
- const FINISH_REASON_MAP = {
8
- stop: 'stop',
9
- length: 'length',
10
- tool_calls: 'tool_calls',
11
- content_filter: 'content_filter'
12
- };
13
- const isRecord = (value) => typeof value === 'object' && value !== null;
14
- const readReasoningEffort = (value) => {
15
- if (typeof value === 'string') {
16
- return value;
17
- }
18
- if (isRecord(value) && typeof value.effort === 'string') {
19
- return value.effort;
20
- }
21
- return undefined;
22
- };
23
- export function applyQwenRequestTransform(payload) {
24
- const cloned = structuredClone(payload);
25
- const transformed = convertToQwenRequest(cloned);
26
- return transformed;
27
- }
28
- export function applyQwenResponseTransform(payload) {
29
- const cloned = structuredClone(payload);
30
- const transformed = transformQwenResponseToOpenAI(cloned);
31
- return transformed;
32
- }
33
- function convertToQwenRequest(request) {
34
- const qwenRequest = {};
35
- const mappedModel = mapModelName(typeof request.model === 'string' ? request.model : undefined);
36
- if (mappedModel) {
37
- qwenRequest.model = mappedModel;
38
- }
39
- if (Array.isArray(request.messages)) {
40
- qwenRequest.messages = structuredClone(request.messages);
41
- const normalizedMessages = request.messages
42
- .map(message => normalizeMessage(message))
43
- .filter((entry) => entry !== null);
44
- if (normalizedMessages.length > 0) {
45
- qwenRequest.input = normalizedMessages;
46
- }
47
- }
48
- const parameters = extractParameters(request);
49
- if (Object.keys(parameters).length > 0) {
50
- qwenRequest.parameters = parameters;
51
- }
52
- if (typeof request.stream === 'boolean') {
53
- qwenRequest.stream = request.stream;
54
- }
55
- if (isRecord(request.response_format)) {
56
- qwenRequest.response_format = structuredClone(request.response_format);
57
- }
58
- if (typeof request.user === 'string') {
59
- qwenRequest.user = request.user;
60
- }
61
- if (Array.isArray(request.tools)) {
62
- qwenRequest.tools = sanitizeTools(request.tools);
63
- }
64
- if (isRecord(request.metadata)) {
65
- qwenRequest.metadata = structuredClone(request.metadata);
66
- }
67
- return qwenRequest;
68
- }
69
- function sanitizeTools(tools) {
70
- return tools.map(tool => {
71
- if (!isRecord(tool)) {
72
- return tool;
73
- }
74
- const normalized = {};
75
- if (typeof tool.type === 'string') {
76
- normalized.type = tool.type;
77
- }
78
- if (isRecord(tool.function)) {
79
- normalized.function = structuredClone(tool.function);
80
- }
81
- return Object.keys(normalized).length > 0 ? normalized : tool;
82
- });
83
- }
84
- function normalizeMessage(message) {
85
- if (!isRecord(message)) {
86
- return null;
87
- }
88
- const role = typeof message.role === 'string' ? message.role : 'user';
89
- const content = normalizeMessageContent(message.content);
90
- return { role, content };
91
- }
92
- function normalizeMessageContent(content) {
93
- if (content === undefined || content === null) {
94
- return [{ text: '' }];
95
- }
96
- if (typeof content === 'string') {
97
- return [{ text: content }];
98
- }
99
- if (Array.isArray(content)) {
100
- return content.map(chunk => normalizeContentChunk(chunk));
101
- }
102
- if (isRecord(content) && typeof content.text === 'string') {
103
- return [{ text: content.text }];
104
- }
105
- return [{ text: JSON.stringify(content) }];
106
- }
107
- function normalizeContentChunk(chunk) {
108
- if (typeof chunk === 'string') {
109
- return { text: chunk };
110
- }
111
- if (isRecord(chunk)) {
112
- if (typeof chunk.text === 'string') {
113
- return { text: chunk.text };
114
- }
115
- return structuredClone(chunk);
116
- }
117
- return { text: String(chunk) };
118
- }
119
- function extractParameters(request) {
120
- const parameters = {};
121
- const numericFields = [
122
- { key: 'temperature', target: 'temperature' },
123
- { key: 'top_p', target: 'top_p' },
124
- { key: 'frequency_penalty', target: 'frequency_penalty' },
125
- { key: 'presence_penalty', target: 'presence_penalty' },
126
- { key: 'max_tokens', target: 'max_output_tokens' }
127
- ];
128
- for (const field of numericFields) {
129
- const value = request[field.key];
130
- if (typeof value === 'number') {
131
- parameters[field.target] = value;
132
- }
133
- }
134
- if (request.stop !== undefined) {
135
- const stops = Array.isArray(request.stop) ? request.stop : [request.stop];
136
- const sequences = stops.filter(item => typeof item === 'string');
137
- if (sequences.length > 0) {
138
- parameters.stop_sequences = sequences;
139
- }
140
- }
141
- if (typeof request.debug === 'boolean') {
142
- parameters.debug = request.debug;
143
- }
144
- const reasoningEffort = readReasoningEffort(request.reasoning)?.toLowerCase();
145
- if (reasoningEffort !== 'low') {
146
- parameters.reasoning = true;
147
- }
148
- return parameters;
149
- }
150
- function transformQwenResponseToOpenAI(response) {
151
- const data = isRecord(response.data) ? response.data : response;
152
- const usage = isRecord(data.usage)
153
- ? structuredClone(data.usage)
154
- : {
155
- prompt_tokens: 0,
156
- completion_tokens: 0,
157
- total_tokens: 0
158
- };
159
- const transformed = {
160
- id: typeof data.id === 'string' ? data.id : `chatcmpl-${Date.now()}`,
161
- object: 'chat.completion',
162
- created: typeof data.created === 'number' ? data.created : Math.floor(Date.now() / 1000),
163
- model: typeof data.model === 'string' ? data.model : 'qwen-turbo',
164
- choices: transformChoices(data.choices),
165
- usage,
166
- _transformed: true,
167
- _originalFormat: 'qwen',
168
- _targetFormat: 'openai'
1
+ import { buildNativeReqOutboundCompatAdapterContext } from '../../hub/pipeline/compat/native-adapter-context.js';
2
+ import { runReqOutboundStage3CompatWithNative, runRespInboundStage3CompatWithNative } from '../../../router/virtual-router/engine-selection/native-hub-pipeline-req-outbound-semantics.js';
3
+ const PROFILE = 'chat:qwen';
4
+ const DEFAULT_PROVIDER_PROTOCOL = 'openai-chat';
5
+ const DEFAULT_ENTRY_ENDPOINT = '/v1/chat/completions';
6
+ function buildQwenCompatContext(adapterContext) {
7
+ const nativeContext = buildNativeReqOutboundCompatAdapterContext(adapterContext);
8
+ return {
9
+ ...nativeContext,
10
+ compatibilityProfile: PROFILE,
11
+ providerProtocol: nativeContext.providerProtocol ?? adapterContext?.providerProtocol ?? DEFAULT_PROVIDER_PROTOCOL,
12
+ entryEndpoint: nativeContext.entryEndpoint ?? adapterContext?.entryEndpoint ?? DEFAULT_ENTRY_ENDPOINT
169
13
  };
170
- const firstMessage = (() => {
171
- const choices = Array.isArray(transformed.choices) ? transformed.choices : [];
172
- const primary = choices[0] && isRecord(choices[0]) ? choices[0] : undefined;
173
- const message = primary && isRecord(primary.message) ? primary.message : undefined;
174
- return message;
175
- })();
176
- if (firstMessage && typeof firstMessage.reasoning_content === 'string' && firstMessage.reasoning_content.trim()) {
177
- transformed.__responses_reasoning = {
178
- content: [{ type: 'reasoning_text', text: String(firstMessage.reasoning_content).trim() }]
179
- };
180
- }
181
- return transformed;
182
14
  }
183
- function transformChoices(rawChoices) {
184
- if (!Array.isArray(rawChoices)) {
185
- return [];
186
- }
187
- return rawChoices.map((choice, index) => {
188
- const choiceObj = isRecord(choice) ? choice : {};
189
- const messageObj = isRecord(choiceObj.message) ? choiceObj.message : {};
190
- const contentDetails = extractContentAndReasoning(messageObj.content);
191
- const reasoningText = mergeReasoningText(contentDetails?.reasoningText, readString(messageObj.reasoning_content) ?? readString(messageObj.reasoning));
192
- return {
193
- index: typeof choiceObj.index === 'number' ? choiceObj.index : index,
194
- message: {
195
- role: typeof messageObj.role === 'string' ? messageObj.role : 'assistant',
196
- content: contentDetails?.contentText ?? (typeof messageObj.content === 'string' ? messageObj.content : ''),
197
- tool_calls: transformToolCalls(messageObj.tool_calls),
198
- ...(reasoningText ? { reasoning_content: reasoningText } : {})
199
- },
200
- finish_reason: transformFinishReason(typeof choiceObj.finish_reason === 'string' ? choiceObj.finish_reason : undefined)
201
- };
202
- });
203
- }
204
- function readString(value) {
205
- if (typeof value !== 'string') {
206
- return undefined;
207
- }
208
- const trimmed = value.trim();
209
- return trimmed.length ? trimmed : undefined;
210
- }
211
- function mergeReasoningText(primary, secondary) {
212
- const parts = [primary, secondary].filter((item) => typeof item === 'string' && item.trim().length > 0);
213
- if (parts.length === 0) {
214
- return undefined;
215
- }
216
- return parts.join('\n');
217
- }
218
- function extractContentAndReasoning(content) {
219
- if (!Array.isArray(content)) {
220
- return null;
221
- }
222
- const contentParts = [];
223
- const reasoningParts = [];
224
- for (const chunk of content) {
225
- if (typeof chunk === 'string') {
226
- contentParts.push(chunk);
227
- continue;
228
- }
229
- if (!isRecord(chunk)) {
230
- continue;
231
- }
232
- const text = readString(chunk.text);
233
- const type = typeof chunk.type === 'string' ? chunk.type.toLowerCase() : '';
234
- const isThinking = Boolean(chunk.thought) || type === 'thinking' || type === 'reasoning';
235
- if (text) {
236
- if (isThinking) {
237
- reasoningParts.push(text);
238
- }
239
- else {
240
- contentParts.push(text);
241
- }
242
- }
243
- }
15
+ function buildQwenRequestCompatInput(payload, adapterContext) {
244
16
  return {
245
- contentText: contentParts.join('\n'),
246
- reasoningText: reasoningParts.length ? reasoningParts.join('\n') : undefined
17
+ payload,
18
+ adapterContext: buildQwenCompatContext(adapterContext),
19
+ explicitProfile: PROFILE
247
20
  };
248
21
  }
249
- function transformToolCalls(toolCalls) {
250
- if (!Array.isArray(toolCalls)) {
251
- return [];
252
- }
253
- return toolCalls.map((toolCall, index) => {
254
- const toolCallObj = isRecord(toolCall) ? toolCall : {};
255
- const fnObj = isRecord(toolCallObj.function) ? toolCallObj.function : {};
256
- const id = typeof toolCallObj.id === 'string'
257
- ? toolCallObj.id
258
- : `call_${Date.now()}_${index}`;
259
- const name = typeof fnObj.name === 'string' ? fnObj.name : '';
260
- const args = typeof fnObj.arguments === 'string'
261
- ? fnObj.arguments
262
- : JSON.stringify(fnObj.arguments ?? {});
263
- return {
264
- id,
265
- type: 'function',
266
- function: { name, arguments: args }
267
- };
268
- });
22
+ function buildQwenResponseCompatInput(payload, adapterContext) {
23
+ return {
24
+ payload,
25
+ adapterContext: buildQwenCompatContext(adapterContext),
26
+ explicitProfile: PROFILE
27
+ };
269
28
  }
270
- function transformFinishReason(reason) {
271
- if (!reason) {
272
- return 'stop';
29
+ export function applyQwenRequestTransform(payload, adapterContext) {
30
+ if (!payload || typeof payload !== 'object') {
31
+ return payload;
273
32
  }
274
- return FINISH_REASON_MAP[reason] ?? reason;
33
+ return runReqOutboundStage3CompatWithNative(buildQwenRequestCompatInput(payload, adapterContext)).payload;
275
34
  }
276
- function mapModelName(model) {
277
- if (!model) {
278
- return undefined;
35
+ export function applyQwenResponseTransform(payload, adapterContext) {
36
+ if (!payload || typeof payload !== 'object') {
37
+ return payload;
279
38
  }
280
- return MODEL_MAP[model] ?? model;
39
+ return runRespInboundStage3CompatWithNative(buildQwenResponseCompatInput(payload, adapterContext)).payload;
281
40
  }
@@ -1,177 +1,7 @@
1
- const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
2
- function readString(value) {
3
- return typeof value === 'string' ? value.trim() : '';
4
- }
5
- function collectToolNames(toolsRaw) {
6
- const out = [];
7
- if (!Array.isArray(toolsRaw)) {
8
- return out;
9
- }
10
- for (const item of toolsRaw) {
11
- if (!isRecord(item))
12
- continue;
13
- const fn = isRecord(item.function) ? item.function : item;
14
- const name = readString(fn.name);
15
- if (!name)
16
- continue;
17
- if (!out.includes(name)) {
18
- out.push(name);
19
- }
20
- }
21
- return out;
22
- }
23
- function isToolChoiceRequired(root) {
24
- const toolChoice = root.tool_choice;
25
- if (typeof toolChoice === 'string') {
26
- const normalized = toolChoice.trim().toLowerCase();
27
- if (normalized === 'required')
28
- return true;
29
- if (normalized === 'auto' || normalized === 'none')
30
- return false;
31
- }
32
- if (isRecord(toolChoice)) {
33
- return String(toolChoice.type || '').trim().toLowerCase() === 'function';
34
- }
35
- return false;
36
- }
37
- function buildDefaultInstruction(root, config) {
38
- const toolNames = collectToolNames(root.tools);
39
- const includeToolNames = config?.includeToolNames !== false;
40
- const required = isToolChoiceRequired(root);
41
- const marker = readString(config?.marker) || 'Tool-call output contract (STRICT)';
42
- const lines = [
43
- `${marker}:`,
44
- '1) If calling tools, output exactly one JSON object: {"tool_calls":[{"name":"tool_name","input":{...}}]}',
45
- '2) Use only keys: `tool_calls` + each call `name` and `input`.',
46
- '3) Do not output markdown fences, prose, or tool transcripts around JSON.',
47
- '4) Do NOT output pseudo tool results in text (forbidden examples: {"exec_command":...}, <function_results>...</function_results>).'
48
- ];
49
- if (includeToolNames && toolNames.length) {
50
- lines.push(`5) Allowed tool names this turn: ${toolNames.join(', ')}`);
51
- }
52
- else {
53
- lines.push('5) Tool name must match provided schema exactly.');
54
- }
55
- lines.push(required
56
- ? '6) tool_choice is required for this turn: return at least one tool call.'
57
- : '6) If no tool is needed, plain text is allowed.');
58
- return lines.join('\n');
59
- }
60
- function ensureSystemMessage(messages) {
61
- const first = messages[0];
62
- if (isRecord(first) && readString(first.role).toLowerCase() === 'system') {
63
- return first;
64
- }
65
- const created = { role: 'system', content: '' };
66
- messages.unshift(created);
67
- return created;
68
- }
69
- function contentToText(content) {
70
- if (typeof content === 'string') {
71
- return content;
72
- }
73
- if (Array.isArray(content)) {
74
- const parts = [];
75
- for (const part of content) {
76
- if (typeof part === 'string') {
77
- parts.push(part);
78
- continue;
79
- }
80
- if (!isRecord(part))
81
- continue;
82
- const text = readString(part.text) || readString(part.content);
83
- if (text)
84
- parts.push(text);
85
- }
86
- return parts.join('\n').trim();
87
- }
88
- if (isRecord(content)) {
89
- const text = readString(content.text) || readString(content.content);
90
- if (text) {
91
- return text;
92
- }
93
- if (Array.isArray(content.content)) {
94
- return contentToText(content.content);
95
- }
96
- }
97
- return '';
98
- }
99
- function contentHasMarker(content, marker) {
100
- if (!marker) {
101
- return false;
102
- }
103
- const text = contentToText(content);
104
- return text.includes(marker);
105
- }
106
- function appendInstructionToContent(content, instruction) {
107
- if (typeof content === 'string') {
108
- return content.trim() ? `${content}\n\n${instruction}` : instruction;
109
- }
110
- if (Array.isArray(content)) {
111
- return [
112
- ...content,
113
- {
114
- type: 'text',
115
- text: content.length ? `\n\n${instruction}` : instruction
116
- }
117
- ];
118
- }
119
- if (isRecord(content)) {
120
- if (typeof content.text === 'string') {
121
- const previous = content.text;
122
- return {
123
- ...content,
124
- text: previous.trim() ? `${previous}\n\n${instruction}` : instruction
125
- };
126
- }
127
- if (typeof content.content === 'string') {
128
- const previous = content.content;
129
- return {
130
- ...content,
131
- content: previous.trim() ? `${previous}\n\n${instruction}` : instruction
132
- };
133
- }
134
- if (Array.isArray(content.content)) {
135
- return {
136
- ...content,
137
- content: appendInstructionToContent(content.content, instruction)
138
- };
139
- }
140
- return [content, { type: 'text', text: instruction }];
141
- }
142
- return instruction;
143
- }
1
+ import { applyToolTextRequestGuidanceWithNative } from '../../../router/virtual-router/engine-selection/native-compat-action-semantics.js';
144
2
  export function applyToolTextRequestGuidance(payload, config) {
145
- const enabled = config?.enabled !== false;
146
- if (!enabled) {
3
+ if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
147
4
  return payload;
148
5
  }
149
- const root = structuredClone(payload);
150
- const requireTools = config?.requireTools !== false;
151
- if (requireTools) {
152
- const tools = Array.isArray(root.tools) ? root.tools : [];
153
- if (!tools.length) {
154
- return root;
155
- }
156
- }
157
- if (!Array.isArray(root.messages)) {
158
- return root;
159
- }
160
- const messages = root.messages.filter((item) => isRecord(item));
161
- if (!messages.length) {
162
- return root;
163
- }
164
- const instruction = readString(config?.instruction) || buildDefaultInstruction(root, config);
165
- if (!instruction) {
166
- return root;
167
- }
168
- const marker = readString(config?.marker) || 'Tool-call output contract (STRICT)';
169
- const system = ensureSystemMessage(messages);
170
- if (contentHasMarker(system.content, marker)) {
171
- root.messages = messages;
172
- return root;
173
- }
174
- system.content = appendInstructionToContent(system.content, instruction);
175
- root.messages = messages;
176
- return root;
6
+ return applyToolTextRequestGuidanceWithNative(payload, (config ?? {}));
177
7
  }
@@ -1,11 +1,11 @@
1
- import type { AdapterContext } from '../../hub/types/chat-envelope.js';
2
- import type { JsonObject } from '../../hub/types/json.js';
1
+ import type { AdapterContext } from "../../hub/types/chat-envelope.js";
2
+ import type { JsonObject } from "../../hub/types/json.js";
3
3
  type RequestMessagesRule = {
4
4
  when?: {
5
- role?: 'system' | 'user' | 'assistant' | 'tool';
5
+ role?: "system" | "user" | "assistant" | "tool";
6
6
  hasToolCalls?: boolean;
7
7
  };
8
- action: 'drop' | 'keep' | 'set';
8
+ action: "drop" | "keep" | "set";
9
9
  set?: Record<string, unknown>;
10
10
  };
11
11
  export interface FilterConfig {
@@ -22,7 +22,7 @@ export interface FilterConfig {
22
22
  forceToolChoiceAuto?: boolean;
23
23
  };
24
24
  assistantToolCalls?: {
25
- functionArgumentsType?: 'object' | 'string';
25
+ functionArgumentsType?: "object" | "string";
26
26
  };
27
27
  messagesRules?: RequestMessagesRule[];
28
28
  };
@@ -37,7 +37,7 @@ export interface FilterConfig {
37
37
  tool_calls?: {
38
38
  function?: {
39
39
  nameRequired?: boolean;
40
- argumentsType?: 'object' | 'string';
40
+ argumentsType?: "object" | "string";
41
41
  };
42
42
  };
43
43
  };
@@ -53,22 +53,5 @@ export declare class UniversalShapeFilter {
53
53
  constructor(config: FilterConfig);
54
54
  applyRequestFilter(payload: JsonObject): JsonObject;
55
55
  applyResponseFilter(payload: JsonObject, ctx?: AdapterContext): JsonObject;
56
- private shallowPick;
57
- private toObjectArgs;
58
- private toStringArgs;
59
- private normalizeToolContent;
60
- private normalizeRequestMessages;
61
- private normalizeSingleMessage;
62
- private normalizeAssistantToolCalls;
63
- private applyMessageRules;
64
- private pairToolResults;
65
- private normalizeTools;
66
- private normalizeSingleTool;
67
- private normalizeToolParameters;
68
- private enforceShellSchema;
69
- private cleanupToolChoice;
70
- private normalizeResponseChoice;
71
- private normalizeResponseMessage;
72
- private normalizeResponseToolCalls;
73
56
  }
74
57
  export {};