@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.
- package/dist/conversion/codecs/anthropic-openai-codec.js +28 -2
- package/dist/conversion/codecs/gemini-openai-codec.js +23 -0
- package/dist/conversion/codecs/responses-openai-codec.js +8 -1
- package/dist/conversion/hub/node-support.js +14 -1
- package/dist/conversion/hub/pipeline/hub-pipeline.d.ts +66 -0
- package/dist/conversion/hub/pipeline/hub-pipeline.js +284 -193
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage1_format_parse/index.d.ts +11 -0
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage1_format_parse/index.js +6 -0
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage2_semantic_map/index.d.ts +16 -0
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage2_semantic_map/index.js +17 -0
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage3_context_capture/context-factories.d.ts +5 -0
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage3_context_capture/context-factories.js +17 -0
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage3_context_capture/index.d.ts +19 -0
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage3_context_capture/index.js +269 -0
- package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage1_semantic_map/index.d.ts +18 -0
- package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage1_semantic_map/index.js +141 -0
- package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage2_format_build/index.d.ts +11 -0
- package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage2_format_build/index.js +29 -0
- package/dist/conversion/hub/pipeline/stages/req_process/req_process_stage1_tool_governance/index.d.ts +16 -0
- package/dist/conversion/hub/pipeline/stages/req_process/req_process_stage1_tool_governance/index.js +15 -0
- package/dist/conversion/hub/pipeline/stages/req_process/req_process_stage2_route_select/index.d.ts +17 -0
- package/dist/conversion/hub/pipeline/stages/req_process/req_process_stage2_route_select/index.js +18 -0
- package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage1_sse_decode/index.d.ts +17 -0
- package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage1_sse_decode/index.js +63 -0
- package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage2_format_parse/index.d.ts +11 -0
- package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage2_format_parse/index.js +6 -0
- package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage3_semantic_map/index.d.ts +12 -0
- package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage3_semantic_map/index.js +6 -0
- package/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage1_client_remap/index.d.ts +13 -0
- package/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage1_client_remap/index.js +43 -0
- package/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage2_sse_stream/index.d.ts +17 -0
- package/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage2_sse_stream/index.js +22 -0
- package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage1_tool_governance/index.d.ts +16 -0
- package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage1_tool_governance/index.js +19 -0
- package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage2_finalize/index.d.ts +17 -0
- package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage2_finalize/index.js +19 -0
- package/dist/conversion/hub/pipeline/stages/utils.d.ts +2 -0
- package/dist/conversion/hub/pipeline/stages/utils.js +11 -0
- package/dist/conversion/hub/pipeline/target-utils.d.ts +5 -0
- package/dist/conversion/hub/pipeline/target-utils.js +87 -0
- package/dist/conversion/hub/process/chat-process.js +23 -17
- package/dist/conversion/hub/response/provider-response.js +69 -122
- package/dist/conversion/hub/response/response-mappers.d.ts +19 -0
- package/dist/conversion/hub/response/response-mappers.js +22 -2
- package/dist/conversion/hub/response/response-runtime.d.ts +8 -0
- package/dist/conversion/hub/response/response-runtime.js +239 -6
- package/dist/conversion/hub/semantic-mappers/anthropic-mapper.d.ts +8 -0
- package/dist/conversion/hub/semantic-mappers/anthropic-mapper.js +135 -55
- package/dist/conversion/hub/semantic-mappers/chat-mapper.js +80 -40
- package/dist/conversion/hub/semantic-mappers/gemini-mapper.js +5 -29
- package/dist/conversion/hub/semantic-mappers/responses-mapper.js +16 -13
- package/dist/conversion/hub/snapshot-recorder.d.ts +13 -0
- package/dist/conversion/hub/snapshot-recorder.js +90 -50
- package/dist/conversion/hub/standardized-bridge.js +49 -38
- package/dist/conversion/hub/types/chat-envelope.d.ts +68 -0
- package/dist/conversion/hub/types/standardized.d.ts +97 -0
- package/dist/conversion/pipeline/codecs/v2/anthropic-openai-pipeline.js +29 -2
- package/dist/conversion/pipeline/codecs/v2/responses-openai-pipeline.js +68 -1
- package/dist/conversion/responses/responses-openai-bridge.d.ts +6 -1
- package/dist/conversion/responses/responses-openai-bridge.js +132 -10
- package/dist/conversion/shared/anthropic-message-utils.d.ts +9 -1
- package/dist/conversion/shared/anthropic-message-utils.js +414 -26
- package/dist/conversion/shared/bridge-actions.js +267 -95
- package/dist/conversion/shared/bridge-message-utils.js +54 -8
- package/dist/conversion/shared/bridge-policies.js +21 -2
- package/dist/conversion/shared/chat-envelope-validator.d.ts +8 -0
- package/dist/conversion/shared/chat-envelope-validator.js +128 -0
- package/dist/conversion/shared/chat-request-filters.js +109 -28
- package/dist/conversion/shared/mcp-injection.js +41 -20
- package/dist/conversion/shared/openai-finalizer.d.ts +11 -0
- package/dist/conversion/shared/openai-finalizer.js +73 -0
- package/dist/conversion/shared/openai-message-normalize.js +32 -31
- package/dist/conversion/shared/protocol-state.d.ts +4 -0
- package/dist/conversion/shared/protocol-state.js +23 -0
- package/dist/conversion/shared/reasoning-normalizer.d.ts +1 -0
- package/dist/conversion/shared/reasoning-normalizer.js +50 -18
- package/dist/conversion/shared/responses-output-builder.d.ts +1 -1
- package/dist/conversion/shared/responses-output-builder.js +76 -25
- package/dist/conversion/shared/responses-reasoning-registry.d.ts +8 -0
- package/dist/conversion/shared/responses-reasoning-registry.js +61 -0
- package/dist/conversion/shared/responses-response-utils.js +32 -2
- package/dist/conversion/shared/responses-tool-utils.js +28 -2
- package/dist/conversion/shared/snapshot-hooks.d.ts +9 -0
- package/dist/conversion/shared/snapshot-hooks.js +60 -6
- package/dist/conversion/shared/snapshot-utils.d.ts +16 -0
- package/dist/conversion/shared/snapshot-utils.js +84 -0
- package/dist/conversion/shared/tool-filter-pipeline.js +46 -7
- package/dist/conversion/shared/tool-mapping.js +13 -2
- package/dist/filters/index.d.ts +18 -0
- package/dist/filters/index.js +0 -1
- package/dist/filters/special/request-streaming-to-nonstreaming.d.ts +13 -0
- package/dist/filters/special/request-streaming-to-nonstreaming.js +13 -1
- package/dist/filters/special/request-tool-choice-policy.js +3 -1
- package/dist/filters/special/request-tool-list-filter.d.ts +11 -0
- package/dist/filters/special/request-tool-list-filter.js +20 -7
- package/dist/sse/shared/responses-output-normalizer.js +5 -4
- package/dist/sse/sse-to-json/builders/response-builder.js +24 -1
- package/dist/sse/types/responses-types.d.ts +2 -0
- 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
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
|
-
|
|
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
|
-
|
|
22
|
-
|
|
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'
|
|
36
|
-
return candidate
|
|
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';
|
package/dist/filters/index.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
101
|
-
|
|
102
|
-
|
|
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',
|
|
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',
|
|
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
|
-
|
|
17
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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;
|