MCPcopy Create free account
hub / github.com/dwgx/WindsurfAPI / parseNativeFunctionCallsFromText

Function parseNativeFunctionCallsFromText

src/cascade-native-bridge.js:1145–1199  ·  view source on GitHub ↗
(text, callerLookup = new Map())

Source from the content-addressed store, hash-verified

1143 * proposal. Convert it back to the caller's declared tool name.
1144 */
1145export function parseNativeFunctionCallsFromText(text, callerLookup = new Map()) {
1146 if (typeof text !== 'string' || !/<function_calls\b/i.test(text)) {
1147 return { text: text || '', toolCalls: [] };
1148 }
1149 const calls = [];
1150 const keepOutsideBlocks = [];
1151 let lastBlockEnd = 0;
1152 const blockRe = /<function_calls\b[^>]*>([\s\S]*?)<\/function_calls>/gi;
1153 const invokeRe = /<invoke\b([^>]*)>([\s\S]*?)<\/invoke>/gi;
1154 let block;
1155 while ((block = blockRe.exec(text)) !== null) {
1156 keepOutsideBlocks.push(text.slice(lastBlockEnd, block.index));
1157 lastBlockEnd = block.index + block[0].length;
1158 invokeRe.lastIndex = 0;
1159 let match;
1160 while ((match = invokeRe.exec(block[1])) !== null) {
1161 const nameAttr = match[1].match(/\bname\s*=\s*"([^"]+)"/i)
1162 || match[1].match(/\bname\s*=\s*'([^']+)'/i);
1163 const rawName = nameAttr ? unescapeXmlText(nameAttr[1]).trim() : '';
1164 const entry = TOOL_MAP[rawName];
1165 if (!rawName || !entry) continue;
1166 const params = {};
1167 const paramRe = /<parameter\b([^>]*)>([\s\S]*?)<\/parameter>/gi;
1168 let pm;
1169 while ((pm = paramRe.exec(match[2])) !== null) {
1170 const paramNameAttr = pm[1].match(/\bname\s*=\s*"([^"]+)"/i)
1171 || pm[1].match(/\bname\s*=\s*'([^']+)'/i);
1172 const paramName = paramNameAttr ? unescapeXmlText(paramNameAttr[1]).trim() : '';
1173 if (!paramName) continue;
1174 const rawValue = unescapeXmlText(pm[2].trim());
1175 const parsed = safeJsonParse(rawValue);
1176 params[paramName] = Object.keys(parsed).length || /^[\[{]/.test(rawValue.trim())
1177 ? parsed
1178 : rawValue;
1179 }
1180 const cascadeKind = entry.kind;
1181 const candidates = callerLookup?.get(cascadeKind) || [];
1182 const callerName = candidates[0];
1183 if (!callerName) continue;
1184 const reverseFn = TOOL_MAP[callerName]?.reverse || identityArgs;
1185 let openaiArgs;
1186 try { openaiArgs = reverseFn(entry.forward(params)); }
1187 catch { openaiArgs = params; }
1188 calls.push({
1189 id: `call_native_${calls.length}_${Date.now().toString(36)}`,
1190 name: callerName,
1191 argumentsJson: JSON.stringify(openaiArgs ?? {}),
1192 });
1193 }
1194 }
1195 const trailing = text.slice(lastBlockEnd);
1196 const danglingOpen = trailing.search(/<function_calls\b/i);
1197 keepOutsideBlocks.push(danglingOpen === -1 ? trailing : trailing.slice(0, danglingOpen));
1198 return { text: keepOutsideBlocks.join('').trim(), toolCalls: calls };
1199}
1200
1201/**
1202 * Streaming guard for Claude provider-native <function_calls> blocks in native

Callers 3

nonStreamResponseFunction · 0.90
_drainMethod · 0.85

Calls 3

unescapeXmlTextFunction · 0.85
pushMethod · 0.80
safeJsonParseFunction · 0.70

Tested by

no test coverage detected