@jsonstudio/llms 0.4.6 → 0.6.2

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 (99) 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 +23 -17
  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 +135 -55
  49. package/dist/conversion/hub/semantic-mappers/chat-mapper.js +80 -40
  50. package/dist/conversion/hub/semantic-mappers/gemini-mapper.js +5 -29
  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 +49 -38
  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 -10
  61. package/dist/conversion/shared/anthropic-message-utils.d.ts +9 -1
  62. package/dist/conversion/shared/anthropic-message-utils.js +414 -26
  63. package/dist/conversion/shared/bridge-actions.js +267 -95
  64. package/dist/conversion/shared/bridge-message-utils.js +54 -8
  65. package/dist/conversion/shared/bridge-policies.js +21 -2
  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 +109 -28
  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/protocol-state.d.ts +4 -0
  74. package/dist/conversion/shared/protocol-state.js +23 -0
  75. package/dist/conversion/shared/reasoning-normalizer.d.ts +1 -0
  76. package/dist/conversion/shared/reasoning-normalizer.js +50 -18
  77. package/dist/conversion/shared/responses-output-builder.d.ts +1 -1
  78. package/dist/conversion/shared/responses-output-builder.js +76 -25
  79. package/dist/conversion/shared/responses-reasoning-registry.d.ts +8 -0
  80. package/dist/conversion/shared/responses-reasoning-registry.js +61 -0
  81. package/dist/conversion/shared/responses-response-utils.js +32 -2
  82. package/dist/conversion/shared/responses-tool-utils.js +28 -2
  83. package/dist/conversion/shared/snapshot-hooks.d.ts +9 -0
  84. package/dist/conversion/shared/snapshot-hooks.js +60 -6
  85. package/dist/conversion/shared/snapshot-utils.d.ts +16 -0
  86. package/dist/conversion/shared/snapshot-utils.js +84 -0
  87. package/dist/conversion/shared/tool-filter-pipeline.js +46 -7
  88. package/dist/conversion/shared/tool-mapping.js +13 -2
  89. package/dist/filters/index.d.ts +18 -0
  90. package/dist/filters/index.js +0 -1
  91. package/dist/filters/special/request-streaming-to-nonstreaming.d.ts +13 -0
  92. package/dist/filters/special/request-streaming-to-nonstreaming.js +13 -1
  93. package/dist/filters/special/request-tool-choice-policy.js +3 -1
  94. package/dist/filters/special/request-tool-list-filter.d.ts +11 -0
  95. package/dist/filters/special/request-tool-list-filter.js +20 -7
  96. package/dist/sse/shared/responses-output-normalizer.js +5 -4
  97. package/dist/sse/sse-to-json/builders/response-builder.js +24 -1
  98. package/dist/sse/types/responses-types.d.ts +2 -0
  99. package/package.json +1 -1
@@ -1,5 +1,6 @@
1
1
  import { FilterEngine } from '../../filters/index.js';
2
2
  import { loadFieldMapConfig } from '../../filters/utils/fieldmap-loader.js';
3
+ import { createSnapshotWriter } from './snapshot-utils.js';
3
4
  export async function runChatRequestToolFilters(chatRequest, options = {}) {
4
5
  const reqCtxBase = {
5
6
  requestId: options.requestId ?? `req_${Date.now()}`,
@@ -10,16 +11,35 @@ export async function runChatRequestToolFilters(chatRequest, options = {}) {
10
11
  toolFilterHints: options.toolFilterHints,
11
12
  debug: { emit: () => { } }
12
13
  };
14
+ const snapshot = createSnapshotWriter({
15
+ requestId: reqCtxBase.requestId,
16
+ endpoint: reqCtxBase.endpoint,
17
+ folderHint: 'openai-chat'
18
+ });
19
+ const recordStage = (stage, payload) => {
20
+ if (!snapshot)
21
+ return;
22
+ snapshot(stage, payload);
23
+ };
24
+ recordStage('req_process_tool_filters_input', chatRequest);
13
25
  const engine = new FilterEngine();
14
- try {
15
- const { RequestToolListFilter } = await import('../../filters/index.js');
16
- engine.registerFilter(new RequestToolListFilter());
26
+ const profile = (reqCtxBase.profile || '').toLowerCase();
27
+ const endpoint = (reqCtxBase.endpoint || '').toLowerCase();
28
+ const isAnthropic = profile === 'anthropic-messages' || endpoint.includes('/v1/messages');
29
+ if (!isAnthropic) {
30
+ try {
31
+ const { RequestToolListFilter } = await import('../../filters/index.js');
32
+ engine.registerFilter(new RequestToolListFilter());
33
+ }
34
+ catch {
35
+ /* optional */
36
+ }
17
37
  }
18
- catch { /* optional */ }
19
- const { RequestToolCallsStringifyFilter, RequestToolChoicePolicyFilter, RequestStreamingToNonStreamingFilter } = await import('../../filters/index.js');
38
+ const { RequestToolCallsStringifyFilter, RequestToolChoicePolicyFilter } = await import('../../filters/index.js');
20
39
  engine.registerFilter(new RequestToolCallsStringifyFilter());
21
- engine.registerFilter(new RequestToolChoicePolicyFilter());
22
- engine.registerFilter(new RequestStreamingToNonStreamingFilter());
40
+ if (!isAnthropic) {
41
+ engine.registerFilter(new RequestToolChoicePolicyFilter());
42
+ }
23
43
  try {
24
44
  const cfg = await loadFieldMapConfig('openai-openai.fieldmap.json');
25
45
  if (cfg)
@@ -33,8 +53,12 @@ export async function runChatRequestToolFilters(chatRequest, options = {}) {
33
53
  }
34
54
  catch { /* ignore */ }
35
55
  let staged = await engine.run('request_pre', chatRequest, reqCtxBase);
56
+ recordStage('req_process_tool_filters_request_pre', staged);
36
57
  staged = await engine.run('request_map', staged, reqCtxBase);
58
+ recordStage('req_process_tool_filters_request_map', staged);
37
59
  staged = await engine.run('request_post', staged, reqCtxBase);
60
+ recordStage('req_process_tool_filters_request_post', staged);
61
+ recordStage('req_process_tool_filters_output', staged);
38
62
  return staged;
39
63
  }
40
64
  export async function runChatResponseToolFilters(chatJson, options = {}) {
@@ -45,6 +69,17 @@ export async function runChatResponseToolFilters(chatJson, options = {}) {
45
69
  profile: options.profile || 'openai-chat',
46
70
  debug: { emit: () => { } }
47
71
  };
72
+ const snapshot = createSnapshotWriter({
73
+ requestId: resCtxBase.requestId,
74
+ endpoint: resCtxBase.endpoint,
75
+ folderHint: 'openai-chat'
76
+ });
77
+ const recordStage = (stage, payload) => {
78
+ if (!snapshot)
79
+ return;
80
+ snapshot(stage, payload);
81
+ };
82
+ recordStage('resp_process_tool_filters_input', chatJson);
48
83
  const engine = new FilterEngine();
49
84
  const { ResponseToolTextCanonicalizeFilter, ResponseToolArgumentsStringifyFilter, ResponseFinishInvariantsFilter } = await import('../../filters/index.js');
50
85
  engine.registerFilter(new ResponseToolTextCanonicalizeFilter());
@@ -73,7 +108,11 @@ export async function runChatResponseToolFilters(chatJson, options = {}) {
73
108
  }
74
109
  catch { /* ignore */ }
75
110
  let staged = await engine.run('response_pre', chatJson, resCtxBase);
111
+ recordStage('resp_process_tool_filters_response_pre', staged);
76
112
  staged = await engine.run('response_map', staged, resCtxBase);
113
+ recordStage('resp_process_tool_filters_response_map', staged);
77
114
  staged = await engine.run('response_post', staged, resCtxBase);
115
+ recordStage('resp_process_tool_filters_response_post', staged);
116
+ recordStage('resp_process_tool_filters_output', staged);
78
117
  return staged;
79
118
  }
@@ -32,8 +32,8 @@ function pickToolName(candidates, options) {
32
32
  return undefined;
33
33
  }
34
34
  function resolveToolDescription(candidate) {
35
- if (typeof candidate === 'string' && candidate.trim().length) {
36
- return candidate.trim();
35
+ if (typeof candidate === 'string') {
36
+ return candidate;
37
37
  }
38
38
  return undefined;
39
39
  }
@@ -121,6 +121,17 @@ export function chatToolToBridgeDefinition(rawTool, options) {
121
121
  if (strict !== undefined) {
122
122
  responseShape.strict = strict;
123
123
  }
124
+ const fnOut = { name };
125
+ if (description !== undefined) {
126
+ fnOut.description = description;
127
+ }
128
+ if (parameters !== undefined) {
129
+ fnOut.parameters = parameters;
130
+ }
131
+ if (strict !== undefined) {
132
+ fnOut.strict = strict;
133
+ }
134
+ responseShape.function = fnOut;
124
135
  return responseShape;
125
136
  }
126
137
  export function mapChatToolsToBridge(rawTools, options) {
@@ -0,0 +1,18 @@
1
+ export * from './types.js';
2
+ export * from './engine.js';
3
+ export * from './builtin/whitelist-filter.js';
4
+ export * from './builtin/blacklist-filter.js';
5
+ export * from './builtin/add-fields-filter.js';
6
+ export * from './special/request-toolcalls-stringify.js';
7
+ export * from './special/request-tool-choice-policy.js';
8
+ export * from './special/request-tool-list-filter.js';
9
+ export * from './special/tool-filter-hooks.js';
10
+ export * from './special/response-tool-text-canonicalize.js';
11
+ export * from './special/response-tool-arguments-stringify.js';
12
+ export * from './special/response-finish-invariants.js';
13
+ export * from './special/request-tools-normalize.js';
14
+ export * from './special/response-tool-arguments-toon-decode.js';
15
+ export * from './special/response-tool-arguments-blacklist.js';
16
+ export * from './special/response-tool-arguments-schema-converge.js';
17
+ export * from './special/response-tool-arguments-whitelist.js';
18
+ export * from './special/tool-post-constraints.js';
@@ -9,7 +9,6 @@ export * from './special/request-toolcalls-stringify.js';
9
9
  export * from './special/request-tool-choice-policy.js';
10
10
  export * from './special/request-tool-list-filter.js';
11
11
  export * from './special/tool-filter-hooks.js';
12
- export * from './special/request-streaming-to-nonstreaming.js';
13
12
  export * from './special/response-tool-text-canonicalize.js';
14
13
  export * from './special/response-tool-arguments-stringify.js';
15
14
  export * from './special/response-finish-invariants.js';
@@ -0,0 +1,13 @@
1
+ import type { Filter, FilterContext, FilterResult, JsonObject } from '../types.js';
2
+ /**
3
+ * RequestStreamingToNonStreamingFilter (request_post)
4
+ * - Unifies provider requests to non-streaming regardless of inbound stream flag.
5
+ * - Preserves original intent via `originalStream` and `_originalStreamOptions`,
6
+ * but ensures `stream: false` is sent to providers.
7
+ */
8
+ export declare class RequestStreamingToNonStreamingFilter implements Filter<JsonObject> {
9
+ readonly name = "request_streaming_to_nonstreaming";
10
+ readonly stage: FilterContext['stage'];
11
+ apply(input: JsonObject, ctx: FilterContext): FilterResult<JsonObject>;
12
+ private shouldPreserveStream;
13
+ }
@@ -7,9 +7,12 @@
7
7
  export class RequestStreamingToNonStreamingFilter {
8
8
  name = 'request_streaming_to_nonstreaming';
9
9
  stage = 'request_post';
10
- apply(input) {
10
+ apply(input, ctx) {
11
11
  try {
12
12
  const out = JSON.parse(JSON.stringify(input || {}));
13
+ if (this.shouldPreserveStream(out, ctx)) {
14
+ return { ok: true, data: out };
15
+ }
13
16
  if (out.stream === true) {
14
17
  out.originalStream = true;
15
18
  out.stream = false;
@@ -24,4 +27,13 @@ export class RequestStreamingToNonStreamingFilter {
24
27
  return { ok: true, data: input };
25
28
  }
26
29
  }
30
+ shouldPreserveStream(payload, ctx) {
31
+ if (ctx.stream === true) {
32
+ return true;
33
+ }
34
+ if (payload.stream === true) {
35
+ return true;
36
+ }
37
+ return false;
38
+ }
27
39
  }
@@ -11,8 +11,10 @@ export class RequestToolChoicePolicyFilter {
11
11
  const out = JSON.parse(JSON.stringify(input || {}));
12
12
  const tools = Array.isArray(out.tools) ? out.tools : [];
13
13
  if (tools.length > 0) {
14
- if (out.tool_choice == null)
14
+ const hasOwn = Object.prototype.hasOwnProperty.call(out, 'tool_choice');
15
+ if (!hasOwn || out.tool_choice === undefined) {
15
16
  out.tool_choice = 'auto';
17
+ }
16
18
  }
17
19
  else {
18
20
  if (Object.prototype.hasOwnProperty.call(out, 'tool_choice'))
@@ -0,0 +1,11 @@
1
+ import type { Filter, FilterContext, FilterResult, JsonObject } from '../types.js';
2
+ /**
3
+ * RequestToolListFilter (request_pre)
4
+ * - Generic tool-list filter/augment hook
5
+ * - Currently only handles MCP tools with phase-based exposure
6
+ */
7
+ export declare class RequestToolListFilter implements Filter<JsonObject> {
8
+ readonly name = "request_tool_list_filter";
9
+ readonly stage: FilterContext['stage'];
10
+ apply(input: JsonObject, ctx: FilterContext): FilterResult<JsonObject>;
11
+ }
@@ -94,15 +94,21 @@ function removeToolByName(tools, name) {
94
94
  export class RequestToolListFilter {
95
95
  name = 'request_tool_list_filter';
96
96
  stage = 'request_pre';
97
- apply(input) {
97
+ apply(input, ctx) {
98
98
  try {
99
99
  const out = JSON.parse(JSON.stringify(input || {}));
100
- const tools = Array.isArray(out.tools) ? out.tools : [];
101
- if (!tools.length)
102
- return { ok: true, data: out };
100
+ const hadIncomingTools = Array.isArray(out.tools);
101
+ const tools = hadIncomingTools ? out.tools : [];
102
+ if (!hadIncomingTools) {
103
+ out.tools = tools;
104
+ }
103
105
  const mode = envMode();
104
- if (mode === 'off')
106
+ if (mode === 'off') {
107
+ if (!hadIncomingTools && tools.length === 0) {
108
+ delete out.tools;
109
+ }
105
110
  return { ok: true, data: out };
111
+ }
106
112
  const messages = Array.isArray(out.messages) ? out.messages : [];
107
113
  const servers = new Set();
108
114
  for (const s of getEnvServers())
@@ -137,14 +143,21 @@ export class RequestToolListFilter {
137
143
  required: ['server', 'uri'],
138
144
  additionalProperties: false
139
145
  };
146
+ const profileKey = String(ctx?.profile || '').toLowerCase();
147
+ const endpointKey = String(ctx?.endpoint || '').toLowerCase();
148
+ const prefersLegacyListDescription = profileKey.includes('anthropic') ||
149
+ endpointKey.includes('/v1/messages');
150
+ const listDescription = prefersLegacyListDescription
151
+ ? 'List resources from an MCP server.'
152
+ : 'List resources from a given MCP server (arguments.server = server label).';
140
153
  if (mode === 'all') {
141
- ensureFunctionTool(tools, 'list_mcp_resources', 'List resources from an MCP server.', listResParams);
154
+ ensureFunctionTool(tools, 'list_mcp_resources', listDescription, listResParams);
142
155
  ensureFunctionTool(tools, 'list_mcp_resource_templates', 'List resource templates from MCP servers.', listTplParams);
143
156
  ensureFunctionTool(tools, 'read_mcp_resource', 'Read a specific MCP resource.', readResParamsBase);
144
157
  }
145
158
  else {
146
159
  // phase
147
- ensureFunctionTool(tools, 'list_mcp_resources', 'List resources from an MCP server.', listResParams);
160
+ ensureFunctionTool(tools, 'list_mcp_resources', listDescription, listResParams);
148
161
  ensureFunctionTool(tools, 'list_mcp_resource_templates', 'List resource templates from MCP servers.', listTplParams);
149
162
  // read is only exposed when we have known servers
150
163
  if (knownServers.length > 0) {
@@ -13,9 +13,8 @@ export function normalizeResponsesMessageItem(item, options) {
13
13
  const extras = Array.isArray(additionalReasoning) ? additionalReasoning : [additionalReasoning];
14
14
  for (const entry of extras) {
15
15
  if (typeof entry === 'string') {
16
- const trimmed = entry.trim();
17
- if (trimmed.length) {
18
- reasoningChunks.push(trimmed);
16
+ if (entry.length) {
17
+ reasoningChunks.push(entry);
19
18
  }
20
19
  }
21
20
  }
@@ -41,5 +40,7 @@ export function normalizeResponsesMessageItem(item, options) {
41
40
  }
42
41
  export function expandResponsesMessageItem(item, options) {
43
42
  const { message, reasoning } = normalizeResponsesMessageItem(item, options);
44
- return reasoning ? [message, reasoning] : [message];
43
+ // Responses upstream (legacy + CCR) emitted reasoning segments before the final assistant message.
44
+ // Preserve that ordering so roundtrip comparisons against provider snapshots remain identical.
45
+ return reasoning ? [reasoning, message] : [message];
45
46
  }
@@ -574,7 +574,30 @@ export class ResponsesResponseBuilder {
574
574
  * 处理required_action事件
575
575
  */
576
576
  handleRequiredAction(event) {
577
- // TODO: 实现required_action处理
577
+ const payload = event.data ?? {};
578
+ const responsePayload = payload.response ?? payload;
579
+ const requiredAction = responsePayload.required_action ??
580
+ payload.required_action ??
581
+ undefined;
582
+ const usage = responsePayload.usage ??
583
+ payload.usage ??
584
+ this.response.usage;
585
+ const nextResponse = {
586
+ ...this.response,
587
+ object: 'response',
588
+ id: responsePayload.id ?? this.response.id,
589
+ status: responsePayload.status ?? 'requires_action',
590
+ output: Array.isArray(responsePayload.output) && responsePayload.output.length
591
+ ? responsePayload.output
592
+ : this.buildOutputItems(),
593
+ required_action: requiredAction ?? this.response.required_action,
594
+ usage
595
+ };
596
+ if (responsePayload.metadata) {
597
+ nextResponse.metadata = responsePayload.metadata;
598
+ }
599
+ this.response = nextResponse;
600
+ this.state = 'completed';
578
601
  }
579
602
  /**
580
603
  * 处理response.done事件
@@ -3,6 +3,7 @@
3
3
  * 支持OpenAI Responses API的JSON↔SSE双向转换
4
4
  */
5
5
  import { BaseSseEvent, StreamDirection, type JsonObject, type JsonValue } from './core-interfaces.js';
6
+ import type { RequiredAction } from './sse-events.js';
6
7
  export * from './sse-events.js';
7
8
  export type ResponsesSseEventType = 'response.created' | 'response.in_progress' | 'response.completed' | 'response.required_action' | 'response.done' | 'response.output_item.added' | 'response.output_item.done' | 'response.content_part.added' | 'response.content_part.done' | 'response.output_text.delta' | 'response.output_text.done' | 'response.reasoning_text.delta' | 'response.reasoning_text.done' | 'response.reasoning_signature.delta' | 'response.reasoning_image.delta' | 'response.reasoning_summary_part.added' | 'response.reasoning_summary_part.done' | 'response.reasoning_summary_text.delta' | 'response.reasoning_summary_text.done' | 'response.function_call_arguments.delta' | 'response.function_call_arguments.done' | 'response.error' | 'response.cancelled' | 'response.start' | 'content_part.delta' | 'reasoning.delta' | 'function_call.start' | 'function_call.delta' | 'function_call.done' | 'output_item.start' | 'content_part.start' | 'content_part.done' | 'output_item.done' | 'reasoning.start' | 'reasoning.done' | 'required_action' | 'error';
8
9
  export interface ResponsesSseEvent extends BaseSseEvent {
@@ -118,6 +119,7 @@ export interface ResponsesResponse {
118
119
  output: ResponsesOutputItem[];
119
120
  previous_response_id?: string;
120
121
  usage?: ResponsesUsage;
122
+ required_action?: RequiredAction;
121
123
  temperature?: number;
122
124
  top_p?: number;
123
125
  max_output_tokens?: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsonstudio/llms",
3
- "version": "0.4.6",
3
+ "version": "0.6.002",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",