parseToolCall method

ToolCallParseResult parseToolCall(
  1. String llmOutput
)

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,
    );
  }
}