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.
Swift (iOS / macOS)
Kotlin (all platforms)
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)"
),
]
)
)
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",
),
),
),
)
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.
Swift (iOS / macOS)
Kotlin (all platforms)
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
}
}
data class LeapFunctionCall(
val name: String,
val arguments: Map<String, Any?>,
)
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.
The model may emit missing or invalid arguments β defensively validate the arguments map against your toolβs expected shape before dispatching.
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.
Swift (iOS / macOS)
Kotlin (all platforms)
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)
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)
Then call generateResponse(...) on the new conversation to get the modelβs tool-aware reply.
LeapFunction
Swift (iOS / macOS)
Kotlin (all platforms)
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
}
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,
)
Parameter types
LeapFunctionParameterType is translated into JSON Schema for the model. The same primitive set is exposed on both platforms.
Swift (iOS / macOS)
Kotlin (all 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).
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.
Example: array + enum parameters
Swift (iOS / macOS)
Kotlin (all platforms)
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"
),
]
)
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",
),
),
)
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.
Swift (iOS / macOS)
Kotlin (all platforms)
var options = GenerationOptions()
options.functionCallParser = HermesFunctionCallParser()
for try await response in conversation.generateResponse(
message: userMessage,
generationOptions: options
) {
// ...
}
val options = GenerationOptions.build {
functionCallParser = HermesFunctionCallParser()
}
conversation.generateResponse(userMessage, options).onEach { /* ... */ }.collect()
Pass null / nil as the parser to disable tool-call parsing entirely β the raw tool-call text is then surfaced as ordinary Chunks.