parseToolCall method
Parse LLM output for tool calls using C++ implementation.
*** THIS IS THE ONLY PARSING IMPLEMENTATION - NO DART FALLBACK ***
Handles all edge cases:
- Missing closing tags (brace-matching)
- Unquoted JSON keys ({tool: "name"} → {"tool": "name"})
- Multiple key naming conventions
- Tool name as key pattern
llmOutput Raw LLM output text
Returns parsed result with tool call info
Implementation
ToolCallParseResult parseToolCall(String llmOutput) {
try {
final parseFn = lib.lookupFunction<
Int32 Function(Pointer<Utf8>, Pointer<RacToolCallStruct>),
int Function(Pointer<Utf8>, Pointer<RacToolCallStruct>)>(
'rac_tool_call_parse',
);
final freeFn = lib.lookupFunction<
Void Function(Pointer<RacToolCallStruct>),
void Function(Pointer<RacToolCallStruct>)>(
'rac_tool_call_free',
);
final outputPtr = llmOutput.toNativeUtf8();
final resultPtr = calloc<RacToolCallStruct>();
try {
final rc = parseFn(outputPtr, resultPtr);
if (rc != RAC_SUCCESS) {
return ToolCallParseResult(
hasToolCall: false,
cleanText: llmOutput,
callId: 0,
);
}
final result = resultPtr.ref;
final hasToolCall = result.hasToolCall == RAC_TRUE;
String cleanText = llmOutput;
if (result.cleanText != nullptr) {
cleanText = result.cleanText.toDartString();
}
String? toolName;
Map<String, dynamic>? arguments;
int callId = 0;
if (hasToolCall) {
if (result.toolName != nullptr) {
toolName = result.toolName.toDartString();
}
if (result.argumentsJson != nullptr) {
final argsJson = result.argumentsJson.toDartString();
try {
arguments = jsonDecode(argsJson) as Map<String, dynamic>;
} catch (e) {
arguments = {};
}
}
callId = result.callId;
}
freeFn(resultPtr);
return ToolCallParseResult(
hasToolCall: hasToolCall,
cleanText: cleanText,
toolName: toolName,
arguments: arguments,
callId: callId,
);
} finally {
calloc.free(outputPtr);
calloc.free(resultPtr);
}
} catch (e) {
_logger.error('parseToolCall failed: $e');
return ToolCallParseResult(
hasToolCall: false,
cleanText: llmOutput,
callId: 0,
);
}
}