Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.liquid.ai/llms.txt

Use this file to discover all available pages before exploring further.

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.
Not all models support function calling. Check the model card on Hugging Face before assuming a checkpoint supports tool use.
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.

Register functions on the conversation

Conversation.registerFunction takes a LeapFunction instance describing name, parameters, and purpose.
conversation.registerFunction(
  LeapFunction(
    name: "get_weather",
    description: "Query the weather of a city",
    parameters: [
      LeapFunctionParameter(
        name: "city",
        type: LeapFunctionParameterType.string(StringType()),
        description: "The city to query weather for"
      ),
      LeapFunctionParameter(
        name: "unit",
        type: LeapFunctionParameterType.string(
          StringType(enumValues: ["celsius", "fahrenheit"])
        ),
        description: "Temperature unit (celsius or fahrenheit)"
      ),
    ]
  )
)
Use normal identifiers β€” letters, underscores, and digits (not starting with a digit). Most models trained for tool use recognize that shape.
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 primitives under cleaner names (.string(...), .number(...), etc.) via SKIE.

Handle the response

Function calls arrive as MessageResponse.functionCalls (Swift) / MessageResponse.FunctionCalls (Kotlin), which wraps a list of LeapFunctionCall.
public struct LeapFunctionCall {
  public let name: String
  public let arguments: [String: Any?]
}
let userMessage = ChatMessage(role: .user, content: [.text("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
    }
}
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.
let toolMessage = ChatMessage(
  role: .tool,
  content: [.text(#"{"temperature":72,"conditions":"sunny"}"#)]
)

guard let current = conversation else { return }
let updatedHistory = current.history + [toolMessage]
conversation = current.modelRunner.createConversationFromHistory(history: updatedHistory)
Then call generateResponse(...) on the new conversation to get the model’s tool-aware reply.

LeapFunction

public struct LeapFunction: Equatable {
  public let name: String
  public let description: String
  public let parameters: [LeapFunctionParameter]
}

public struct LeapFunctionParameter: Equatable {
  public let name: String
  public let type: LeapFunctionParameterType
  public let description: String
  public let optional: Bool
}

Parameter types

LeapFunctionParameterType is translated into JSON Schema for the model. The same primitive set is exposed on both platforms.
public indirect enum LeapFunctionParameterType: Codable, Equatable {
  case string(StringType)
  case number(NumberType)
  case integer(IntegerType)
  case boolean(BooleanType)
  case array(ArrayType)
  case object(ObjectType)
  case null(NullType)
}
  • StringType, NumberType, IntegerType accept enumValues to constrain valid values.
  • ArrayType has itemType describing element type.
  • ObjectType has properties: [String: LeapFunctionParameterType] and required: [String].
  • All non-null types take an optional description (only used when nested via ArrayType.itemType or object properties β€” when used directly as LeapFunctionParameter.type, the outer description wins).

Example: array + enum parameters

LeapFunction(
  name: "get_weather",
  description: "Query the weather of cities",
  parameters: [
    LeapFunctionParameter(
      name: "cities",
      type: LeapFunctionParameterType.array(
        ArrayType(itemType: .string(StringType()))
      ),
      description: "Names of the cities to query weather for"
    ),
    LeapFunctionParameter(
      name: "unit",
      type: LeapFunctionParameterType.string(
        StringType(enumValues: ["celsius", "fahrenheit"])
      ),
      description: "Temperature unit"
    ),
  ]
)

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, use HermesFunctionCallParser.
var options = GenerationOptions()
options.functionCallParser = HermesFunctionCallParser()

for try await response in conversation.generateResponse(
  message: userMessage,
  generationOptions: options
) {
  // ...
}
Pass null / nil as the parser to disable tool-call parsing entirely β€” the raw tool-call text is then surfaced as ordinary Chunks.