applySchemas function

List<ToolCall>? applySchemas(
  1. List<ToolCall>? calls,
  2. List<FunctionTool> functions
)

Repairs argument types against each function's declared schema.

A prompted model returns scalars as strings far more often than a native tool-caller does — "5" where the schema says integer. Every coercion here is lossless or skipped: a value that does not convert CLEANLY to the declared type travels exactly as the model sent it, and parameters the schema does not declare are never touched.

This is what turns a type mismatch from a repair round trip — one more message off an anonymous hourly allowance — into a first-pass parse.

Implementation

List<ToolCall>? applySchemas(
    List<ToolCall>? calls, List<FunctionTool> functions) {
  if (calls == null || calls.isEmpty || functions.isEmpty) return calls;

  final byName = {for (final f in functions) f.name: f.parameters};
  return [
    for (final call in calls)
      switch (byName[call.name]?['properties']) {
        final Map<dynamic, dynamic> props => ToolCall(
            id: call.id,
            name: call.name,
            arguments: {
              for (final e in call.arguments.entries)
                e.key: coerceValue(e.value, props[e.key]),
            },
          ),
        _ => call,
      },
  ];
}