@jsonstudio/llms 0.6.3275 → 0.6.3379

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 (48) hide show
  1. package/dist/conversion/bridge-message-utils.d.ts +4 -4
  2. package/dist/conversion/bridge-message-utils.js +28 -538
  3. package/dist/conversion/compat/profiles/responses-crs.json +15 -0
  4. package/dist/conversion/hub/operation-table/semantic-mappers/chat-mapper.js +16 -5
  5. package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage1_tool_governance/index.js +1 -6
  6. package/dist/conversion/hub/response/response-runtime.js +14 -6
  7. package/dist/conversion/responses/responses-openai-bridge/response-payload.js +11 -11
  8. package/dist/conversion/shared/anthropic-message-utils.js +2 -12
  9. package/dist/conversion/shared/chat-request-filters.js +2 -61
  10. package/dist/conversion/shared/reasoning-mapping.js +3 -0
  11. package/dist/conversion/shared/reasoning-normalizer.d.ts +1 -0
  12. package/dist/conversion/shared/reasoning-normalizer.js +35 -388
  13. package/dist/conversion/shared/reasoning-tool-normalizer.js +8 -15
  14. package/dist/conversion/shared/reasoning-utils.js +13 -35
  15. package/dist/conversion/shared/responses-tool-utils.d.ts +1 -1
  16. package/dist/conversion/shared/responses-tool-utils.js +63 -65
  17. package/dist/conversion/shared/streaming-text-extractor.d.ts +0 -5
  18. package/dist/conversion/shared/streaming-text-extractor.js +18 -111
  19. package/dist/conversion/shared/text-markup-normalizer/normalize.d.ts +1 -1
  20. package/dist/conversion/shared/text-markup-normalizer/normalize.js +3 -91
  21. package/dist/conversion/shared/thought-signature-validator.js +19 -133
  22. package/dist/conversion/shared/tool-argument-repairer.js +16 -19
  23. package/dist/conversion/shared/tool-call-id-manager.d.ts +1 -5
  24. package/dist/conversion/shared/tool-call-id-manager.js +74 -98
  25. package/dist/conversion/shared/tool-harvester.js +19 -382
  26. package/dist/conversion/shared/tool-mapping.d.ts +2 -3
  27. package/dist/conversion/shared/tool-mapping.js +28 -184
  28. package/dist/conversion/shared/tooling.js +20 -151
  29. package/dist/filters/special/response-tool-arguments-stringify.js +9 -1
  30. package/dist/guidance/index.js +2 -2
  31. package/dist/native/router_hotpath_napi.node +0 -0
  32. package/dist/router/virtual-router/engine-legacy/helpers.js +1 -1
  33. package/dist/router/virtual-router/engine-selection/native-hub-bridge-action-semantics.d.ts +39 -0
  34. package/dist/router/virtual-router/engine-selection/native-hub-bridge-action-semantics.js +196 -0
  35. package/dist/router/virtual-router/engine-selection/native-hub-pipeline-req-inbound-semantics.d.ts +1 -0
  36. package/dist/router/virtual-router/engine-selection/native-hub-pipeline-req-inbound-semantics.js +27 -0
  37. package/dist/router/virtual-router/engine-selection/native-router-hotpath-loader.js +34 -0
  38. package/dist/router/virtual-router/engine-selection/native-shared-conversion-semantics.d.ts +65 -1
  39. package/dist/router/virtual-router/engine-selection/native-shared-conversion-semantics.js +836 -35
  40. package/dist/router/virtual-router/engine.js +3 -2
  41. package/dist/router/virtual-router/routing-instructions/parse.js +30 -3
  42. package/dist/sse/sse-to-json/builders/anthropic-response-builder.js +28 -3
  43. package/dist/sse/types/anthropic-types.d.ts +3 -1
  44. package/dist/tools/apply-patch/args-normalizer/extract-patch.js +2 -2
  45. package/dist/tools/apply-patch/patch-text/looks-like-patch.js +3 -6
  46. package/dist/tools/apply-patch/patch-text/normalize.js +14 -3
  47. package/dist/tools/tool-registry.js +12 -0
  48. package/package.json +6 -1
@@ -1,18 +1,14 @@
1
1
  import { normalizeChatResponseReasoningToolsWithNative, normalizeMessageReasoningToolsWithNative } from '../../router/virtual-router/engine-selection/native-hub-bridge-action-semantics.js';
2
- function overwriteRecordInPlace(target, source) {
3
- for (const key of Object.keys(target)) {
4
- delete target[key];
5
- }
6
- for (const [key, value] of Object.entries(source)) {
7
- target[key] = value;
2
+ const MODULE_NAME = 'reasoning-tool-normalizer';
3
+ function assertReasoningToolNormalizerNativeAvailable() {
4
+ if (typeof normalizeMessageReasoningToolsWithNative !== 'function' ||
5
+ typeof normalizeChatResponseReasoningToolsWithNative !== 'function') {
6
+ throw new Error(`[${MODULE_NAME}] native bindings unavailable`);
8
7
  }
9
8
  }
10
9
  export function normalizeMessageReasoningTools(message, options) {
11
- if (!message || typeof message !== 'object') {
12
- return { toolCallsAdded: 0 };
13
- }
10
+ assertReasoningToolNormalizerNativeAvailable();
14
11
  const normalized = normalizeMessageReasoningToolsWithNative(message, typeof options?.idPrefix === 'string' ? options.idPrefix : undefined);
15
- overwriteRecordInPlace(message, normalized.message);
16
12
  return {
17
13
  toolCallsAdded: normalized.toolCallsAdded,
18
14
  ...(typeof normalized.cleanedReasoning === 'string'
@@ -21,9 +17,6 @@ export function normalizeMessageReasoningTools(message, options) {
21
17
  };
22
18
  }
23
19
  export function normalizeChatResponseReasoningTools(response, options) {
24
- if (!response || typeof response !== 'object') {
25
- return;
26
- }
27
- const normalized = normalizeChatResponseReasoningToolsWithNative(response, typeof options?.idPrefixBase === 'string' ? options.idPrefixBase : undefined);
28
- overwriteRecordInPlace(response, normalized);
20
+ assertReasoningToolNormalizerNativeAvailable();
21
+ normalizeChatResponseReasoningToolsWithNative(response, typeof options?.idPrefixBase === 'string' ? options.idPrefixBase : undefined);
29
22
  }
@@ -1,41 +1,19 @@
1
- import { sanitizeReasoningTaggedTextWithNative } from '../../router/virtual-router/engine-selection/native-shared-conversion-semantics.js';
2
- export function extractReasoningSegments(source, reasoningCollector) {
3
- let working = source ?? '';
4
- const hasExplicitOpen = /<think>/i.test(source) ||
5
- /<reflection>/i.test(source) ||
6
- /```\s*(?:think|reflection)/i.test(source);
7
- const hasExplicitClose = /<\/think>/i.test(source) ||
8
- /<\/reflection>/i.test(source);
9
- const push = (value) => {
10
- const trimmed = (value ?? '').trim();
11
- if (trimmed && reasoningCollector) {
12
- reasoningCollector.push(trimmed);
13
- }
14
- };
15
- const patterns = [
16
- /<think>([\s\S]*?)<\/think>/gi,
17
- /<reflection>([\s\S]*?)<\/reflection>/gi,
18
- /```\s*(?:think|reflection)[\s\S]*?```/gi
19
- ];
20
- for (const pattern of patterns) {
21
- working = working.replace(pattern, (_match, inner) => {
22
- push(inner);
23
- return '';
24
- });
1
+ import { extractReasoningSegmentsWithNative, sanitizeReasoningTaggedTextWithNative } from '../../router/virtual-router/engine-selection/native-shared-conversion-semantics.js';
2
+ function assertReasoningUtilsNativeAvailable() {
3
+ if (typeof extractReasoningSegmentsWithNative !== 'function' ||
4
+ typeof sanitizeReasoningTaggedTextWithNative !== 'function') {
5
+ throw new Error('[reasoning-utils] native bindings unavailable');
25
6
  }
26
- working = working
27
- .replace(/<\/?think>/gi, '')
28
- .replace(/<\/?reflection>/gi, '');
29
- working = working.replace(/\n{3,}/g, '\n\n');
30
- if (reasoningCollector && !hasExplicitOpen && hasExplicitClose) {
31
- const trimmed = working.trim();
32
- if (trimmed.length) {
33
- reasoningCollector.push(trimmed);
34
- }
35
- return '';
7
+ }
8
+ export function extractReasoningSegments(source, reasoningCollector) {
9
+ assertReasoningUtilsNativeAvailable();
10
+ const output = extractReasoningSegmentsWithNative(source ?? '');
11
+ if (reasoningCollector) {
12
+ reasoningCollector.push(...output.segments);
36
13
  }
37
- return working.trim();
14
+ return output.text;
38
15
  }
39
16
  export function sanitizeReasoningTaggedText(value) {
17
+ assertReasoningUtilsNativeAvailable();
40
18
  return sanitizeReasoningTaggedTextWithNative(value);
41
19
  }
@@ -6,9 +6,9 @@ export interface CallIdTransformer {
6
6
  normalizeOutputId(callId: string, raw: unknown): string;
7
7
  }
8
8
  export declare function createToolCallIdTransformer(style: ToolCallIdStyle): CallIdTransformer | null;
9
- export declare function enforceToolCallIdStyle(input: BridgeInputItem[], transformer: CallIdTransformer): void;
10
9
  export declare function normalizeResponsesToolCallIds(payload: Record<string, unknown> | null | undefined): void;
11
10
  export declare function resolveToolCallIdStyle(metadata: Record<string, unknown> | undefined): ToolCallIdStyle;
12
11
  export declare function stripInternalToolingMetadata(metadata: unknown): void;
13
12
  export declare function sanitizeResponsesFunctionName(rawName: unknown): string | undefined;
13
+ export declare function enforceToolCallIdStyle(input: BridgeInputItem[], transformer: CallIdTransformer): void;
14
14
  export {};
@@ -1,75 +1,52 @@
1
- import { normalizeFunctionCallId, normalizeFunctionCallOutputId, normalizeResponsesCallId } from '../bridge-id-utils.js';
1
+ import { createToolCallIdTransformerWithNative, normalizeFunctionCallIdWithNative, normalizeFunctionCallOutputIdWithNative, normalizeResponsesCallIdWithNative } from '../../router/virtual-router/engine-selection/native-shared-conversion-semantics.js';
2
2
  import { sanitizeResponsesFunctionNameWithNative } from '../../router/virtual-router/engine-selection/native-hub-pipeline-resp-semantics.js';
3
+ function assertResponsesToolUtilsNativeAvailable() {
4
+ if (typeof createToolCallIdTransformerWithNative !== 'function' ||
5
+ typeof normalizeFunctionCallIdWithNative !== 'function' ||
6
+ typeof normalizeFunctionCallOutputIdWithNative !== 'function' ||
7
+ typeof normalizeResponsesCallIdWithNative !== 'function' ||
8
+ typeof sanitizeResponsesFunctionNameWithNative !== 'function') {
9
+ throw new Error('[responses-tool-utils] native bindings unavailable');
10
+ }
11
+ }
3
12
  export function createToolCallIdTransformer(style) {
13
+ assertResponsesToolUtilsNativeAvailable();
4
14
  if (style !== 'fc') {
5
15
  return null;
6
16
  }
7
- let callCounter = 0;
8
- let itemCounter = 0;
9
- let outputCounter = 0;
10
- const callAlias = new Map();
11
- const normalizeCallId = (raw) => {
12
- const rawStr = typeof raw === 'string' && raw.trim().length ? raw.trim() : undefined;
13
- if (rawStr && callAlias.has(rawStr)) {
14
- return callAlias.get(rawStr);
15
- }
16
- const normalized = normalizeResponsesCallId({
17
- callId: rawStr,
18
- fallback: `call_${++callCounter}`
19
- });
20
- if (rawStr) {
21
- callAlias.set(rawStr, normalized);
22
- }
23
- return normalized;
24
- };
25
- const normalizeItemId = (raw, callId) => {
26
- const rawStr = typeof raw === 'string' && raw.trim().length ? raw.trim() : undefined;
27
- return normalizeFunctionCallId({
28
- callId: rawStr ?? callId,
29
- fallback: `fc_item_${++itemCounter}`
30
- });
31
- };
32
- const normalizeOutputId = (callId, raw) => {
33
- const rawStr = typeof raw === 'string' && raw.trim().length ? raw.trim() : undefined;
34
- return normalizeFunctionCallOutputId({
35
- callId,
36
- fallback: rawStr ?? `fc_tool_${++outputCounter}`
37
- });
38
- };
17
+ const state = createToolCallIdTransformerWithNative(style);
39
18
  return {
40
- normalizeCallId,
41
- normalizeItemId,
42
- normalizeOutputId
19
+ normalizeCallId(raw) {
20
+ return normalizeResponsesCallIdWithNative({
21
+ callId: typeof raw === 'string' && raw.trim().length ? raw.trim() : undefined,
22
+ fallback: transformCounter(state, 'call')
23
+ });
24
+ },
25
+ normalizeItemId(raw, callId) {
26
+ return normalizeFunctionCallIdWithNative({
27
+ callId: typeof raw === 'string' && raw.trim().length ? raw.trim() : callId,
28
+ fallback: transformCounter(state, 'item')
29
+ });
30
+ },
31
+ normalizeOutputId(callId, raw) {
32
+ return normalizeFunctionCallOutputIdWithNative({
33
+ callId,
34
+ fallback: typeof raw === 'string' && raw.trim().length ? raw.trim() : transformCounter(state, 'tool')
35
+ });
36
+ }
43
37
  };
44
38
  }
45
- export function enforceToolCallIdStyle(input, transformer) {
46
- for (const entry of input) {
47
- if (!entry || typeof entry !== 'object')
48
- continue;
49
- const type = typeof entry.type === 'string' ? entry.type.toLowerCase() : '';
50
- if (type === 'function_call') {
51
- const normalizedCallId = transformer.normalizeCallId(entry.call_id ?? entry.id);
52
- entry.call_id = normalizedCallId;
53
- entry.id = transformer.normalizeItemId(entry.id ?? normalizedCallId, normalizedCallId);
54
- continue;
55
- }
56
- if (type === 'function_call_output' || type === 'tool_result' || type === 'tool_message') {
57
- const normalizedCallId = transformer.normalizeCallId(entry.call_id ?? entry.tool_call_id ?? entry.id);
58
- entry.call_id = normalizedCallId;
59
- // OpenAI `/v1/responses` request schema uses `call_id` for tool outputs.
60
- // Some internal carriers may include `tool_call_id`; strip it before sending upstream
61
- // to avoid strict schema errors (e.g. "Unknown parameter: input[N].tool_call_id").
62
- if (entry.tool_call_id !== undefined) {
63
- delete entry.tool_call_id;
64
- }
65
- entry.id = transformer.normalizeOutputId(normalizedCallId, entry.id);
66
- }
67
- }
39
+ function transformCounter(state, prefix) {
40
+ const current = typeof state.__counter === 'number' ? state.__counter : 0;
41
+ const next = current + 1;
42
+ state.__counter = next;
43
+ return `${prefix}_${next}`;
68
44
  }
69
45
  function isStableToolCallId(raw) {
70
46
  return /^((fc|call)_[A-Za-z0-9_-]+)$/i.test(raw);
71
47
  }
72
48
  export function normalizeResponsesToolCallIds(payload) {
49
+ assertResponsesToolUtilsNativeAvailable();
73
50
  if (!payload || typeof payload !== 'object') {
74
51
  return;
75
52
  }
@@ -85,7 +62,7 @@ export function normalizeResponsesToolCallIds(payload) {
85
62
  }
86
63
  const normalized = trimmed && isStableToolCallId(trimmed)
87
64
  ? trimmed
88
- : normalizeFunctionCallId({
65
+ : normalizeFunctionCallIdWithNative({
89
66
  callId: trimmed || undefined,
90
67
  fallback: nextFallback(fallbackPrefix)
91
68
  });
@@ -106,7 +83,7 @@ export function normalizeResponsesToolCallIds(payload) {
106
83
  item.tool_call_id = normalizedCallId;
107
84
  }
108
85
  const rawOutputId = typeof item.id === 'string' ? item.id : undefined;
109
- item.id = normalizeFunctionCallOutputId({
86
+ item.id = normalizeFunctionCallOutputIdWithNative({
110
87
  callId: normalizedCallId,
111
88
  fallback: rawOutputId ?? nextFallback('fc')
112
89
  });
@@ -119,7 +96,7 @@ export function normalizeResponsesToolCallIds(payload) {
119
96
  item.tool_call_id = normalizedCallId;
120
97
  }
121
98
  const rawOutputId = typeof item.id === 'string' ? item.id : undefined;
122
- item.id = normalizeFunctionCallOutputId({
99
+ item.id = normalizeFunctionCallOutputIdWithNative({
123
100
  callId: normalizedCallId,
124
101
  fallback: rawOutputId ?? nextFallback('fc')
125
102
  });
@@ -155,8 +132,6 @@ export function normalizeResponsesToolCallIds(payload) {
155
132
  }
156
133
  }
157
134
  export function resolveToolCallIdStyle(metadata) {
158
- // Standard OpenAI `/v1/responses` requires function_call item ids to start with `fc_`.
159
- // Default to `fc` unless explicitly overridden (e.g. LM Studio compat).
160
135
  if (!metadata)
161
136
  return 'fc';
162
137
  const raw = metadata.toolCallIdStyle;
@@ -171,6 +146,7 @@ export function resolveToolCallIdStyle(metadata) {
171
146
  }
172
147
  return 'fc';
173
148
  }
149
+ const RAW_SYSTEM_SENTINEL = '__rcc_raw_system';
174
150
  export function stripInternalToolingMetadata(metadata) {
175
151
  if (!metadata || typeof metadata !== 'object')
176
152
  return;
@@ -203,7 +179,29 @@ function prunePrivateExtraFields(target) {
203
179
  }
204
180
  }
205
181
  }
206
- const RAW_SYSTEM_SENTINEL = '__rcc_raw_system';
207
182
  export function sanitizeResponsesFunctionName(rawName) {
183
+ assertResponsesToolUtilsNativeAvailable();
208
184
  return sanitizeResponsesFunctionNameWithNative(rawName);
209
185
  }
186
+ export function enforceToolCallIdStyle(input, transformer) {
187
+ assertResponsesToolUtilsNativeAvailable();
188
+ for (const entry of input) {
189
+ if (!entry || typeof entry !== 'object')
190
+ continue;
191
+ const type = typeof entry.type === 'string' ? entry.type.toLowerCase() : '';
192
+ if (type === 'function_call') {
193
+ const normalizedCallId = transformer.normalizeCallId(entry.call_id ?? entry.id);
194
+ entry.call_id = normalizedCallId;
195
+ entry.id = transformer.normalizeItemId(entry.id ?? normalizedCallId, normalizedCallId);
196
+ continue;
197
+ }
198
+ if (type === 'function_call_output' || type === 'tool_result' || type === 'tool_message') {
199
+ const normalizedCallId = transformer.normalizeCallId(entry.call_id ?? entry.tool_call_id ?? entry.id);
200
+ entry.call_id = normalizedCallId;
201
+ if (entry.tool_call_id !== undefined) {
202
+ delete entry.tool_call_id;
203
+ }
204
+ entry.id = transformer.normalizeOutputId(normalizedCallId, entry.id);
205
+ }
206
+ }
207
+ }
@@ -16,10 +16,5 @@ export declare class StreamingTextToolExtractor {
16
16
  constructor(opts?: StreamingToolExtractorOptions);
17
17
  reset(): void;
18
18
  feedText(text: string): StreamingToolCall[];
19
- private genId;
20
- private toToolCall;
21
- private tryExtractStructuredBlocks;
22
- private tryExtractFunctionExecuteBlocks;
23
- private splitCommand;
24
19
  }
25
20
  export declare function createStreamingToolExtractor(opts?: StreamingToolExtractorOptions): StreamingTextToolExtractor;
@@ -1,10 +1,11 @@
1
1
  // Streaming textual tool intent extractor (对齐)
2
2
  // Detects <function=execute> blocks and structured apply_patch payloads
3
3
  // and converts them into OpenAI tool_calls incrementally.
4
- import { isStructuredApplyPatchPayload } from '../../tools/apply-patch-structured.js';
5
- import { repairArgumentsToStringWithNative } from '../../router/virtual-router/engine-selection/native-shared-conversion-semantics.js';
6
- function isObject(v) {
7
- return !!v && typeof v === 'object' && !Array.isArray(v);
4
+ import { extractStreamingToolCallsWithNative } from '../../router/virtual-router/engine-selection/native-shared-conversion-semantics.js';
5
+ function assertStreamingToolExtractorNativeAvailable() {
6
+ if (typeof extractStreamingToolCallsWithNative !== 'function') {
7
+ throw new Error('[streaming-text-extractor] native bindings unavailable');
8
+ }
8
9
  }
9
10
  export class StreamingTextToolExtractor {
10
11
  opts;
@@ -18,114 +19,20 @@ export class StreamingTextToolExtractor {
18
19
  this.idCounter = 0;
19
20
  }
20
21
  feedText(text) {
21
- const out = [];
22
22
  if (typeof text !== 'string' || !text)
23
- return out;
24
- this.buffer += text;
25
- // 1) Structured apply_patch block detection (```json ... ```)
26
- out.push(...this.tryExtractStructuredBlocks());
27
- // 2) <function=execute> compact blocks detection
28
- out.push(...this.tryExtractFunctionExecuteBlocks());
29
- return out;
30
- }
31
- genId() {
32
- const p = this.opts.idPrefix || 'call';
33
- return `${p}_${Date.now()}_${(++this.idCounter).toString(36)}`;
34
- }
35
- toToolCall(name, argsObj) {
36
- const argStr = repairArgumentsToStringWithNative(argsObj);
37
- return { id: this.genId(), type: 'function', function: { name, arguments: argStr } };
38
- }
39
- tryExtractStructuredBlocks() {
40
- const out = [];
41
- let searchIdx = 0;
42
- while (searchIdx < this.buffer.length) {
43
- const startIdx = this.buffer.indexOf('```', searchIdx);
44
- if (startIdx < 0)
45
- break;
46
- const headerEnd = this.buffer.indexOf('\n', startIdx + 3);
47
- if (headerEnd < 0)
48
- break;
49
- const language = this.buffer.slice(startIdx + 3, headerEnd).trim().toLowerCase();
50
- const endIdx = this.buffer.indexOf('```', headerEnd + 1);
51
- if (endIdx < 0)
52
- break;
53
- const body = this.buffer.slice(headerEnd + 1, endIdx);
54
- if (!language || language === 'json' || language === 'apply_patch' || language === 'toon') {
55
- try {
56
- const parsed = JSON.parse(body);
57
- if (isStructuredApplyPatchPayload(parsed)) {
58
- out.push(this.toToolCall('apply_patch', parsed));
59
- this.buffer = this.buffer.slice(0, startIdx) + this.buffer.slice(endIdx + 3);
60
- searchIdx = 0;
61
- continue;
62
- }
63
- }
64
- catch {
65
- /* ignore parse errors */
66
- }
67
- }
68
- searchIdx = endIdx + 3;
69
- }
70
- return out;
71
- }
72
- // rcc.tool.v1 JSON detection removed
73
- tryExtractFunctionExecuteBlocks() {
74
- const out = [];
75
- // Very lightweight parser for <function=execute> <parameter=command>...</parameter>
76
- const execRe = /<function=execute>[\s\S]*?<parameter=command>([\s\S]*?)<\/parameter>[\s\S]*?<\/function=execute>/gi;
77
- let m;
78
- while ((m = execRe.exec(this.buffer)) !== null) {
79
- const cmd = (m[1] || '').trim();
80
- if (cmd) {
81
- // split a shell command string into argv best-effort
82
- const argv = this.splitCommand(cmd);
83
- out.push(this.toToolCall('shell', { command: argv }));
84
- }
85
- }
86
- if (out.length > 0) {
87
- this.buffer = this.buffer.replace(execRe, '');
88
- }
89
- return out;
90
- }
91
- splitCommand(s) {
92
- try {
93
- // basic quotes-aware split
94
- const out = [];
95
- let cur = '';
96
- let quote = null;
97
- for (let i = 0; i < s.length; i++) {
98
- const ch = s[i];
99
- if (quote) {
100
- if (ch === quote) {
101
- quote = null;
102
- }
103
- else {
104
- cur += ch;
105
- }
106
- }
107
- else {
108
- if (ch === '"' || ch === '\'') {
109
- quote = ch;
110
- }
111
- else if (/\s/.test(ch)) {
112
- if (cur) {
113
- out.push(cur);
114
- cur = '';
115
- }
116
- }
117
- else {
118
- cur += ch;
119
- }
120
- }
121
- }
122
- if (cur)
123
- out.push(cur);
124
- return out;
125
- }
126
- catch {
127
- return [s];
128
- }
23
+ return [];
24
+ assertStreamingToolExtractorNativeAvailable();
25
+ const idPrefix = this.opts.idPrefix || 'call';
26
+ const output = extractStreamingToolCallsWithNative({
27
+ buffer: this.buffer,
28
+ text,
29
+ idPrefix,
30
+ idCounter: this.idCounter,
31
+ nowMs: Date.now()
32
+ });
33
+ this.buffer = typeof output.buffer === 'string' ? output.buffer : this.buffer;
34
+ this.idCounter = typeof output.idCounter === 'number' ? output.idCounter : this.idCounter;
35
+ return Array.isArray(output.toolCalls) ? output.toolCalls : [];
129
36
  }
130
37
  }
131
38
  export function createStreamingToolExtractor(opts) {
@@ -1,2 +1,2 @@
1
1
  import type { TextMarkupNormalizeOptions } from '../../types/text-markup-normalizer.js';
2
- export declare function normalizeAssistantTextToToolCalls(message: Record<string, any>, _options?: TextMarkupNormalizeOptions): Record<string, any>;
2
+ export declare function normalizeAssistantTextToToolCalls(message: Record<string, any>, options?: TextMarkupNormalizeOptions): Record<string, any>;
@@ -1,4 +1,4 @@
1
- import { extractToolCallsFromReasoningTextWithNative } from '../../../router/virtual-router/engine-selection/native-shared-conversion-semantics.js';
1
+ import { normalizeAssistantTextToToolCallsWithNative } from '../../../router/virtual-router/engine-selection/native-shared-conversion-semantics.js';
2
2
  function enabled() {
3
3
  try {
4
4
  return String(process?.env?.RCC_TEXT_MARKUP_COMPAT ?? '1').trim() !== '0';
@@ -7,96 +7,8 @@ function enabled() {
7
7
  return true;
8
8
  }
9
9
  }
10
- export function normalizeAssistantTextToToolCalls(message, _options) {
10
+ export function normalizeAssistantTextToToolCalls(message, options) {
11
11
  if (!enabled())
12
12
  return message;
13
- try {
14
- if (!message || typeof message !== 'object')
15
- return message;
16
- if (Array.isArray(message.tool_calls) && message.tool_calls.length)
17
- return message;
18
- const content = message.content;
19
- const candidates = [];
20
- if (typeof content === 'string') {
21
- candidates.push(content);
22
- }
23
- else if (Array.isArray(content)) {
24
- for (const part of content) {
25
- if (!part || typeof part !== 'object')
26
- continue;
27
- const p = part;
28
- if (typeof p.text === 'string' && p.text.trim()) {
29
- candidates.push(p.text);
30
- continue;
31
- }
32
- if (typeof p.content === 'string' && p.content.trim()) {
33
- candidates.push(p.content);
34
- continue;
35
- }
36
- }
37
- }
38
- if (typeof message.reasoning === 'string' && message.reasoning.trim()) {
39
- candidates.push(String(message.reasoning));
40
- }
41
- if (typeof message.thinking === 'string' && message.thinking.trim()) {
42
- candidates.push(String(message.thinking));
43
- }
44
- if (!candidates.length)
45
- return message;
46
- let calls = null;
47
- const mapNativeToolCalls = (raw) => {
48
- const mapped = [];
49
- raw.forEach((entry, index) => {
50
- if (!entry || typeof entry !== 'object')
51
- return;
52
- const functionNode = entry.function && typeof entry.function === 'object' && !Array.isArray(entry.function)
53
- ? entry.function
54
- : undefined;
55
- const name = (typeof functionNode?.name === 'string' && functionNode.name.trim()) ||
56
- (typeof entry.name === 'string' && entry.name.trim()) ||
57
- undefined;
58
- if (!name)
59
- return;
60
- const argsCandidate = functionNode?.arguments ?? entry.arguments ?? entry.args ?? '{}';
61
- let args = '{}';
62
- if (typeof argsCandidate === 'string') {
63
- args = argsCandidate;
64
- }
65
- else {
66
- try {
67
- args = JSON.stringify(argsCandidate ?? {});
68
- }
69
- catch {
70
- args = '{}';
71
- }
72
- }
73
- const id = (typeof entry.id === 'string' && entry.id.trim()) ||
74
- (typeof entry.call_id === 'string' && entry.call_id.trim()) ||
75
- `call_${index + 1}`;
76
- mapped.push({ id, name, args });
77
- });
78
- return mapped;
79
- };
80
- for (const text of candidates) {
81
- const nativeParsed = extractToolCallsFromReasoningTextWithNative(text);
82
- if (nativeParsed.toolCalls.length) {
83
- const nativeCalls = mapNativeToolCalls(nativeParsed.toolCalls);
84
- if (nativeCalls.length) {
85
- calls = nativeCalls;
86
- break;
87
- }
88
- }
89
- }
90
- if (calls && calls.length) {
91
- const toolCalls = calls.map((c) => ({ id: c.id, type: 'function', function: { name: c.name, arguments: c.args } }));
92
- const copy = { ...message };
93
- copy.tool_calls = toolCalls;
94
- copy.content = '';
95
- return copy;
96
- }
97
- }
98
- catch {
99
- // ignore normalization failures
100
- }
101
- return message;
13
+ return normalizeAssistantTextToToolCallsWithNative(message, options);
102
14
  }