@jsonstudio/llms 0.6.34 → 0.6.74

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 (44) hide show
  1. package/dist/conversion/codecs/gemini-openai-codec.js +1 -2
  2. package/dist/conversion/codecs/responses-openai-codec.js +16 -1
  3. package/dist/conversion/compat/profiles/chat-glm.json +17 -0
  4. package/dist/conversion/compat/profiles/chat-iflow.json +36 -0
  5. package/dist/conversion/compat/profiles/chat-lmstudio.json +37 -0
  6. package/dist/conversion/compat/profiles/chat-qwen.json +18 -0
  7. package/dist/conversion/compat/profiles/responses-c4m.json +45 -0
  8. package/dist/conversion/config/compat-profiles.json +38 -0
  9. package/dist/conversion/config/sample-config.json +314 -0
  10. package/dist/conversion/config/version-switch.json +150 -0
  11. package/dist/conversion/hub/pipeline/compat/compat-engine.d.ts +4 -0
  12. package/dist/conversion/hub/pipeline/compat/compat-engine.js +667 -0
  13. package/dist/conversion/hub/pipeline/compat/compat-profile-store.d.ts +2 -0
  14. package/dist/conversion/hub/pipeline/compat/compat-profile-store.js +76 -0
  15. package/dist/conversion/hub/pipeline/compat/compat-types.d.ts +62 -0
  16. package/dist/conversion/hub/pipeline/compat/compat-types.js +1 -0
  17. package/dist/conversion/hub/pipeline/hub-pipeline.d.ts +1 -0
  18. package/dist/conversion/hub/pipeline/hub-pipeline.js +76 -28
  19. package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage3_context_capture/index.js +0 -13
  20. package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage3_compat/index.d.ts +14 -0
  21. package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage3_compat/index.js +23 -0
  22. package/dist/conversion/hub/response/provider-response.js +18 -0
  23. package/dist/conversion/hub/response/response-mappers.d.ts +1 -1
  24. package/dist/conversion/hub/response/response-mappers.js +2 -12
  25. package/dist/conversion/responses/responses-openai-bridge.d.ts +1 -0
  26. package/dist/conversion/responses/responses-openai-bridge.js +71 -0
  27. package/dist/conversion/shared/responses-output-builder.js +22 -43
  28. package/dist/conversion/shared/responses-response-utils.js +1 -47
  29. package/dist/conversion/shared/text-markup-normalizer.js +2 -2
  30. package/dist/conversion/shared/tool-canonicalizer.js +16 -118
  31. package/dist/conversion/shared/tool-filter-pipeline.js +63 -21
  32. package/dist/conversion/shared/tool-mapping.js +52 -32
  33. package/dist/filters/config/openai-openai.fieldmap.json +18 -0
  34. package/dist/filters/special/request-tools-normalize.js +20 -1
  35. package/dist/index.d.ts +0 -1
  36. package/dist/index.js +0 -1
  37. package/dist/router/virtual-router/bootstrap.js +18 -33
  38. package/dist/router/virtual-router/classifier.js +51 -77
  39. package/dist/router/virtual-router/features.js +338 -111
  40. package/dist/router/virtual-router/types.d.ts +2 -4
  41. package/dist/router/virtual-router/types.js +2 -2
  42. package/dist/sse/sse-to-json/builders/response-builder.js +1 -0
  43. package/dist/tools/tool-registry.js +4 -3
  44. package/package.json +3 -3
@@ -262,7 +262,6 @@ export function buildOpenAIChatFromGeminiResponse(payload) {
262
262
  catch {
263
263
  // best-effort policy execution
264
264
  }
265
- const normalizedFinishReason = toolCalls.length ? 'tool_calls' : finish_reason;
266
265
  const chatResp = {
267
266
  id: payload?.id || `chatcmpl_${Date.now()}`,
268
267
  object: 'chat.completion',
@@ -270,7 +269,7 @@ export function buildOpenAIChatFromGeminiResponse(payload) {
270
269
  choices: [
271
270
  {
272
271
  index: 0,
273
- finish_reason: normalizedFinishReason,
272
+ finish_reason,
274
273
  message: chatMsg
275
274
  }
276
275
  ]
@@ -1,5 +1,6 @@
1
1
  import { buildResponsesPayloadFromChat, runStandardChatRequestFilters } from '../index.js';
2
- import { captureResponsesContext, buildChatRequestFromResponses } from '../responses/responses-openai-bridge.js';
2
+ import { captureResponsesContext, buildChatRequestFromResponses, buildResponsesRequestFromChat } from '../responses/responses-openai-bridge.js';
3
+ import { captureResponsesRequestContext } from '../shared/responses-conversation-store.js';
3
4
  import { FilterEngine, ResponseToolTextCanonicalizeFilter, ResponseToolArgumentsStringifyFilter, ResponseFinishInvariantsFilter } from '../../filters/index.js';
4
5
  // Ported from root package (no behavior change). Types relaxed.
5
6
  export class ResponsesOpenAIConversionCodec {
@@ -83,6 +84,20 @@ export class ResponsesOpenAIConversionCodec {
83
84
  endpoint: context.endpoint ?? dto.metadata?.endpoint
84
85
  };
85
86
  const filtered = await runStandardChatRequestFilters(chatRequest, profile, ctxForFilters);
87
+ try {
88
+ const rebuilt = buildResponsesRequestFromChat(filtered, ctx);
89
+ const payloadForStore = rebuilt?.request;
90
+ if (payloadForStore && typeof payloadForStore === 'object') {
91
+ captureResponsesRequestContext({
92
+ requestId: dto.route.requestId,
93
+ payload: payloadForStore,
94
+ context: ctx
95
+ });
96
+ }
97
+ }
98
+ catch {
99
+ // best-effort capture
100
+ }
86
101
  if (filtered && typeof filtered === 'object') {
87
102
  const maybe = filtered;
88
103
  if (maybe.max_tokens === undefined && typeof maybe.max_output_tokens === 'number') {
@@ -0,0 +1,17 @@
1
+ {
2
+ "id": "chat:glm",
3
+ "protocol": "openai-chat",
4
+ "direction": "request",
5
+ "mappings": [
6
+ {
7
+ "action": "rename",
8
+ "from": "response_format",
9
+ "to": "metadata.generation.response_format"
10
+ },
11
+ {
12
+ "action": "remove",
13
+ "path": "metadata.clientModelId"
14
+ }
15
+ ],
16
+ "filters": []
17
+ }
@@ -0,0 +1,36 @@
1
+ {
2
+ "id": "chat:iflow",
3
+ "protocol": "openai-chat",
4
+ "request": {
5
+ "mappings": [
6
+ {
7
+ "action": "remove",
8
+ "path": "metadata.toolCallIdStyle"
9
+ },
10
+ {
11
+ "action": "remove",
12
+ "path": "metadata.clientModelId"
13
+ },
14
+ {
15
+ "action": "remove",
16
+ "path": "metadata.providerHint"
17
+ }
18
+ ]
19
+ },
20
+ "response": {
21
+ "mappings": [
22
+ {
23
+ "action": "rename",
24
+ "from": "created_at",
25
+ "to": "created"
26
+ },
27
+ {
28
+ "action": "convert_responses_output_to_choices"
29
+ },
30
+ {
31
+ "action": "stringify",
32
+ "path": "choices[*].message.tool_calls[*].function.arguments"
33
+ }
34
+ ]
35
+ }
36
+ }
@@ -0,0 +1,37 @@
1
+ {
2
+ "id": "chat:lmstudio",
3
+ "protocol": "openai-chat",
4
+ "request": {
5
+ "mappings": [
6
+ {
7
+ "action": "normalize_tool_choice",
8
+ "path": "tool_choice",
9
+ "objectReplacement": "required"
10
+ }
11
+ ]
12
+ },
13
+ "response": {
14
+ "mappings": [
15
+ {
16
+ "action": "set_default",
17
+ "path": "object",
18
+ "value": "chat.completion"
19
+ },
20
+ {
21
+ "action": "set_default",
22
+ "path": "id",
23
+ "valueSource": "chat_completion_id"
24
+ },
25
+ {
26
+ "action": "set_default",
27
+ "path": "created",
28
+ "valueSource": "timestamp_seconds"
29
+ },
30
+ {
31
+ "action": "set_default",
32
+ "path": "model",
33
+ "value": "unknown"
34
+ }
35
+ ]
36
+ }
37
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "id": "chat:qwen",
3
+ "protocol": "openai-chat",
4
+ "request": {
5
+ "mappings": [
6
+ {
7
+ "action": "parse_json",
8
+ "path": "messages[*].tool_calls[*].function.arguments",
9
+ "fallback": {}
10
+ },
11
+ {
12
+ "action": "stringify",
13
+ "path": "messages[*].tool_calls[*].function.arguments",
14
+ "fallback": {}
15
+ }
16
+ ]
17
+ }
18
+ }
@@ -0,0 +1,45 @@
1
+ {
2
+ "id": "responses:c4m",
3
+ "protocol": "openai-responses",
4
+ "request": {
5
+ "mappings": [
6
+ {
7
+ "action": "remove",
8
+ "path": "max_tokens"
9
+ },
10
+ {
11
+ "action": "remove",
12
+ "path": "maxTokens"
13
+ },
14
+ {
15
+ "action": "remove",
16
+ "path": "max_output_tokens"
17
+ },
18
+ {
19
+ "action": "remove",
20
+ "path": "maxOutputTokens"
21
+ },
22
+ {
23
+ "action": "inject_instruction",
24
+ "sourcePath": "instructions",
25
+ "targetPath": "input",
26
+ "role": "system",
27
+ "contentType": "input_text",
28
+ "stripHtml": true,
29
+ "maxLengthEnv": [
30
+ "ROUTECODEX_C4M_INSTRUCTIONS_MAX",
31
+ "RCC_C4M_INSTRUCTIONS_MAX",
32
+ "ROUTECODEX_COMPAT_INSTRUCTIONS_MAX"
33
+ ]
34
+ }
35
+ ]
36
+ },
37
+ "response": {
38
+ "filters": [
39
+ {
40
+ "action": "rate_limit_text",
41
+ "needle": "The Codex-For.ME service is available, but you have reached the request limit"
42
+ }
43
+ ]
44
+ }
45
+ }
@@ -0,0 +1,38 @@
1
+ {
2
+ "version": "1.0.0",
3
+ "profiles": {
4
+ "chat:iflow": {
5
+ "protocol": "openai-chat",
6
+ "direction": "request",
7
+ "mappings": [
8
+ {
9
+ "action": "remove",
10
+ "path": "messages[*].content[*].annotations"
11
+ }
12
+ ],
13
+ "filters": []
14
+ },
15
+ "chat:glm": {
16
+ "protocol": "openai-chat",
17
+ "direction": "request",
18
+ "mappings": [
19
+ {
20
+ "action": "rename",
21
+ "from": "response_format",
22
+ "to": "extra.response_format"
23
+ }
24
+ ],
25
+ "filters": []
26
+ },
27
+ "responses:c4m": {
28
+ "protocol": "openai-responses",
29
+ "direction": "response",
30
+ "filters": [
31
+ {
32
+ "action": "rate_limit_text",
33
+ "needle": "The Codex-For.ME service is available, but you have reached the request limit"
34
+ }
35
+ ]
36
+ }
37
+ }
38
+ }
@@ -0,0 +1,314 @@
1
+ {
2
+ "version": "1.0.0",
3
+ "description": "LLM Switch Conversion 配置文件",
4
+ "lastModified": "2024-11-13T00:00:00.000Z",
5
+ "httpserver": {
6
+ "port": 5520,
7
+ "host": "0.0.0.0",
8
+ "timeout": 30000,
9
+ "cors": {
10
+ "enabled": true,
11
+ "origin": "*",
12
+ "methods": ["GET", "POST", "PUT", "DELETE", "OPTIONS"]
13
+ }
14
+ },
15
+ "virtualrouter": {
16
+ "inputProtocol": "openai",
17
+ "outputProtocol": "openai",
18
+ "providers": {
19
+ "chat-provider-1": {
20
+ "id": "chat-provider-1",
21
+ "enabled": true,
22
+ "type": "openai",
23
+ "name": "Generic Chat Provider",
24
+ "description": "Example chat-completions provider",
25
+ "baseUrl": "https://api.example.com/chat",
26
+ "apiVersion": "v1",
27
+ "compatibility": {
28
+ "type": "openai",
29
+ "features": ["streaming", "function-calling"]
30
+ },
31
+ "models": {
32
+ "chat-model-a": {
33
+ "displayName": "Chat-Model-A",
34
+ "description": "Latest chat model with improved reasoning",
35
+ "supportsStreaming": true,
36
+ "maxTokens": 128000,
37
+ "contextWindow": 128000,
38
+ "capabilities": ["text", "code", "reasoning", "tool-use"],
39
+ "pricing": {
40
+ "input": "0.001",
41
+ "output": "0.002",
42
+ "currency": "CNY"
43
+ },
44
+ "compatibility": {
45
+ "type": "openai",
46
+ "moduleConfig": {
47
+ "policy": {
48
+ "preflight": true
49
+ }
50
+ }
51
+ }
52
+ },
53
+ "chat-model-b": {
54
+ "displayName": "Chat-Model-B",
55
+ "description": "Lightweight chat model for faster responses",
56
+ "supportsStreaming": true,
57
+ "maxTokens": 8192,
58
+ "contextWindow": 8192,
59
+ "capabilities": ["text", "code", "basic-tool-use"],
60
+ "pricing": {
61
+ "input": "0.0005",
62
+ "output": "0.001",
63
+ "currency": "CNY"
64
+ },
65
+ "compatibility": {
66
+ "type": "openai",
67
+ "moduleConfig": {
68
+ "policy": {
69
+ "preflight": false
70
+ }
71
+ }
72
+ }
73
+ },
74
+ "chat-model-c": {
75
+ "displayName": "Chat-Model-C",
76
+ "description": "Ultra-fast chat model for quick responses",
77
+ "supportsStreaming": false,
78
+ "maxTokens": 4096,
79
+ "contextWindow": 4096,
80
+ "capabilities": ["text", "code"],
81
+ "pricing": {
82
+ "input": "0.0002",
83
+ "output": "0.0004",
84
+ "currency": "CNY"
85
+ },
86
+ "compatibility": {
87
+ "type": "openai",
88
+ "moduleConfig": {
89
+ "policy": {
90
+ "preflight": false
91
+ }
92
+ }
93
+ }
94
+ }
95
+ },
96
+ "apiKey": [
97
+ "your-api-key-here"
98
+ ],
99
+ "auth": {
100
+ "type": "apikey",
101
+ "apiKey": "your-api-key-here"
102
+ },
103
+ "rateLimit": {
104
+ "requestsPerMinute": 60,
105
+ "tokensPerMinute": 6000,
106
+ "concurrent": 5
107
+ },
108
+ "healthCheck": {
109
+ "enabled": true,
110
+ "endpoint": "/health",
111
+ "interval": 30000
112
+ }
113
+ },
114
+ "openai": {
115
+ "id": "openai",
116
+ "enabled": false,
117
+ "type": "openai",
118
+ "name": "OpenAI Provider",
119
+ "description": "Official OpenAI provider",
120
+ "baseUrl": "https://api.openai.com/v1",
121
+ "apiVersion": "v1",
122
+ "models": {
123
+ "gpt-4": {
124
+ "displayName": "GPT-4",
125
+ "supportsStreaming": true,
126
+ "maxTokens": 8192,
127
+ "contextWindow": 8192
128
+ },
129
+ "gpt-4-turbo": {
130
+ "displayName": "GPT-4 Turbo",
131
+ "supportsStreaming": true,
132
+ "maxTokens": 4096,
133
+ "contextWindow": 4096
134
+ },
135
+ "gpt-3.5-turbo": {
136
+ "displayName": "GPT-3.5 Turbo",
137
+ "supportsStreaming": true,
138
+ "maxTokens": 4096,
139
+ "contextWindow": 16384
140
+ }
141
+ },
142
+ "apiKey": [],
143
+ "auth": {
144
+ "type": "apikey"
145
+ },
146
+ "rateLimit": {
147
+ "requestsPerMinute": 3500,
148
+ "tokensPerMinute": 90000,
149
+ "concurrent": 100
150
+ }
151
+ },
152
+ "anthropic": {
153
+ "id": "anthropic",
154
+ "enabled": false,
155
+ "type": "anthropic",
156
+ "name": "Anthropic Claude Provider",
157
+ "description": "Anthropic Claude provider",
158
+ "baseUrl": "https://api.anthropic.com",
159
+ "apiVersion": "2023-06-01",
160
+ "models": {
161
+ "claude-3-sonnet": {
162
+ "displayName": "Claude 3 Sonnet",
163
+ "supportsStreaming": true,
164
+ "maxTokens": 200000,
165
+ "contextWindow": 200000
166
+ },
167
+ "claude-3-haiku": {
168
+ "displayName": "Claude 3 Haiku",
169
+ "supportsStreaming": false,
170
+ "maxTokens": 200000,
171
+ "contextWindow": 200000
172
+ }
173
+ },
174
+ "apiKey": [],
175
+ "auth": {
176
+ "type": "apikey"
177
+ },
178
+ "rateLimit": {
179
+ "requestsPerMinute": 1000,
180
+ "tokensPerMinute": 40000,
181
+ "concurrent": 5
182
+ }
183
+ }
184
+ },
185
+ "routing": {
186
+ "default": ["chat-provider-1.chat-model-a"],
187
+ "coding": ["chat-provider-1.chat-model-a"],
188
+ "longcontext": ["chat-provider-1.chat-model-a"],
189
+ "thinking": ["chat-provider-1.chat-model-a", "chat-model-b"],
190
+ "fast": ["chat-model-c"],
191
+ "vision": [],
192
+ "websearch": [],
193
+ "background": [],
194
+ "fallback": ["chat-provider-1.chat-model-b"]
195
+ },
196
+ "rules": {
197
+ "inputValidation": {
198
+ "enabled": true,
199
+ "strict": false,
200
+ "maxMessageLength": 100000,
201
+ "maxToolCount": 50
202
+ },
203
+ "outputValidation": {
204
+ "enabled": true,
205
+ "strict": false,
206
+ "maxResponseLength": 100000
207
+ },
208
+ "contentFiltering": {
209
+ "enabled": true,
210
+ "blockedWords": [],
211
+ "blockedPatterns": []
212
+ },
213
+ "rateLimiting": {
214
+ "enabled": true,
215
+ "perUser": {
216
+ "requestsPerMinute": 10,
217
+ "tokensPerMinute": 1000
218
+ },
219
+ "perProvider": {
220
+ "chat-provider-1": { "requestsPerMinute": 60, "tokensPerMinute": 6000 },
221
+ "openai": { "requestsPerMinute": 3500, "tokensPerMinute": 90000 },
222
+ "anthropic": { "requestsPerMinute": 1000, "tokensPerMinute": 40000 }
223
+ }
224
+ }
225
+ }
226
+ },
227
+ "serverTools": {
228
+ "replace": {
229
+ "web_fetch": {
230
+ "enabled": true,
231
+ "timeout": 30000,
232
+ "maxResponseSize": 1000000,
233
+ "allowedDomains": ["*"],
234
+ "blockedDomains": []
235
+ }
236
+ },
237
+ "custom": {
238
+ "enabled": false,
239
+ "tools": []
240
+ },
241
+ "enabled": true
242
+ },
243
+ "monitoring": {
244
+ "enabled": true,
245
+ "metrics": {
246
+ "requestCount": true,
247
+ "responseTime": true,
248
+ "errorRate": true,
249
+ "tokenUsage": true,
250
+ "providerPerformance": true
251
+ },
252
+ "logging": {
253
+ "level": "info",
254
+ "maxFileSize": "10MB",
255
+ "rotate": true,
256
+ "keepFiles": 7
257
+ },
258
+ "alerts": {
259
+ "errorRateThreshold": 0.05,
260
+ "responseTimeThreshold": 5000,
261
+ "tokenUsageThreshold": 10000
262
+ }
263
+ },
264
+ "conversion": {
265
+ "defaultVersion": "v2",
266
+ "passthrough": {
267
+ "enabled": true,
268
+ "criteria": {
269
+ "sameProtocol": true,
270
+ "sameProvider": true,
271
+ "minimalProcessing": true
272
+ }
273
+ },
274
+ "optimization": {
275
+ "enabled": true,
276
+ "caching": {
277
+ "enabled": true,
278
+ "maxSize": "100MB",
279
+ "ttl": 300000
280
+ },
281
+ "batching": {
282
+ "enabled": true,
283
+ "maxBatchSize": 10,
284
+ "maxBatchWaitTime": 100
285
+ }
286
+ }
287
+ },
288
+ "security": {
289
+ "apiKeyEncryption": {
290
+ "enabled": true,
291
+ "algorithm": "AES-256-GCM"
292
+ },
293
+ "requestValidation": {
294
+ "enabled": true,
295
+ "maxRequestSize": "10MB",
296
+ "allowedOrigins": ["*"],
297
+ "rateLimit": {
298
+ "enabled": true,
299
+ "requestsPerMinute": 1000,
300
+ "tokensPerMinute": 50000
301
+ }
302
+ },
303
+ "contentFiltering": {
304
+ "enabled": false,
305
+ "blockedContent": {
306
+ "profanity": false,
307
+ "personalData": false,
308
+ "malware": true,
309
+ "spam": true
310
+ },
311
+ "customFilters": []
312
+ }
313
+ }
314
+ }