Gemini.Tools.AutomaticFunctionCalling (GeminiEx v0.8.4)
View SourceImplements the Automatic Function Calling (AFC) loop for Gemini.
AFC automatically executes function calls from Gemini responses and continues the conversation until no more function calls are needed or limits are reached.
How It Works
- Send initial request to Gemini with tools defined
- Check if response contains function calls
- If yes, execute function calls against the registry
- Build function response content
- Send new request with function results
- Repeat until no more function calls or max_calls reached
Configuration
Use config/1 to create an AFC configuration:
config = AFC.config(
max_calls: 10, # Maximum function calls before stopping
ignore_call_history: false, # Whether to track call history
enabled: true # Enable/disable AFC
)Usage with Coordinator
AFC is typically used through the high-level API:
# Define tools
tools = [
%FunctionDeclaration{
name: "get_weather",
description: "Get current weather",
parameters: %{type: "object", properties: %{"location" => %{type: "string"}}}
}
]
# Define registry
registry = %{
"get_weather" => fn args -> WeatherService.get(args["location"]) end
}
# Generate with AFC
{:ok, response} = Gemini.generate(
"What's the weather in NYC?",
tools: tools,
auto_execute_tools: true,
tool_registry: registry
)Manual AFC Loop
For more control, you can use the AFC functions directly:
response = initial_response
history = []
call_count = 0
config = AFC.config(max_calls: 5)
{final_response, call_count, history} =
AFC.loop(response, contents, registry, config, call_count, history, generate_fn)
Summary
Functions
Build content containing function responses for the API.
Create an AFC configuration.
Extract function calls from a Gemini API response.
Extract model content from a response in API-compatible format.
Check if a response contains function calls.
Execute the AFC loop.
Determine if the AFC loop should continue.
Track function call history.
Types
@type call_history() :: [Altar.ADM.FunctionCall.t()]
@type config() :: Gemini.Tools.AutomaticFunctionCalling.Config.t()
Functions
@spec build_function_response_content([Altar.ADM.FunctionCall.t()], [ Gemini.Tools.Executor.execution_result() ]) :: map()
Build content containing function responses for the API.
Parameters
calls: List of executed FunctionCall structsresults: List of execution results from Executor
Returns
A content map with role "function" and function response parts.
@spec config(keyword()) :: Gemini.Tools.AutomaticFunctionCalling.Config.t()
Create an AFC configuration.
Options
:max_calls- Maximum number of function calls to execute (default: 10):ignore_call_history- If true, don't track call history (default: false):enabled- Enable or disable AFC (default: true):parallel_execution- Execute multiple calls in parallel (default: false)
Examples
# Default configuration
config = AFC.config()
# Custom configuration
config = AFC.config(max_calls: 5, parallel_execution: true)
# Disable AFC
config = AFC.config(enabled: false)
@spec extract_function_calls(map()) :: [Altar.ADM.FunctionCall.t()]
Extract function calls from a Gemini API response.
Parameters
response: Raw API response map or GenerateContentResponse struct
Returns
List of FunctionCall structs.
Examples
calls = AFC.extract_function_calls(response)
[%FunctionCall{name: "get_weather", args: %{"location" => "NYC"}}] = calls
Extract model content from a response in API-compatible format.
This is useful for multi-turn conversations where you need to include the model's response (including function calls) in the conversation history.
Parameters
response: A GenerateContentResponse struct or raw API response map
Returns
A map with role: "model" and parts in API format (camelCase keys).
Examples
# Get model content for conversation history
model_content = AFC.extract_model_content_for_api(response)
contents = [user_content, model_content, function_response_content]
Check if a response contains function calls.
Examples
if AFC.has_function_calls?(response) do
# Handle function calls
end
@spec loop( map(), list(), Gemini.Tools.Executor.function_registry(), Gemini.Tools.AutomaticFunctionCalling.Config.t(), non_neg_integer(), call_history(), generate_fn(), keyword() ) :: {map(), non_neg_integer(), call_history()}
Execute the AFC loop.
This is the main entry point for automatic function calling. It:
- Checks if response contains function calls
- Executes them against the registry
- Builds function response content
- Calls the generate function with updated contents
- Repeats until done or limits reached
Parameters
response: Initial Gemini responsecontents: Current conversation contentsregistry: Function registry mapconfig: AFC configurationcall_count: Current call count (usually 0)history: Call history (usually [])generate_fn: Function to call Gemini API
Returns
{final_response, final_call_count, final_history}
Examples
generate_fn = fn contents, opts ->
Gemini.APIs.Coordinator.generate_content(contents, opts)
end
{response, call_count, history} =
AFC.loop(initial_response, contents, registry, config, 0, [], generate_fn)
@spec should_continue?( map(), Gemini.Tools.AutomaticFunctionCalling.Config.t(), non_neg_integer() ) :: boolean()
Determine if the AFC loop should continue.
Returns true if:
- AFC is enabled
- Response contains function calls
- Call count is below max_calls limit
Parameters
response: The current Gemini responseconfig: AFC configurationcall_count: Current number of executed calls
Examples
if AFC.should_continue?(response, config, call_count) do
# Continue AFC loop
end
@spec track_history(call_history(), [Altar.ADM.FunctionCall.t()]) :: call_history()
Track function call history.
Parameters
history: Current call historycalls: New calls to add
Returns
Updated history with new calls appended.