> ## Documentation Index
> Fetch the complete documentation index at: https://liquidai-example-leonie-demo.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Function Calling

> Tool use with LeapFunction — same API on every platform, with Hermes and Pythonic parsers.

Function calling lets the model invoke predefined functions provided by your app — query an API, run a calculation, fetch external state. Register `LeapFunction` definitions on the `Conversation`, run generation as usual, and the model's tool-call tokens come back as `MessageResponse.functionCalls`.

<Warning>
  Not all models support function calling. Check the model card on [Hugging Face](https://huggingface.co/LiquidAI) before assuming a checkpoint supports tool use.
</Warning>

<Info>
  Vision and audio-capable models require companion files. Bundles embed these references; GGUF checkpoints expect siblings such as `mmproj-*.gguf` (vision) and audio decoder/tokenizer files. When detected, you can attach `ChatMessageContent.image` / `.audio` parts to your tool responses as well as user messages.
</Info>

## Register functions on the conversation

`Conversation.registerFunction` takes a `LeapFunction` instance describing name, parameters, and purpose.

<Tabs>
  <Tab title="Swift (iOS / macOS)">
    The Kotlin `LeapFunction` / `LeapFunctionParameter` constructors carry `@ObjCName` annotations on `description:`, so the Swift labels are `functionDescription:` and `parameterDescription:`. `LeapFunctionParameter`'s `optional` parameter has no Swift default — pass `optional: false` for required parameters.

    ```swift theme={null}
    conversation.registerFunction(
      function: LeapFunction(
        name: "get_weather",
        functionDescription: "Query the weather of a city",
        parameters: [
          LeapFunctionParameter(
            name: "city",
            type: LeapFunctionParameterType.LeapStr(enumValues: nil, description: nil),
            parameterDescription: "The city to query weather for",
            optional: false
          ),
          LeapFunctionParameter(
            name: "unit",
            type: LeapFunctionParameterType.LeapStr(
              enumValues: ["celsius", "fahrenheit"],
              description: nil
            ),
            parameterDescription: "Temperature unit (celsius or fahrenheit)",
            optional: false
          ),
        ]
      )
    )
    ```
  </Tab>

  <Tab title="Kotlin (all platforms)">
    ```kotlin theme={null}
    val conversation = modelRunner.createConversation("You are a helpful assistant.")

    conversation.registerFunction(
      LeapFunction(
        name = "get_weather",
        description = "Get the weather forecast of a city",
        parameters = listOf(
          LeapFunctionParameter(
            name = "city",
            type = LeapFunctionParameterType.LeapStr(),
            description = "The city name",
          ),
          LeapFunctionParameter(
            name = "unit",
            type = LeapFunctionParameterType.LeapStr(
              enumValues = listOf("celsius", "fahrenheit")
            ),
            description = "Temperature unit",
          ),
        ),
      ),
    )
    ```
  </Tab>
</Tabs>

Use normal identifiers — letters, underscores, and digits (not starting with a digit). Most models trained for tool use recognize that shape.

<Info>
  The Kotlin parameter type classes are named with a `Leap` prefix (`LeapStr`, `LeapNum`, `LeapInt`, `LeapBool`, `LeapArr`, `LeapObj`, `LeapNull`) to avoid collisions with Kotlin's built-in `String`, `Number`, `Int`, `Boolean`, etc. The Swift bindings expose the same names — there are no separate `.string(...)` / `.number(...)` aliases; SKIE preserves the Kotlin nested-class names.
</Info>

## Handle the response

Function calls arrive as the `MessageResponse.FunctionCalls` variant on both platforms, wrapping a list of `LeapFunctionCall` payloads.

<Tabs>
  <Tab title="Swift (iOS / macOS)">
    `LeapFunctionCall` is a Kotlin `data class` bridged into Swift. `arguments` is a Kotlin `Map<String, Any?>` exposed as Swift `[String: Any]` (the ObjC bridge collapses `Any?` to non-optional `id`):

    ```swift theme={null}
    public class LeapFunctionCall {
      public var name: String
      public var arguments: [String: Any]
    }
    ```

    ```swift theme={null}
    let userMessage = ChatMessage(role: .user, textContent: "What's the weather in NYC?")

    for try await response in conversation.generateResponse(message: userMessage) {
        switch onEnum(of: response) {
        case .functionCalls(let payload):
            for call in payload.functionCalls {
                print("Function call: \(call.name) \(call.arguments)")
                // dispatch to your tool implementation
            }
        case .chunk, .reasoningChunk, .audioSample, .complete:
            break
        }
    }
    ```
  </Tab>

  <Tab title="Kotlin (all platforms)">
    ```kotlin theme={null}
    data class LeapFunctionCall(
        val name: String,
        val arguments: Map<String, Any?>,
    )
    ```

    ```kotlin theme={null}
    conversation.generateResponse(userMessage).onEach { response ->
        when (response) {
            is MessageResponse.Chunk -> { /* text chunk */ }
            is MessageResponse.FunctionCalls -> {
                response.functionCalls.forEach { call ->
                    Log.d(TAG, "Call ${call.name} with ${call.arguments}")
                    // dispatch to your tool implementation
                }
            }
            is MessageResponse.Complete -> {
                // Tool calls are also surfaced on the assembled assistant message:
                response.fullMessage.functionCalls?.forEach { /* ... */ }
            }
            else -> {}
        }
    }.collect()
    ```

    Tool calls are also attached to the final assistant message on the `Complete` event — useful if you'd rather batch-process tool calls once generation finishes.
  </Tab>
</Tabs>

The model may emit missing or invalid arguments — defensively validate the arguments map against your tool's expected shape before dispatching.

## Sending tool results back

Append the tool's output as a `tool`-role message and continue the conversation. Both platforms use the same shape — see also [Quick Start → Add tool results back to history](./quick-start).

<Tabs>
  <Tab title="Swift (iOS / macOS)">
    ```swift theme={null}
    let toolMessage = ChatMessage(
      role: .tool,
      textContent: #"{"temperature":72,"conditions":"sunny"}"#
    )

    let updatedHistory = conversation.history + [toolMessage]
    let nextConversation = conversation.modelRunner.createConversationFromHistory(history: updatedHistory)
    // Continue generation against `nextConversation`.
    ```
  </Tab>

  <Tab title="Kotlin (all platforms)">
    ```kotlin theme={null}
    val toolMessage = ChatMessage(
        role = ChatMessage.Role.TOOL,
        content = listOf(
            ChatMessageContent.Text("""{"temperature":72,"conditions":"sunny"}""")
        )
    )

    val updatedHistory = conversation.history + toolMessage
    val nextConversation = modelRunner.createConversationFromHistory(updatedHistory)
    ```
  </Tab>
</Tabs>

Then call `generateResponse(...)` on the new conversation to get the model's tool-aware reply.

## `LeapFunction`

<Tabs>
  <Tab title="Swift (iOS / macOS)">
    Both types are Kotlin `data class`es bridged into Swift. `@ObjCName` annotations rename the `description` parameter on the Swift inits to `functionDescription:` / `parameterDescription:`.

    ```swift theme={null}
    public class LeapFunction {
      public var name: String
      public var functionDescription: String       // ObjC-renamed from Kotlin `description`
      public var parameters: [LeapFunctionParameter]

      public init(name: String, functionDescription: String, parameters: [LeapFunctionParameter])
    }

    public class LeapFunctionParameter {
      public var name: String
      public var type: LeapFunctionParameterType
      public var parameterDescription: String      // ObjC-renamed from Kotlin `description`
      public var optional: Bool

      public init(
        name: String,
        type: LeapFunctionParameterType,
        parameterDescription: String,
        optional: Bool                              // no default in Swift — pass `false` for required
      )
    }
    ```
  </Tab>

  <Tab title="Kotlin (all platforms)">
    ```kotlin theme={null}
    data class LeapFunction(
        val name: String,
        val description: String,
        val parameters: List<LeapFunctionParameter>,
    )

    data class LeapFunctionParameter(
        val name: String,
        val type: LeapFunctionParameterType,
        val description: String,
        val optional: Boolean = false,
    )
    ```
  </Tab>
</Tabs>

## Parameter types

`LeapFunctionParameterType` is translated into JSON Schema for the model. The same primitive set is exposed on both platforms.

<Tabs>
  <Tab title="Swift (iOS / macOS)">
    `LeapFunctionParameterType` is a Kotlin `sealed class`. SKIE generates an `onEnum(of:)`-compatible enum view, but the constructors you use to build instances keep the Kotlin nested-class names — there is no `.string(...)` / `.number(...)` alias.

    ```swift theme={null}
    // Direct constructors (use these to build parameter types):
    LeapFunctionParameterType.LeapStr(enumValues: [String]?, description: String?)
    LeapFunctionParameterType.LeapNum(enumValues: [NSNumber]?, description: String?)
    LeapFunctionParameterType.LeapInt(enumValues: [KotlinInt]?, description: String?)
    LeapFunctionParameterType.LeapBool(description: String?)
    LeapFunctionParameterType.LeapArr(itemType: LeapFunctionParameterType, description: String?)
    LeapFunctionParameterType.LeapObj(
      properties: [String: LeapFunctionParameterType],
      required: [String],
      description: String?
    )
    LeapFunctionParameterType.LeapNull()   // no description parameter
    ```

    * `LeapStr` / `LeapNum` / `LeapInt` accept `enumValues` to constrain valid values.
    * `LeapArr` has `itemType` describing the element type.
    * `LeapObj` has `properties: [String: LeapFunctionParameterType]` and `required: [String]`.
    * The nested `description` is overridden when the type is used directly as `LeapFunctionParameter.type`; it's only consulted when the type is used inside `LeapArr.itemType` or `LeapObj.properties`.
  </Tab>

  <Tab title="Kotlin (all platforms)">
    ```kotlin theme={null}
    LeapFunctionParameterType.LeapStr(enumValues: List<String>? = null, description: String? = null)
    LeapFunctionParameterType.LeapNum(enumValues: List<Number>? = null, description: String? = null)
    LeapFunctionParameterType.LeapInt(enumValues: List<Int>? = null, description: String? = null)
    LeapFunctionParameterType.LeapBool(description: String? = null)
    LeapFunctionParameterType.LeapArr(itemType: LeapFunctionParameterType, description: String? = null)
    LeapFunctionParameterType.LeapObj(
        properties: Map<String, LeapFunctionParameterType>,
        required: List<String> = listOf(),
        description: String? = null,
    )
    LeapFunctionParameterType.LeapNull()
    ```

    The nested `description` is overridden when the type is used directly as `LeapFunctionParameter.type`; it's only consulted when the type is used inside `LeapArr.itemType` or `LeapObj.properties`.
  </Tab>
</Tabs>

### Example: array + enum parameters

<Tabs>
  <Tab title="Swift (iOS / macOS)">
    ```swift theme={null}
    LeapFunction(
      name: "get_weather",
      functionDescription: "Query the weather of cities",
      parameters: [
        LeapFunctionParameter(
          name: "cities",
          type: LeapFunctionParameterType.LeapArr(
            itemType: LeapFunctionParameterType.LeapStr(enumValues: nil, description: nil),
            description: nil
          ),
          parameterDescription: "Names of the cities to query weather for",
          optional: false
        ),
        LeapFunctionParameter(
          name: "unit",
          type: LeapFunctionParameterType.LeapStr(
            enumValues: ["celsius", "fahrenheit"],
            description: nil
          ),
          parameterDescription: "Temperature unit",
          optional: false
        ),
      ]
    )
    ```
  </Tab>

  <Tab title="Kotlin (all platforms)">
    ```kotlin theme={null}
    LeapFunction(
      name = "get_weather",
      description = "Get the weather forecast of cities",
      parameters = listOf(
        LeapFunctionParameter(
          name = "cities",
          type = LeapFunctionParameterType.LeapArr(
            itemType = LeapFunctionParameterType.LeapStr()
          ),
          description = "City names to query",
        ),
        LeapFunctionParameter(
          name = "temperature_unit",
          type = LeapFunctionParameterType.LeapStr(
            enumValues = listOf("Fahrenheit", "Celsius", "Kelvin")
          ),
          description = "Units for temperature",
        ),
      ),
    )
    ```
  </Tab>
</Tabs>

## Function call parser

Different models emit tool-call tokens in different shapes. The parser translates those tokens into `LeapFunctionCall` values. The default `LFMFunctionCallParser` handles Liquid Foundation Model (LFM2) Pythonic-style control tokens (`<|tool_call_start|> ... <|tool_call_end|>`). For Qwen3 and other models using the [Hermes function-calling format](https://github.com/NousResearch/Hermes-Function-Calling), use `HermesFunctionCallParser`.

<Tabs>
  <Tab title="Swift (iOS / macOS)">
    ```swift theme={null}
    var options = GenerationOptions()
    options.functionCallParser = HermesFunctionCallParser()

    for try await response in conversation.generateResponse(
      message: userMessage,
      generationOptions: options
    ) {
      // ...
    }
    ```
  </Tab>

  <Tab title="Kotlin (all platforms)">
    ```kotlin theme={null}
    val options = GenerationOptions.build {
        functionCallParser = HermesFunctionCallParser()
    }

    conversation.generateResponse(userMessage, options).onEach { /* ... */ }.collect()
    ```
  </Tab>
</Tabs>

Pass `null` / `nil` as the parser to disable tool-call parsing entirely — the raw tool-call text is then surfaced as ordinary `Chunk`s.
