@jsonstudio/llms 0.6.3275 → 0.6.3405
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/bridge-message-utils.d.ts +4 -4
- package/dist/conversion/bridge-message-utils.js +28 -538
- package/dist/conversion/compat/actions/claude-thinking-tools.d.ts +1 -14
- package/dist/conversion/compat/actions/claude-thinking-tools.js +3 -71
- package/dist/conversion/compat/actions/lmstudio-responses-fc-ids.d.ts +0 -8
- package/dist/conversion/compat/actions/lmstudio-responses-fc-ids.js +2 -57
- package/dist/conversion/compat/actions/normalize-tool-call-ids.d.ts +0 -9
- package/dist/conversion/compat/actions/normalize-tool-call-ids.js +6 -136
- package/dist/conversion/compat/actions/request-rules.js +2 -61
- package/dist/conversion/compat/actions/response-blacklist.d.ts +0 -4
- package/dist/conversion/compat/actions/response-blacklist.js +2 -77
- package/dist/conversion/compat/actions/response-normalize.js +2 -119
- package/dist/conversion/compat/actions/response-validate.js +2 -74
- package/dist/conversion/compat/actions/strip-orphan-function-calls-tag.js +2 -150
- package/dist/conversion/compat/profiles/responses-crs.json +15 -0
- package/dist/conversion/hub/operation-table/semantic-mappers/anthropic-mapper.js +24 -1
- package/dist/conversion/hub/operation-table/semantic-mappers/chat-mapper.js +16 -5
- package/dist/conversion/hub/pipeline/hub-pipeline.js +91 -0
- package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage1_tool_governance/index.js +1 -6
- package/dist/conversion/hub/response/response-runtime.js +14 -6
- package/dist/conversion/responses/responses-openai-bridge/response-payload.js +11 -11
- package/dist/conversion/shared/anthropic-message-utils.js +2 -12
- package/dist/conversion/shared/chat-request-filters.js +2 -61
- package/dist/conversion/shared/reasoning-mapping.js +3 -0
- package/dist/conversion/shared/reasoning-normalizer.d.ts +1 -0
- package/dist/conversion/shared/reasoning-normalizer.js +35 -388
- package/dist/conversion/shared/reasoning-tool-normalizer.js +8 -15
- package/dist/conversion/shared/reasoning-tool-parser.js +7 -8
- package/dist/conversion/shared/reasoning-utils.js +13 -35
- package/dist/conversion/shared/responses-response-utils.js +3 -48
- package/dist/conversion/shared/responses-tool-utils.d.ts +1 -1
- package/dist/conversion/shared/responses-tool-utils.js +74 -180
- package/dist/conversion/shared/streaming-text-extractor.d.ts +0 -5
- package/dist/conversion/shared/streaming-text-extractor.js +18 -111
- package/dist/conversion/shared/text-markup-normalizer/normalize.d.ts +1 -1
- package/dist/conversion/shared/text-markup-normalizer/normalize.js +3 -91
- package/dist/conversion/shared/thought-signature-validator.js +19 -133
- package/dist/conversion/shared/tool-argument-repairer.js +16 -19
- package/dist/conversion/shared/tool-call-id-manager.d.ts +1 -5
- package/dist/conversion/shared/tool-call-id-manager.js +74 -98
- package/dist/conversion/shared/tool-harvester.js +19 -382
- package/dist/conversion/shared/tool-mapping.d.ts +2 -3
- package/dist/conversion/shared/tool-mapping.js +28 -184
- package/dist/conversion/shared/tooling.js +20 -151
- package/dist/filters/special/response-tool-arguments-stringify.js +9 -1
- package/dist/guidance/index.js +2 -2
- package/dist/native/router_hotpath_napi.node +0 -0
- package/dist/router/virtual-router/bootstrap/web-search-config.js +25 -0
- package/dist/router/virtual-router/bootstrap.js +21 -16
- package/dist/router/virtual-router/engine-legacy/helpers.js +1 -1
- package/dist/router/virtual-router/engine-selection/native-compat-action-semantics.d.ts +6 -0
- package/dist/router/virtual-router/engine-selection/native-compat-action-semantics.js +171 -0
- package/dist/router/virtual-router/engine-selection/native-hub-bridge-action-semantics.d.ts +39 -0
- package/dist/router/virtual-router/engine-selection/native-hub-bridge-action-semantics.js +196 -0
- package/dist/router/virtual-router/engine-selection/native-hub-pipeline-req-inbound-semantics.d.ts +1 -0
- package/dist/router/virtual-router/engine-selection/native-hub-pipeline-req-inbound-semantics.js +27 -0
- package/dist/router/virtual-router/engine-selection/native-router-hotpath-loader.js +45 -0
- package/dist/router/virtual-router/engine-selection/native-shared-conversion-semantics.d.ts +70 -1
- package/dist/router/virtual-router/engine-selection/native-shared-conversion-semantics.js +993 -55
- package/dist/router/virtual-router/engine.js +3 -2
- package/dist/router/virtual-router/routing-instructions/parse.js +30 -3
- package/dist/router/virtual-router/types.d.ts +23 -0
- package/dist/servertool/handlers/web-search.js +26 -1
- package/dist/servertool/server-side-tools.js +11 -2
- package/dist/servertool/types.d.ts +4 -0
- package/dist/sse/sse-to-json/builders/anthropic-response-builder.js +28 -3
- package/dist/sse/types/anthropic-types.d.ts +3 -1
- package/dist/tools/apply-patch/args-normalizer/extract-patch.js +2 -2
- package/dist/tools/apply-patch/patch-text/looks-like-patch.js +3 -6
- package/dist/tools/apply-patch/patch-text/normalize.js +14 -3
- package/dist/tools/tool-registry.js +12 -0
- package/package.json +6 -1
|
@@ -4,6 +4,7 @@ import { parseRoutingInstructions } from './routing-instructions/parse.js';
|
|
|
4
4
|
import { createVirtualRouterEngineProxy } from './engine-selection/native-virtual-router-engine-proxy.js';
|
|
5
5
|
import { cleanRoutingInstructionMarkersWithNative, parseRoutingInstructionKindsWithNative } from './engine-selection/native-virtual-router-routing-instructions-semantics.js';
|
|
6
6
|
import { getLatestUserTextFromResponsesContext, hasLatestUserRoutingInstructionMarker, hasRoutingInstructionMarkerInResponsesContext } from './engine-legacy/helpers.js';
|
|
7
|
+
import { extractMessageText, getLatestUserMessage } from './message-utils.js';
|
|
7
8
|
import { ProviderRegistry } from './provider-registry.js';
|
|
8
9
|
import { resolveStopMessageScope } from './engine/routing-state/store.js';
|
|
9
10
|
import { loadRoutingInstructionStateSync } from './sticky-session-store.js';
|
|
@@ -225,8 +226,8 @@ function buildRoutingInstructionParseLog(request, metadata) {
|
|
|
225
226
|
if (!messages.length) {
|
|
226
227
|
return null;
|
|
227
228
|
}
|
|
228
|
-
const latest = messages
|
|
229
|
-
const latestText =
|
|
229
|
+
const latest = getLatestUserMessage(messages);
|
|
230
|
+
const latestText = latest ? extractMessageText(latest).trim() : '';
|
|
230
231
|
const parsedKinds = parseRoutingInstructionKindsWithNative(request);
|
|
231
232
|
const stopMessageTypes = parsedKinds.filter((type) => type === 'stopMessageSet' || type === 'stopMessageMode' || type === 'stopMessageClear');
|
|
232
233
|
const scopedTypes = parsedKinds.filter((type) => type === 'stopMessageSet' ||
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { extractMessageText } from '../message-utils.js';
|
|
1
|
+
import { extractMessageText, getLatestUserMessage } from '../message-utils.js';
|
|
2
2
|
import { parseStopMessageInstruction } from '../routing-stop-message-parser.js';
|
|
3
3
|
import { parsePreCommandInstruction } from '../routing-pre-command-parser.js';
|
|
4
4
|
import { stripCodeSegments } from './clean.js';
|
|
@@ -6,8 +6,8 @@ import { ROUTING_INSTRUCTION_MARKER_PATTERN } from './types.js';
|
|
|
6
6
|
export function parseRoutingInstructions(messages) {
|
|
7
7
|
const instructions = [];
|
|
8
8
|
// 只解析“当前最新一条消息”中的 marker,避免历史 user marker 在后续轮次被重复回放。
|
|
9
|
-
const latestMessage = messages
|
|
10
|
-
if (!latestMessage
|
|
9
|
+
const latestMessage = getLatestUserMessage(messages);
|
|
10
|
+
if (!latestMessage) {
|
|
11
11
|
return instructions;
|
|
12
12
|
}
|
|
13
13
|
const content = extractMessageText(latestMessage);
|
|
@@ -87,6 +87,10 @@ function expandInstructionSegments(instruction) {
|
|
|
87
87
|
if (/^precommand(?:\s*:|$)/i.test(normalizedLeading)) {
|
|
88
88
|
return [normalizedLeading];
|
|
89
89
|
}
|
|
90
|
+
const quotedStopMessage = normalizeQuotedStopMessageShorthand(normalizedLeading);
|
|
91
|
+
if (quotedStopMessage) {
|
|
92
|
+
return [normalizeStopMessageCommandPrefix(quotedStopMessage)];
|
|
93
|
+
}
|
|
90
94
|
const prefix = trimmed[0];
|
|
91
95
|
if (prefix === '!' || prefix === '#' || prefix === '@') {
|
|
92
96
|
const tokens = splitInstructionTargets(trimmed.substring(1));
|
|
@@ -121,6 +125,29 @@ function normalizeSplitStopMessageHeadToken(token) {
|
|
|
121
125
|
.replace(/^["']+|["']+$/g, '')
|
|
122
126
|
.trim();
|
|
123
127
|
}
|
|
128
|
+
function normalizeQuotedStopMessageShorthand(content) {
|
|
129
|
+
const normalized = normalizeInstructionLeading(content);
|
|
130
|
+
const quote = normalized[0];
|
|
131
|
+
if (quote !== '"' && quote !== "'") {
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
let escaped = false;
|
|
135
|
+
for (let idx = 1; idx < normalized.length; idx += 1) {
|
|
136
|
+
const ch = normalized[idx];
|
|
137
|
+
if (escaped) {
|
|
138
|
+
escaped = false;
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if (ch === '\\') {
|
|
142
|
+
escaped = true;
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
if (ch === quote) {
|
|
146
|
+
return `stopMessage:${normalized}`;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
124
151
|
function recoverSplitStopMessageInstruction(tokens) {
|
|
125
152
|
if (!Array.isArray(tokens) || tokens.length < 2) {
|
|
126
153
|
return null;
|
|
@@ -215,11 +215,34 @@ export interface ProviderHealthConfig {
|
|
|
215
215
|
cooldownMs: number;
|
|
216
216
|
fatalCooldownMs?: number;
|
|
217
217
|
}
|
|
218
|
+
export type VirtualRouterWebSearchExecutionMode = 'servertool' | 'direct';
|
|
219
|
+
export type VirtualRouterWebSearchDirectActivation = 'route' | 'builtin';
|
|
218
220
|
export interface VirtualRouterWebSearchEngineConfig {
|
|
219
221
|
id: string;
|
|
220
222
|
providerKey: string;
|
|
221
223
|
description?: string;
|
|
222
224
|
default?: boolean;
|
|
225
|
+
/**
|
|
226
|
+
* Search execution mode:
|
|
227
|
+
* - servertool: expose canonical web_search tool and execute through servertool engine.
|
|
228
|
+
* - direct: route to a search-capable model/provider directly; servertool injection must skip it.
|
|
229
|
+
*/
|
|
230
|
+
executionMode?: VirtualRouterWebSearchExecutionMode;
|
|
231
|
+
/**
|
|
232
|
+
* When executionMode=direct, controls how the upstream search capability is activated.
|
|
233
|
+
* - route: route selection itself enables native search behavior (e.g. deepseek-web search route).
|
|
234
|
+
* - builtin: upstream requires a provider-native builtin search tool/schema.
|
|
235
|
+
*/
|
|
236
|
+
directActivation?: VirtualRouterWebSearchDirectActivation;
|
|
237
|
+
/**
|
|
238
|
+
* Optional target model id for direct-mode matching when request/compat layers need to detect
|
|
239
|
+
* which routed provider payload should receive native web search activation.
|
|
240
|
+
*/
|
|
241
|
+
modelId?: string;
|
|
242
|
+
/**
|
|
243
|
+
* Optional builtin max-uses hint for providers that support builtin web search tools.
|
|
244
|
+
*/
|
|
245
|
+
maxUses?: number;
|
|
223
246
|
/**
|
|
224
247
|
* When true, this engine will never be used by server-side tools
|
|
225
248
|
* (e.g. web_search). It will also be omitted from injected tool
|
|
@@ -118,6 +118,27 @@ function getWebSearchConfig(ctx) {
|
|
|
118
118
|
: undefined;
|
|
119
119
|
if (!id || !providerKey)
|
|
120
120
|
continue;
|
|
121
|
+
const rawExecutionMode = typeof obj.executionMode === 'string'
|
|
122
|
+
? obj.executionMode.trim().toLowerCase()
|
|
123
|
+
: typeof obj.mode === 'string'
|
|
124
|
+
? obj.mode.trim().toLowerCase()
|
|
125
|
+
: '';
|
|
126
|
+
const executionMode = rawExecutionMode === 'direct' ? 'direct' : 'servertool';
|
|
127
|
+
const rawDirectActivation = typeof obj.directActivation === 'string'
|
|
128
|
+
? obj.directActivation.trim().toLowerCase()
|
|
129
|
+
: typeof obj.activation === 'string'
|
|
130
|
+
? obj.activation.trim().toLowerCase()
|
|
131
|
+
: '';
|
|
132
|
+
const directActivation = rawDirectActivation === 'builtin'
|
|
133
|
+
? 'builtin'
|
|
134
|
+
: rawDirectActivation === 'route'
|
|
135
|
+
? 'route'
|
|
136
|
+
: executionMode === 'direct'
|
|
137
|
+
? 'route'
|
|
138
|
+
: undefined;
|
|
139
|
+
const modelId = typeof obj.modelId === 'string' && obj.modelId.trim() ? obj.modelId.trim() : undefined;
|
|
140
|
+
const rawMaxUses = typeof obj.maxUses === 'number' ? obj.maxUses : Number(obj.maxUses);
|
|
141
|
+
const maxUses = Number.isFinite(rawMaxUses) && rawMaxUses > 0 ? Math.floor(rawMaxUses) : undefined;
|
|
121
142
|
const serverToolsDisabled = obj.serverToolsDisabled === true ||
|
|
122
143
|
(typeof obj.serverToolsDisabled === 'string' &&
|
|
123
144
|
obj.serverToolsDisabled.trim().toLowerCase() === 'true') ||
|
|
@@ -142,6 +163,10 @@ function getWebSearchConfig(ctx) {
|
|
|
142
163
|
providerKey,
|
|
143
164
|
description: typeof obj.description === 'string' && obj.description.trim() ? obj.description.trim() : undefined,
|
|
144
165
|
default: obj.default === true,
|
|
166
|
+
executionMode,
|
|
167
|
+
...(directActivation ? { directActivation } : {}),
|
|
168
|
+
...(modelId ? { modelId } : {}),
|
|
169
|
+
...(maxUses ? { maxUses } : {}),
|
|
145
170
|
...(serverToolsDisabled ? { serverToolsDisabled: true } : {}),
|
|
146
171
|
...(searchEngineList ? { searchEngineList } : {})
|
|
147
172
|
});
|
|
@@ -181,7 +206,7 @@ function resolveWebSearchEngine(config, engineId) {
|
|
|
181
206
|
return undefined;
|
|
182
207
|
}
|
|
183
208
|
function buildEnginePriorityList(config, engineId) {
|
|
184
|
-
const engines = (Array.isArray(config.engines) ? config.engines : []).filter((engine) => !engine.serverToolsDisabled);
|
|
209
|
+
const engines = (Array.isArray(config.engines) ? config.engines : []).filter((engine) => !engine.serverToolsDisabled && (engine.executionMode ?? 'servertool') === 'servertool');
|
|
185
210
|
if (!engines.length) {
|
|
186
211
|
return [];
|
|
187
212
|
}
|
|
@@ -100,7 +100,7 @@ function normalizeFilterTokenSet(values) {
|
|
|
100
100
|
return normalized.size > 0 ? normalized : null;
|
|
101
101
|
}
|
|
102
102
|
function isNameIncluded(name, includeSet, excludeSet) {
|
|
103
|
-
const normalized = name
|
|
103
|
+
const normalized = normalizeServerToolCallName(name);
|
|
104
104
|
if (includeSet && !includeSet.has(normalized)) {
|
|
105
105
|
return false;
|
|
106
106
|
}
|
|
@@ -109,6 +109,13 @@ function isNameIncluded(name, includeSet, excludeSet) {
|
|
|
109
109
|
}
|
|
110
110
|
return true;
|
|
111
111
|
}
|
|
112
|
+
function normalizeServerToolCallName(name) {
|
|
113
|
+
const normalized = name.trim().toLowerCase();
|
|
114
|
+
if (normalized === 'websearch' || normalized === 'web-search') {
|
|
115
|
+
return 'web_search';
|
|
116
|
+
}
|
|
117
|
+
return normalized;
|
|
118
|
+
}
|
|
112
119
|
function extractToolCallsFromMessage(message) {
|
|
113
120
|
const toolCalls = getArray(message.tool_calls);
|
|
114
121
|
const out = [];
|
|
@@ -120,7 +127,9 @@ function extractToolCallsFromMessage(message) {
|
|
|
120
127
|
const fn = asObject(tc.function) ??
|
|
121
128
|
asObject(tc.functionCall) ??
|
|
122
129
|
asObject(tc.function_call);
|
|
123
|
-
const name = fn && typeof fn.name === 'string' && String(fn.name).trim()
|
|
130
|
+
const name = fn && typeof fn.name === 'string' && String(fn.name).trim()
|
|
131
|
+
? normalizeServerToolCallName(String(fn.name))
|
|
132
|
+
: '';
|
|
124
133
|
const rawArgs = (fn ? fn.arguments : undefined) ??
|
|
125
134
|
(fn ? fn.args : undefined) ??
|
|
126
135
|
(fn ? fn.input : undefined) ??
|
|
@@ -137,6 +137,10 @@ export type ServerToolBackendPlan = {
|
|
|
137
137
|
providerKey: string;
|
|
138
138
|
description?: string;
|
|
139
139
|
default?: boolean;
|
|
140
|
+
executionMode?: 'servertool' | 'direct';
|
|
141
|
+
directActivation?: 'route' | 'builtin';
|
|
142
|
+
modelId?: string;
|
|
143
|
+
maxUses?: number;
|
|
140
144
|
serverToolsDisabled?: boolean;
|
|
141
145
|
searchEngineList?: string[];
|
|
142
146
|
}[];
|
|
@@ -1,4 +1,23 @@
|
|
|
1
1
|
import { dispatchReasoning } from '../../shared/reasoning-dispatcher.js';
|
|
2
|
+
function mergeAnthropicUsage(current, incoming) {
|
|
3
|
+
if (!incoming || typeof incoming !== 'object') {
|
|
4
|
+
return current;
|
|
5
|
+
}
|
|
6
|
+
const incomingRecord = incoming;
|
|
7
|
+
const base = current && typeof current === 'object' ? { ...current } : {};
|
|
8
|
+
for (const [key, value] of Object.entries(incomingRecord)) {
|
|
9
|
+
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
10
|
+
const prev = base[key];
|
|
11
|
+
base[key] = {
|
|
12
|
+
...(prev && typeof prev === 'object' && !Array.isArray(prev) ? prev : {}),
|
|
13
|
+
...value
|
|
14
|
+
};
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
base[key] = value;
|
|
18
|
+
}
|
|
19
|
+
return base;
|
|
20
|
+
}
|
|
2
21
|
export function createAnthropicResponseBuilder(options) {
|
|
3
22
|
const state = {
|
|
4
23
|
content: [],
|
|
@@ -58,6 +77,7 @@ export function createAnthropicResponseBuilder(options) {
|
|
|
58
77
|
state.id = payload.id || state.id;
|
|
59
78
|
state.model = payload.model || state.model;
|
|
60
79
|
state.role = payload.role || state.role;
|
|
80
|
+
state.usage = mergeAnthropicUsage(state.usage, payload.usage);
|
|
61
81
|
}
|
|
62
82
|
break;
|
|
63
83
|
}
|
|
@@ -116,11 +136,14 @@ export function createAnthropicResponseBuilder(options) {
|
|
|
116
136
|
if (delta?.stop_reason) {
|
|
117
137
|
state.stopReason = delta.stop_reason;
|
|
118
138
|
}
|
|
139
|
+
if (typeof delta?.stop_sequence === 'string' || delta?.stop_sequence === null) {
|
|
140
|
+
state.stopSequence = delta.stop_sequence;
|
|
141
|
+
}
|
|
119
142
|
// 部分实现将 usage 挂在 delta.usage,部分实现挂在顶层 event.data.usage,
|
|
120
143
|
// 这里统一优先读取 delta.usage,缺失时回退到 data.usage。
|
|
121
144
|
const usageNode = (delta && delta.usage) ?? data.usage;
|
|
122
145
|
if (usageNode) {
|
|
123
|
-
state.usage = usageNode;
|
|
146
|
+
state.usage = mergeAnthropicUsage(state.usage, usageNode);
|
|
124
147
|
}
|
|
125
148
|
break;
|
|
126
149
|
}
|
|
@@ -151,7 +174,8 @@ export function createAnthropicResponseBuilder(options) {
|
|
|
151
174
|
model: state.model || 'unknown',
|
|
152
175
|
content: state.content,
|
|
153
176
|
usage: state.usage,
|
|
154
|
-
stop_reason: state.stopReason ?? 'end_turn'
|
|
177
|
+
stop_reason: state.stopReason ?? 'end_turn',
|
|
178
|
+
stop_sequence: state.stopSequence
|
|
155
179
|
}
|
|
156
180
|
};
|
|
157
181
|
}
|
|
@@ -166,7 +190,8 @@ export function createAnthropicResponseBuilder(options) {
|
|
|
166
190
|
model: state.model || 'unknown',
|
|
167
191
|
content: state.content,
|
|
168
192
|
usage: state.usage,
|
|
169
|
-
stop_reason: state.stopReason ?? 'end_turn'
|
|
193
|
+
stop_reason: state.stopReason ?? 'end_turn',
|
|
194
|
+
stop_sequence: state.stopSequence
|
|
170
195
|
}
|
|
171
196
|
};
|
|
172
197
|
}
|
|
@@ -30,11 +30,12 @@ export interface AnthropicMessageResponse {
|
|
|
30
30
|
role: 'assistant' | 'user';
|
|
31
31
|
model: string;
|
|
32
32
|
content: AnthropicContentBlock[];
|
|
33
|
-
usage?: {
|
|
33
|
+
usage?: Record<string, unknown> & {
|
|
34
34
|
input_tokens?: number;
|
|
35
35
|
output_tokens?: number;
|
|
36
36
|
};
|
|
37
37
|
stop_reason?: 'end_turn' | 'max_tokens' | 'stop_sequence' | 'tool_use';
|
|
38
|
+
stop_sequence?: string | null;
|
|
38
39
|
}
|
|
39
40
|
export interface AnthropicEventStats {
|
|
40
41
|
totalEvents: number;
|
|
@@ -157,6 +158,7 @@ export interface AnthropicSseEventMessageDelta extends AnthropicSseEventBase<'me
|
|
|
157
158
|
type: 'message_delta';
|
|
158
159
|
delta?: {
|
|
159
160
|
stop_reason?: AnthropicMessageResponse['stop_reason'];
|
|
161
|
+
stop_sequence?: string | null;
|
|
160
162
|
usage?: AnthropicMessageResponse['usage'];
|
|
161
163
|
};
|
|
162
164
|
};
|
|
@@ -4,11 +4,11 @@ export function extractNormalizedPatch(value) {
|
|
|
4
4
|
return {};
|
|
5
5
|
}
|
|
6
6
|
const normalized = normalizeApplyPatchText(value);
|
|
7
|
-
const patchLike = looksLikePatch(value) || looksLikePatch(normalized)
|
|
7
|
+
const patchLike = looksLikePatch(value) || looksLikePatch(normalized);
|
|
8
8
|
if (!patchLike) {
|
|
9
9
|
return {};
|
|
10
10
|
}
|
|
11
|
-
if (
|
|
11
|
+
if (!/^(?:\s*)\*\*\*\s*Begin Patch\b/m.test(normalized)) {
|
|
12
12
|
return { failureReason: 'unsupported_patch_format' };
|
|
13
13
|
}
|
|
14
14
|
return { patchText: normalized };
|
|
@@ -4,11 +4,8 @@ export const looksLikePatch = (text) => {
|
|
|
4
4
|
const t = text.trim();
|
|
5
5
|
if (!t)
|
|
6
6
|
return false;
|
|
7
|
-
return (
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
t.includes('*** Create File:') ||
|
|
11
|
-
t.includes('*** Delete File:') ||
|
|
12
|
-
t.includes('diff --git') ||
|
|
7
|
+
return (/^(?:\s*)\*\*\*\s*Begin Patch\b/m.test(t) ||
|
|
8
|
+
/^(?:\s*)\*\*\*\s*(?:Update|Add|Create|Delete)\s+File:/m.test(t) ||
|
|
9
|
+
/^diff --git\s/m.test(t) ||
|
|
13
10
|
/^(?:@@|\+\+\+\s|---\s)/m.test(t));
|
|
14
11
|
};
|
|
@@ -109,18 +109,29 @@ const convertStarHeaderDiffToApplyPatchIfPossible = (text) => {
|
|
|
109
109
|
return null;
|
|
110
110
|
}
|
|
111
111
|
};
|
|
112
|
+
const normalizeApplyPatchHeaderPath = (raw) => {
|
|
113
|
+
let out = String(raw ?? '').trim();
|
|
114
|
+
if (!out)
|
|
115
|
+
return out;
|
|
116
|
+
if ((out.startsWith('"') && out.endsWith('"')) ||
|
|
117
|
+
(out.startsWith("'") && out.endsWith("'")) ||
|
|
118
|
+
(out.startsWith('`') && out.endsWith('`'))) {
|
|
119
|
+
out = out.slice(1, -1).trim();
|
|
120
|
+
}
|
|
121
|
+
return out;
|
|
122
|
+
};
|
|
112
123
|
const normalizeApplyPatchFileHeader = (line) => {
|
|
113
124
|
const addMatch = line.match(/^\*\*\* Add File:\s*(.+?)(?:\s+\*\*\*)?\s*$/);
|
|
114
125
|
if (addMatch && addMatch[1]) {
|
|
115
|
-
return `*** Add File: ${addMatch[1]
|
|
126
|
+
return `*** Add File: ${normalizeApplyPatchHeaderPath(addMatch[1])}`;
|
|
116
127
|
}
|
|
117
128
|
const updateMatch = line.match(/^\*\*\* Update File:\s*(.+?)(?:\s+\*\*\*)?\s*$/);
|
|
118
129
|
if (updateMatch && updateMatch[1]) {
|
|
119
|
-
return `*** Update File: ${updateMatch[1]
|
|
130
|
+
return `*** Update File: ${normalizeApplyPatchHeaderPath(updateMatch[1])}`;
|
|
120
131
|
}
|
|
121
132
|
const deleteMatch = line.match(/^\*\*\* Delete File:\s*(.+?)(?:\s+\*\*\*)?\s*$/);
|
|
122
133
|
if (deleteMatch && deleteMatch[1]) {
|
|
123
|
-
return `*** Delete File: ${deleteMatch[1]
|
|
134
|
+
return `*** Delete File: ${normalizeApplyPatchHeaderPath(deleteMatch[1])}`;
|
|
124
135
|
}
|
|
125
136
|
return line;
|
|
126
137
|
};
|
|
@@ -72,6 +72,8 @@ const isImagePath = (value) => {
|
|
|
72
72
|
export function getAllowedToolNames() {
|
|
73
73
|
return [
|
|
74
74
|
'shell',
|
|
75
|
+
'shell_command',
|
|
76
|
+
'bash',
|
|
75
77
|
'exec_command',
|
|
76
78
|
'apply_patch',
|
|
77
79
|
'update_plan',
|
|
@@ -108,6 +110,16 @@ export function validateToolCall(name, argsString, options) {
|
|
|
108
110
|
}
|
|
109
111
|
return { ok: true, normalizedArgs: validation.normalizedArgs };
|
|
110
112
|
}
|
|
113
|
+
case 'shell_command':
|
|
114
|
+
case 'bash': {
|
|
115
|
+
const rawArgs = isRecord(rawArgsAny) ? rawArgsAny : {};
|
|
116
|
+
const command = asString(rawArgs.command) ??
|
|
117
|
+
asString(rawArgs.cmd);
|
|
118
|
+
if (!command) {
|
|
119
|
+
return { ok: false, reason: 'missing_command' };
|
|
120
|
+
}
|
|
121
|
+
return { ok: true, normalizedArgs: toJson(rawArgs) };
|
|
122
|
+
}
|
|
111
123
|
case 'apply_patch': {
|
|
112
124
|
const validation = validateApplyPatchArgs(argsString, rawArgsAny);
|
|
113
125
|
if (!validation.ok) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsonstudio/llms",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.3405",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -78,6 +78,7 @@
|
|
|
78
78
|
"test:coverage:hub-resp-outbound-client-remap-switch": "npm run build:ci && node ./node_modules/c8/bin/c8.js --reporter=json-summary --reporter=text --report-dir=coverage/module-hub-resp-outbound-client-remap-switch --include=dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage1_client_remap/client-remap-protocol-switch.js --exclude=scripts/** node scripts/tests/coverage-hub-resp-outbound-client-remap-protocol-switch.mjs",
|
|
79
79
|
"test:coverage:virtual-router-tier-antigravity-session-lease": "npm run build:ci && node ./node_modules/c8/bin/c8.js --reporter=json-summary --reporter=text --report-dir=coverage/module-virtual-router-tier-antigravity-session-lease --include=dist/router/virtual-router/engine-selection/tier-selection-antigravity-session-lease.js --exclude=scripts/** node scripts/tests/coverage-virtual-router-tier-antigravity-session-lease.mjs",
|
|
80
80
|
"test:coverage:virtual-router-tier-antigravity-target-split": "npm run build:ci && node ./node_modules/c8/bin/c8.js --reporter=json-summary --reporter=text --report-dir=coverage/module-virtual-router-tier-antigravity-target-split --include=dist/router/virtual-router/engine-selection/tier-selection-antigravity-target-split.js --exclude=scripts/** node scripts/tests/coverage-virtual-router-tier-antigravity-target-split.mjs",
|
|
81
|
+
"test:coverage:text-markup-normalizer": "npm run build:ci && C8_COVERAGE=1 node ./node_modules/c8/bin/c8.js --lines 95 --branches 95 --functions 95 --statements 95 --reporter=json-summary --reporter=text --report-dir=coverage/module-text-markup-normalizer --include=dist/conversion/shared/text-markup-normalizer.js --exclude=**/node_modules/** node scripts/tests/coverage-text-markup-normalizer.mjs",
|
|
81
82
|
"test:coverage": "node scripts/run-ci-coverage.mjs",
|
|
82
83
|
"verify:module-blackbox": "node scripts/tests/module-blackbox-gate.mjs",
|
|
83
84
|
"verify:shadow-gate": "node scripts/check-shadow-coverage-gate.mjs",
|
|
@@ -141,6 +142,7 @@
|
|
|
141
142
|
"verify:shadow-gate:hub-resp-outbound-sse-stream": "npm run test:coverage:hub-resp-outbound-sse-stream && node scripts/check-shadow-coverage-gate.mjs --summary coverage/module-hub-resp-outbound-sse-stream/coverage-summary.json --module hub.resp-outbound.sse-stream && node scripts/promote-shadow-module.mjs --module hub.resp-outbound.sse-stream",
|
|
142
143
|
"verify:shadow-gate:hub-native-batch": "npm run test:coverage:hub-native-batch && node scripts/check-shadow-coverage-gate.mjs --summary coverage/module-hub-native-batch/coverage-summary.json --module hub.native-batch.adapters-snapshot-governance && node scripts/promote-shadow-module.mjs --module hub.native-batch.adapters-snapshot-governance",
|
|
143
144
|
"test:coverage:hub-chat-request-filters": "npm run build:ci && node ./node_modules/c8/bin/c8.js --reporter=json-summary --reporter=text --report-dir=coverage/module-hub-chat-request-filters --include=dist/conversion/shared/chat-request-filters.js --include=dist/router/virtual-router/engine-selection/native-chat-request-filter-semantics.js --exclude=scripts/** node scripts/tests/coverage-chat-request-filters.mjs",
|
|
145
|
+
"test:coverage:router-hotpath-napi": "cd rust-core && cargo llvm-cov -p router-hotpath-napi --summary-only --json --output-path /tmp/router-hotpath-napi-cov.json && node -e \"const fs=require('fs');const data=JSON.parse(fs.readFileSync('/tmp/router-hotpath-napi-cov.json','utf8'));const files=(data.data&&data.data[0]&&data.data[0].files)||[];const target=files.find(f=>String(f.filename||'').endsWith('resp_process_stage1_tool_governance.rs'));if(!target){console.error('missing resp_process_stage1_tool_governance.rs in coverage');process.exit(1);}const sum=target.summary||{};const lines=sum.lines?sum.lines.percent:0;const funcs=sum.functions?sum.functions.percent:0;const regions=sum.regions?sum.regions.percent:0;const branches=sum.branches?sum.branches.percent:'n/a';const statements=sum.statements?sum.statements.percent:'n/a';console.log('[coverage router-hotpath-napi] lines',lines,'functions',funcs,'regions',regions,'branches',branches,'statements',statements);const min=95;if(lines<min||funcs<min||regions<min){process.exit(1);}\"",
|
|
144
146
|
"verify:shadow-gate:hub-chat-request-filters": "npm run test:coverage:hub-chat-request-filters && node scripts/check-shadow-coverage-gate.mjs --summary coverage/module-hub-chat-request-filters/coverage-summary.json --module hub.shared.chat-request-filters && node scripts/promote-shadow-module.mjs --module hub.shared.chat-request-filters"
|
|
145
147
|
},
|
|
146
148
|
"dependencies": {
|
|
@@ -167,11 +169,14 @@
|
|
|
167
169
|
}
|
|
168
170
|
},
|
|
169
171
|
"devDependencies": {
|
|
172
|
+
"@types/jest": "^29.5.14",
|
|
170
173
|
"@types/node": "^20.11.25",
|
|
171
174
|
"@typescript-eslint/eslint-plugin": "^8.56.1",
|
|
172
175
|
"@typescript-eslint/parser": "^8.56.1",
|
|
173
176
|
"c8": "^11.0.0",
|
|
174
177
|
"eslint": "^8.50.0",
|
|
178
|
+
"jest": "^29.7.0",
|
|
179
|
+
"ts-jest": "^29.2.6",
|
|
175
180
|
"tsx": "^4.21.0",
|
|
176
181
|
"typescript": "^5.4.0"
|
|
177
182
|
},
|