Not all models support function calling. Please check the model card before using the model for function calling.
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 image and audio parts to your messages and tool responses.
Register Functions to Conversations
To enable function calling, function definitions should be registered to the Conversation instance before content generation.
Conversation.registerFunction takes a LeapFunction instance as the input, which describes the name, parameters, and ability of the function.
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.String(),
description = "The city name",
),
),
),
)
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)"
),
]
)
)
Generally speaking, function names and parameter names should be normal identifiers that are recognized by most common programming languages (e.g. Python, JavaScript, etc.).
We recommend using descriptive names composed of only letters, underscores, and digits (not starting with digits).
Handle Function Calling Response
Function calling requests by the model are returned as part of the response stream from generateResponse. Each platform represents them differently:
On Android, function call requests arrive as a MessageResponse.FunctionCalls instance containing a list of function calls.data class FunctionCalls(val functionCalls: List<LeapFunctionCall>): MessageResponse
Each LeapFunctionCall instance contains the name and arguments of the function call request. The arguments field is a map from String to Any?.
The app needs to check whether the required parameters are filled by the model. It is possible (even though very unlikely) that some
parameters are missing or the function name is invalid.data class LeapFunctionCall(
val name: String,
val arguments: Map<String, Any?>,
)
To handle the function call response, add a new branch to match responses from the generateResponse flow:conversation.generateResponse(userMessage).onEach { response ->
when (response) {
is MessageResponse.Chunk -> {
// process text chunk
}
is MessageResponse.FunctionCalls {
response.functionCalls.forEach { call ->
// Process function calls here
Log.d(TAG, "Call function: ${call.name}, arguments: ${call.arguments}")
}
}
else -> {
// other responses
}
}
The function calls are also included in the assistant message generated by the model, so it is possible to delay function call processing until generation is complete:conversation.generateResponse(userMessage).onEach { response ->
when (response) {
is MessageResponse.Complete -> {
val assistantMessage = response.fullMessage
val functionCalls = assistantMessage.functionCalls
functionCalls?.forEach { call ->
// process function calls here
Log.d(TAG, "Call function: ${call.name}, arguments: ${call.arguments}")
}
}
else -> {
// process chunks
}
}
}
On iOS, function call requests arrive as the .functionCall([LeapFunctionCall]) case of the MessageResponse enum.public enum MessageResponse {
case functionCall([LeapFunctionCall])
// ...
}
Each LeapFunctionCall instance contains the name and arguments of the function call request. The arguments field is a map from String to Any?.
The app needs to check whether the required parameters are filled by the model. It is possible (even though very unlikely) that some
parameters are missing or the function name is invalid.public struct LeapFunctionCall {
public let name: String
public let arguments: [String: Any?]
}
To handle the function call response, add a new branch to match responses from the generateResponse flow:let userMessage = ChatMessage(role: .user, content: [.text("What's the weather in NYC?")])
for try await response in conversation.generateResponse(
message: userMessage
) {
switch response {
case .functionCall(let calls):
for call in calls {
// process function call here
print("Function call: \(call.name), \(call.arguments)")
}
case .audioSample:
break // Optional: route audio output elsewhere
default:
// process other responses
break
}
}
Function Definition
Functions for models to call are defined by LeapFunction instances. A LeapFunction has three fields: name, description, and parameters.
data class LeapFunction(
val name: String,
val description: String,
val parameters: List<LeapFunctionParameter>,
)
public struct LeapFunction: Equatable {
public let name: String
public let description: String
public let parameters: [LeapFunctionParameter]
}
name is the function name. It is recommended to use only English letters, underscores, and digits (not starting with digits) because this format is supported by most models.
description tells the model what this function does.
parameters declares what arguments the function accepts.
LeapFunctionParameter
The items of parameters are instances of LeapFunctionParameter.
data class LeapFunctionParameter(
val name: String,
val type: LeapFunctionParameterType,
val description: String,
val optional: Boolean = false,
)
public struct LeapFunctionParameter: Equatable {
public let name: String
public let type: LeapFunctionParameterType
public let description: String
public let optional: Bool
}
name β The name of the parameter.
type β Data type of the parameter.
description β Tells the model what this parameter is about.
optional β Whether the parameter is optional.
LeapFunctionParameterType
LeapFunctionParameterType describes the data types of the parameters. They are translated into JSON Schema for the model to understand.
The following types are supported:
LeapFunctionParameterType.String(enumValues: List<kotlin.String>? = null, description: kotlin.String? = null)
LeapFunctionParameterType.Number(enumValues: List<kotlin.Number>? = null, description: kotlin.String? = null)
LeapFunctionParameterType.Integer(enumValues: List<Int>? = null, description: kotlin.String? = null)
LeapFunctionParameterType.Boolean(description: kotlin.String? = null)
LeapFunctionParameterType.Array(itemType: LeapFunctionParameterType, description: kotlin.String? = null)
LeapFunctionParameterType.Object(
properties: Map<kotlin.String, LeapFunctionParameterType>,
required: List<kotlin.String> = listOf(),
description: kotlin.String? = null,
)
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)
}
- String β String literals. Accepts optional
enumValues to restrict valid values.
- Number β Number literals including integers and floating point numbers. Accepts optional
enumValues.
- Integer β Integer literals. Accepts optional
enumValues.
- Boolean β Boolean literals.
- Array β Arrays of a defined type. The
itemType parameter describes the data type of its items.
- Object β Objects with their own properties.
properties maps property names to their data types. required lists the names of all non-optional properties.
All types accept an optional description, but it will be overridden if the type is used directly as LeapFunctionParameter.type. The description only takes effect when the type instance is used as Array.itemType or as a type within object properties.
Comprehensive Example
LeapFunction(
name = "get_weather",
description = "Get the weather forecast of cities",
parameters = listOf(
LeapFunctionParameter(
name = "cities",
type = LeapFunctionParameterType.Array(
itemType = LeapFunctionParameterType.String()
),
description = "City names to query",
),
LeapFunctionParameter(
name = "temperature_unit",
type = LeapFunctionParameterType.String(
enumValues = listOf(
"Fahrenheit", "Celsius", "Kelvin"
)
),
description = "Units for temperature",
),
),
)
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 (celsius or fahrenheit)"
),
]
)
Function Call Parser
Function call parsers translate the modelβs tool-call tokens into LeapFunctionCall values. Different models emit tool calls in different formats, so you need to use the parser that matches your checkpoint.
By default, LFMFunctionCallParser is used. It supports Liquid Foundation Model (LFM2) Pythonic-style control tokens.
For Qwen3 models and other models that use the Hermes function calling format,
apply HermesFunctionCallParser by injecting a parser instance on the generation options:
val options = GenerationOptions.build {
functionCallParser = HermesFunctionCallParser()
}
conversation.generateResponse(userMessage, options).onEach {
// process message response here
}
var options = GenerationOptions()
options.functionCallParser = HermesFunctionCallParser()
for try await response in conversation.generateResponse(
message: userMessage,
generationOptions: options
) {
// process message response here
}