@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.
- 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 +11 -11
- 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 +119 -59
- package/dist/conversion/hub/semantic-mappers/chat-mapper.js +74 -13
- package/dist/conversion/hub/semantic-mappers/gemini-mapper.js +0 -9
- 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 +44 -30
- 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 -6
- package/dist/conversion/shared/anthropic-message-utils.d.ts +9 -1
- package/dist/conversion/shared/anthropic-message-utils.js +334 -14
- package/dist/conversion/shared/bridge-actions.js +267 -40
- package/dist/conversion/shared/bridge-message-utils.js +54 -8
- package/dist/conversion/shared/bridge-policies.js +29 -4
- 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 +108 -25
- 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/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 +45 -5
- package/dist/conversion/shared/tool-governor.js +5 -0
- package/dist/conversion/shared/tool-mapping.js +13 -2
- 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/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,15 +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
|
-
catch { /* optional */ }
|
|
19
38
|
const { RequestToolCallsStringifyFilter, RequestToolChoicePolicyFilter, RequestStreamingToNonStreamingFilter } = await import('../../filters/index.js');
|
|
20
39
|
engine.registerFilter(new RequestToolCallsStringifyFilter());
|
|
21
|
-
|
|
40
|
+
if (!isAnthropic) {
|
|
41
|
+
engine.registerFilter(new RequestToolChoicePolicyFilter());
|
|
42
|
+
}
|
|
22
43
|
engine.registerFilter(new RequestStreamingToNonStreamingFilter());
|
|
23
44
|
try {
|
|
24
45
|
const cfg = await loadFieldMapConfig('openai-openai.fieldmap.json');
|
|
@@ -33,8 +54,12 @@ export async function runChatRequestToolFilters(chatRequest, options = {}) {
|
|
|
33
54
|
}
|
|
34
55
|
catch { /* ignore */ }
|
|
35
56
|
let staged = await engine.run('request_pre', chatRequest, reqCtxBase);
|
|
57
|
+
recordStage('req_process_tool_filters_request_pre', staged);
|
|
36
58
|
staged = await engine.run('request_map', staged, reqCtxBase);
|
|
59
|
+
recordStage('req_process_tool_filters_request_map', staged);
|
|
37
60
|
staged = await engine.run('request_post', staged, reqCtxBase);
|
|
61
|
+
recordStage('req_process_tool_filters_request_post', staged);
|
|
62
|
+
recordStage('req_process_tool_filters_output', staged);
|
|
38
63
|
return staged;
|
|
39
64
|
}
|
|
40
65
|
export async function runChatResponseToolFilters(chatJson, options = {}) {
|
|
@@ -45,6 +70,17 @@ export async function runChatResponseToolFilters(chatJson, options = {}) {
|
|
|
45
70
|
profile: options.profile || 'openai-chat',
|
|
46
71
|
debug: { emit: () => { } }
|
|
47
72
|
};
|
|
73
|
+
const snapshot = createSnapshotWriter({
|
|
74
|
+
requestId: resCtxBase.requestId,
|
|
75
|
+
endpoint: resCtxBase.endpoint,
|
|
76
|
+
folderHint: 'openai-chat'
|
|
77
|
+
});
|
|
78
|
+
const recordStage = (stage, payload) => {
|
|
79
|
+
if (!snapshot)
|
|
80
|
+
return;
|
|
81
|
+
snapshot(stage, payload);
|
|
82
|
+
};
|
|
83
|
+
recordStage('resp_process_tool_filters_input', chatJson);
|
|
48
84
|
const engine = new FilterEngine();
|
|
49
85
|
const { ResponseToolTextCanonicalizeFilter, ResponseToolArgumentsStringifyFilter, ResponseFinishInvariantsFilter } = await import('../../filters/index.js');
|
|
50
86
|
engine.registerFilter(new ResponseToolTextCanonicalizeFilter());
|
|
@@ -73,7 +109,11 @@ export async function runChatResponseToolFilters(chatJson, options = {}) {
|
|
|
73
109
|
}
|
|
74
110
|
catch { /* ignore */ }
|
|
75
111
|
let staged = await engine.run('response_pre', chatJson, resCtxBase);
|
|
112
|
+
recordStage('resp_process_tool_filters_response_pre', staged);
|
|
76
113
|
staged = await engine.run('response_map', staged, resCtxBase);
|
|
114
|
+
recordStage('resp_process_tool_filters_response_map', staged);
|
|
77
115
|
staged = await engine.run('response_post', staged, resCtxBase);
|
|
116
|
+
recordStage('resp_process_tool_filters_response_post', staged);
|
|
117
|
+
recordStage('resp_process_tool_filters_output', staged);
|
|
78
118
|
return staged;
|
|
79
119
|
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
// Unified tool governance API (标准)
|
|
2
2
|
// Centralizes tool augmentation, guidance injection/refinement, and textual→tool_calls canonicalization
|
|
3
|
+
// canonicalizer 按需加载(避免在请求侧仅注入时引入不必要的模块)
|
|
4
|
+
// enforceChatBudget: 为避免在请求侧引入多余依赖,这里提供最小实现(保留形状,不裁剪)。
|
|
5
|
+
import { augmentOpenAITools } from '../../guidance/index.js';
|
|
3
6
|
function isObject(v) { return !!v && typeof v === 'object' && !Array.isArray(v); }
|
|
4
7
|
// Note: tool schema strict augmentation removed per alignment
|
|
5
8
|
function enforceChatBudget(chat, _modelId) { return chat; }
|
|
@@ -63,6 +66,8 @@ export function processChatRequestTools(request, opts) {
|
|
|
63
66
|
t.function = { ...fn, parameters: {} };
|
|
64
67
|
}
|
|
65
68
|
}
|
|
69
|
+
// 严格化工具 schema(apply_patch/shell/MCP 等)保持在唯一治理点,避免重复注入
|
|
70
|
+
out.tools = augmentOpenAITools(tools);
|
|
66
71
|
}
|
|
67
72
|
}
|
|
68
73
|
catch { /* best-effort: 保持原样 */ }
|
|
@@ -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) {
|
|
@@ -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
|
}
|