@jsonstudio/llms 0.4.5 → 0.6.0

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 (92) hide show
  1. package/dist/conversion/codecs/anthropic-openai-codec.js +28 -2
  2. package/dist/conversion/codecs/gemini-openai-codec.js +23 -0
  3. package/dist/conversion/codecs/responses-openai-codec.js +8 -1
  4. package/dist/conversion/hub/node-support.js +14 -1
  5. package/dist/conversion/hub/pipeline/hub-pipeline.d.ts +66 -0
  6. package/dist/conversion/hub/pipeline/hub-pipeline.js +284 -193
  7. package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage1_format_parse/index.d.ts +11 -0
  8. package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage1_format_parse/index.js +6 -0
  9. package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage2_semantic_map/index.d.ts +16 -0
  10. package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage2_semantic_map/index.js +17 -0
  11. package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage3_context_capture/context-factories.d.ts +5 -0
  12. package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage3_context_capture/context-factories.js +17 -0
  13. package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage3_context_capture/index.d.ts +19 -0
  14. package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage3_context_capture/index.js +269 -0
  15. package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage1_semantic_map/index.d.ts +18 -0
  16. package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage1_semantic_map/index.js +141 -0
  17. package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage2_format_build/index.d.ts +11 -0
  18. package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage2_format_build/index.js +29 -0
  19. package/dist/conversion/hub/pipeline/stages/req_process/req_process_stage1_tool_governance/index.d.ts +16 -0
  20. package/dist/conversion/hub/pipeline/stages/req_process/req_process_stage1_tool_governance/index.js +15 -0
  21. package/dist/conversion/hub/pipeline/stages/req_process/req_process_stage2_route_select/index.d.ts +17 -0
  22. package/dist/conversion/hub/pipeline/stages/req_process/req_process_stage2_route_select/index.js +18 -0
  23. package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage1_sse_decode/index.d.ts +17 -0
  24. package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage1_sse_decode/index.js +63 -0
  25. package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage2_format_parse/index.d.ts +11 -0
  26. package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage2_format_parse/index.js +6 -0
  27. package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage3_semantic_map/index.d.ts +12 -0
  28. package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage3_semantic_map/index.js +6 -0
  29. package/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage1_client_remap/index.d.ts +13 -0
  30. package/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage1_client_remap/index.js +43 -0
  31. package/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage2_sse_stream/index.d.ts +17 -0
  32. package/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage2_sse_stream/index.js +22 -0
  33. package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage1_tool_governance/index.d.ts +16 -0
  34. package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage1_tool_governance/index.js +19 -0
  35. package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage2_finalize/index.d.ts +17 -0
  36. package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage2_finalize/index.js +19 -0
  37. package/dist/conversion/hub/pipeline/stages/utils.d.ts +2 -0
  38. package/dist/conversion/hub/pipeline/stages/utils.js +11 -0
  39. package/dist/conversion/hub/pipeline/target-utils.d.ts +5 -0
  40. package/dist/conversion/hub/pipeline/target-utils.js +87 -0
  41. package/dist/conversion/hub/process/chat-process.js +11 -11
  42. package/dist/conversion/hub/response/provider-response.js +69 -122
  43. package/dist/conversion/hub/response/response-mappers.d.ts +19 -0
  44. package/dist/conversion/hub/response/response-mappers.js +22 -2
  45. package/dist/conversion/hub/response/response-runtime.d.ts +8 -0
  46. package/dist/conversion/hub/response/response-runtime.js +239 -6
  47. package/dist/conversion/hub/semantic-mappers/anthropic-mapper.d.ts +8 -0
  48. package/dist/conversion/hub/semantic-mappers/anthropic-mapper.js +119 -59
  49. package/dist/conversion/hub/semantic-mappers/chat-mapper.js +74 -13
  50. package/dist/conversion/hub/semantic-mappers/gemini-mapper.js +0 -9
  51. package/dist/conversion/hub/semantic-mappers/responses-mapper.js +16 -13
  52. package/dist/conversion/hub/snapshot-recorder.d.ts +13 -0
  53. package/dist/conversion/hub/snapshot-recorder.js +90 -50
  54. package/dist/conversion/hub/standardized-bridge.js +44 -30
  55. package/dist/conversion/hub/types/chat-envelope.d.ts +68 -0
  56. package/dist/conversion/hub/types/standardized.d.ts +97 -0
  57. package/dist/conversion/pipeline/codecs/v2/anthropic-openai-pipeline.js +29 -2
  58. package/dist/conversion/pipeline/codecs/v2/responses-openai-pipeline.js +68 -1
  59. package/dist/conversion/responses/responses-openai-bridge.d.ts +6 -1
  60. package/dist/conversion/responses/responses-openai-bridge.js +132 -6
  61. package/dist/conversion/shared/anthropic-message-utils.d.ts +9 -1
  62. package/dist/conversion/shared/anthropic-message-utils.js +334 -14
  63. package/dist/conversion/shared/bridge-actions.js +267 -40
  64. package/dist/conversion/shared/bridge-message-utils.js +54 -8
  65. package/dist/conversion/shared/bridge-policies.js +29 -4
  66. package/dist/conversion/shared/chat-envelope-validator.d.ts +8 -0
  67. package/dist/conversion/shared/chat-envelope-validator.js +128 -0
  68. package/dist/conversion/shared/chat-request-filters.js +108 -25
  69. package/dist/conversion/shared/mcp-injection.js +41 -20
  70. package/dist/conversion/shared/openai-finalizer.d.ts +11 -0
  71. package/dist/conversion/shared/openai-finalizer.js +73 -0
  72. package/dist/conversion/shared/openai-message-normalize.js +32 -31
  73. package/dist/conversion/shared/reasoning-normalizer.d.ts +1 -0
  74. package/dist/conversion/shared/reasoning-normalizer.js +50 -18
  75. package/dist/conversion/shared/responses-output-builder.d.ts +1 -1
  76. package/dist/conversion/shared/responses-output-builder.js +76 -25
  77. package/dist/conversion/shared/responses-reasoning-registry.d.ts +8 -0
  78. package/dist/conversion/shared/responses-reasoning-registry.js +61 -0
  79. package/dist/conversion/shared/responses-response-utils.js +32 -2
  80. package/dist/conversion/shared/responses-tool-utils.js +28 -2
  81. package/dist/conversion/shared/snapshot-hooks.d.ts +9 -0
  82. package/dist/conversion/shared/snapshot-hooks.js +60 -6
  83. package/dist/conversion/shared/snapshot-utils.d.ts +16 -0
  84. package/dist/conversion/shared/snapshot-utils.js +84 -0
  85. package/dist/conversion/shared/tool-filter-pipeline.js +45 -5
  86. package/dist/conversion/shared/tool-governor.js +5 -0
  87. package/dist/conversion/shared/tool-mapping.js +13 -2
  88. package/dist/filters/special/request-tool-choice-policy.js +3 -1
  89. package/dist/filters/special/request-tool-list-filter.d.ts +11 -0
  90. package/dist/filters/special/request-tool-list-filter.js +20 -7
  91. package/dist/sse/shared/responses-output-normalizer.js +5 -4
  92. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  import { runStandardChatRequestFilters } from '../index.js';
2
2
  import { FilterEngine, ResponseToolTextCanonicalizeFilter, ResponseToolArgumentsStringifyFilter, ResponseFinishInvariantsFilter } from '../../filters/index.js';
3
- import { buildAnthropicFromOpenAIChat, buildOpenAIChatFromAnthropic, mapAnthropicToolsToChat } from '../shared/anthropic-message-utils.js';
3
+ import { buildAnthropicFromOpenAIChat, buildOpenAIChatFromAnthropic, mapAnthropicToolsToChat, buildAnthropicToolAliasMap } from '../shared/anthropic-message-utils.js';
4
4
  export { buildAnthropicFromOpenAIChat, buildOpenAIChatFromAnthropic };
5
5
  export { buildAnthropicRequestFromOpenAIChat } from '../shared/anthropic-message-utils.js';
6
6
  export class AnthropicOpenAIConversionCodec {
@@ -19,6 +19,11 @@ export class AnthropicOpenAIConversionCodec {
19
19
  const model = String(payload?.model || 'unknown');
20
20
  const { messages } = buildOpenAIChatFromAnthropic(payload);
21
21
  const out = { model, messages };
22
+ const aliasMap = buildAnthropicToolAliasMap(payload?.tools);
23
+ if (aliasMap) {
24
+ context.metadata = context.metadata ?? {};
25
+ context.metadata.anthropicToolNameMap = aliasMap;
26
+ }
22
27
  // 最小必要的形状转换:Anthropic tools → OpenAI Chat function 工具
23
28
  try {
24
29
  const normalizedTools = mapAnthropicToolsToChat(payload?.tools);
@@ -86,6 +91,27 @@ export class AnthropicOpenAIConversionCodec {
86
91
  staged = await engine.run('response_map', staged, resCtxBase);
87
92
  staged = await engine.run('response_post', staged, resCtxBase);
88
93
  const governedChat = staged;
89
- return buildAnthropicFromOpenAIChat(governedChat);
94
+ const aliasMap = coerceAliasMap(context.metadata?.anthropicToolNameMap);
95
+ return buildAnthropicFromOpenAIChat(governedChat, {
96
+ toolNameMap: aliasMap,
97
+ requestId: context.requestId
98
+ });
99
+ }
100
+ }
101
+ function coerceAliasMap(candidate) {
102
+ if (!candidate || typeof candidate !== 'object' || Array.isArray(candidate)) {
103
+ return undefined;
104
+ }
105
+ let populated = false;
106
+ const map = {};
107
+ for (const [key, value] of Object.entries(candidate)) {
108
+ if (typeof key !== 'string' || typeof value !== 'string')
109
+ continue;
110
+ const trimmedKey = key.trim();
111
+ if (!trimmedKey.length)
112
+ continue;
113
+ map[trimmedKey] = value;
114
+ populated = true;
90
115
  }
116
+ return populated ? map : undefined;
91
117
  }
@@ -3,6 +3,7 @@ import { resolveBridgePolicy, resolvePolicyActions } from '../shared/bridge-poli
3
3
  import { normalizeChatMessageContent } from '../shared/chat-output-normalizer.js';
4
4
  import { mapBridgeToolsToChat } from '../shared/tool-mapping.js';
5
5
  import { prepareGeminiToolsForBridge } from '../shared/gemini-tool-utils.js';
6
+ import { registerResponsesReasoning, consumeResponsesReasoning, registerResponsesOutputTextMeta, consumeResponsesOutputTextMeta } from '../shared/responses-reasoning-registry.js';
6
7
  function isObject(v) {
7
8
  return !!v && typeof v === 'object' && !Array.isArray(v);
8
9
  }
@@ -276,6 +277,14 @@ export function buildOpenAIChatFromGeminiResponse(payload) {
276
277
  if (Object.keys(usage).length > 0) {
277
278
  chatResp.usage = usage;
278
279
  }
280
+ const preservedReasoning = consumeResponsesReasoning(chatResp.id);
281
+ if (preservedReasoning && preservedReasoning.length) {
282
+ chatResp.__responses_reasoning = preservedReasoning;
283
+ }
284
+ const preservedOutputMeta = consumeResponsesOutputTextMeta(chatResp.id);
285
+ if (preservedOutputMeta) {
286
+ chatResp.__responses_output_text_meta = preservedOutputMeta;
287
+ }
279
288
  return chatResp;
280
289
  }
281
290
  export function buildGeminiFromOpenAIChat(chatResp) {
@@ -344,6 +353,12 @@ export function buildGeminiFromOpenAIChat(chatResp) {
344
353
  if (contentText && contentText.length) {
345
354
  parts.push({ text: contentText });
346
355
  }
356
+ const reasoningText = typeof msg?.reasoning_content === 'string' && msg.reasoning_content.trim().length
357
+ ? String(msg.reasoning_content).trim()
358
+ : undefined;
359
+ if (reasoningText) {
360
+ parts.push({ reasoning: reasoningText });
361
+ }
347
362
  const toolCalls = Array.isArray(msg.tool_calls) ? msg.tool_calls : [];
348
363
  for (const tc of toolCalls) {
349
364
  if (!tc || typeof tc !== 'object')
@@ -388,7 +403,9 @@ export function buildGeminiFromOpenAIChat(chatResp) {
388
403
  usageMetadata.candidatesTokenCount = completionTokens;
389
404
  if (Number.isFinite(totalTokens))
390
405
  usageMetadata.totalTokenCount = totalTokens;
406
+ const responseId = typeof chatResp?.id === 'string' ? String(chatResp.id) : `chatcmpl_${Date.now()}`;
391
407
  const out = {
408
+ id: responseId,
392
409
  candidates: [candidate]
393
410
  };
394
411
  if (chatResp?.model) {
@@ -396,6 +413,12 @@ export function buildGeminiFromOpenAIChat(chatResp) {
396
413
  }
397
414
  if (Object.keys(usageMetadata).length > 0)
398
415
  out.usageMetadata = usageMetadata;
416
+ if (Array.isArray(chatResp?.__responses_reasoning)) {
417
+ registerResponsesReasoning(responseId, chatResp.__responses_reasoning);
418
+ }
419
+ if (chatResp?.__responses_output_text_meta) {
420
+ registerResponsesOutputTextMeta(responseId, chatResp.__responses_output_text_meta);
421
+ }
399
422
  return out;
400
423
  }
401
424
  export class GeminiOpenAIConversionCodec {
@@ -151,7 +151,14 @@ export class ResponsesOpenAIConversionCodec {
151
151
  // Debug snapshot after mapping to Responses JSON (non-stream)
152
152
  try {
153
153
  const { writeSnapshotViaHooks } = await import('../shared/snapshot-hooks.js');
154
- await writeSnapshotViaHooks({ endpoint: '/v1/responses', stage: 'response_mapped_json', requestId: context.requestId || `req_${Date.now()}`, data: responsesJson, verbosity: 'verbose' });
154
+ await writeSnapshotViaHooks({
155
+ endpoint: '/v1/responses',
156
+ stage: 'response_mapped_json',
157
+ requestId: context.requestId || `req_${Date.now()}`,
158
+ data: responsesJson,
159
+ channel: 'responses',
160
+ verbosity: 'verbose'
161
+ });
155
162
  }
156
163
  catch { /* ignore */ }
157
164
  return responsesJson;
@@ -102,7 +102,7 @@ function deriveAdapterContext(context, fallbackProtocol) {
102
102
  (typeof metadata.providerProtocol === 'string' ? metadata.providerProtocol : undefined) ||
103
103
  fallbackProtocol;
104
104
  const streamingHint = metadata.stream === true ? 'force' : metadata.stream === false ? 'disable' : 'auto';
105
- const toolCallIdStyle = typeof metadata.toolCallIdStyle === 'string' ? metadata.toolCallIdStyle : undefined;
105
+ const toolCallIdStyle = normalizeToolCallIdStyleCandidate(metadata.toolCallIdStyle);
106
106
  return {
107
107
  requestId: context.request.id,
108
108
  entryEndpoint: (typeof requestContext.entryEndpoint === 'string' ? requestContext.entryEndpoint : context.request.endpoint) ||
@@ -115,3 +115,16 @@ function deriveAdapterContext(context, fallbackProtocol) {
115
115
  toolCallIdStyle
116
116
  };
117
117
  }
118
+ function normalizeToolCallIdStyleCandidate(value) {
119
+ if (typeof value !== 'string') {
120
+ return undefined;
121
+ }
122
+ const normalized = value.trim().toLowerCase();
123
+ if (normalized === 'fc') {
124
+ return 'fc';
125
+ }
126
+ if (normalized === 'preserve') {
127
+ return 'preserve';
128
+ }
129
+ return undefined;
130
+ }
@@ -0,0 +1,66 @@
1
+ import { Readable } from 'node:stream';
2
+ import type { StandardizedRequest, ProcessedRequest } from '../types/standardized.js';
3
+ import type { JsonObject } from '../types/json.js';
4
+ import type { VirtualRouterConfig, RoutingDecision, RoutingDiagnostics, TargetMetadata } from '../../../router/virtual-router/types.js';
5
+ import { type HubProcessNodeResult } from '../process/chat-process.js';
6
+ export interface HubPipelineConfig {
7
+ virtualRouter: VirtualRouterConfig;
8
+ }
9
+ export interface HubPipelineRequestMetadata extends Record<string, unknown> {
10
+ entryEndpoint?: string;
11
+ providerProtocol?: string;
12
+ processMode?: 'chat' | 'passthrough';
13
+ stage?: 'inbound' | 'outbound';
14
+ direction?: 'request' | 'response';
15
+ stream?: boolean;
16
+ routeHint?: string;
17
+ }
18
+ export interface HubPipelineRequest {
19
+ id?: string;
20
+ endpoint: string;
21
+ payload: Record<string, unknown> | {
22
+ readable?: Readable;
23
+ } | Readable;
24
+ metadata?: HubPipelineRequestMetadata;
25
+ }
26
+ type HubPipelineNodeMetadata = HubProcessNodeResult['metadata'] | Record<string, unknown>;
27
+ export interface HubPipelineNodeResult {
28
+ id: string;
29
+ success: boolean;
30
+ metadata: HubPipelineNodeMetadata;
31
+ error?: JsonObject;
32
+ }
33
+ export interface HubPipelineResult {
34
+ requestId: string;
35
+ providerPayload?: Record<string, unknown>;
36
+ standardizedRequest?: StandardizedRequest;
37
+ processedRequest?: ProcessedRequest;
38
+ routingDecision?: RoutingDecision;
39
+ routingDiagnostics?: RoutingDiagnostics;
40
+ target?: TargetMetadata;
41
+ metadata: Record<string, unknown>;
42
+ nodeResults: HubPipelineNodeResult[];
43
+ }
44
+ export declare class HubPipeline {
45
+ private readonly routerEngine;
46
+ private config;
47
+ constructor(config: HubPipelineConfig);
48
+ updateVirtualRouterConfig(nextConfig: VirtualRouterConfig): void;
49
+ private executeRequestStagePipeline;
50
+ execute(request: HubPipelineRequest): Promise<HubPipelineResult>;
51
+ private captureAnthropicAliasMap;
52
+ private shouldCaptureAnthropicAlias;
53
+ private resolveAliasMapFromSources;
54
+ private resolveProtocolHooks;
55
+ private buildAdapterContext;
56
+ private maybeCreateStageRecorder;
57
+ private asJsonObject;
58
+ private normalizeRequest;
59
+ private convertProcessNodeResult;
60
+ private materializePayload;
61
+ private unwrapReadable;
62
+ private convertSsePayload;
63
+ private resolveSseProtocol;
64
+ private extractModelHint;
65
+ }
66
+ export {};