Current section
Files
Jump to
Current section
Files
lib/gemini/chat.ex
defmodule Gemini.Chat do
@moduledoc """
Formalized chat session management with immutable history updates.
This module provides a robust, immutable approach to managing multi-turn
conversations with the Gemini API, including proper handling of tool-calling
turns with function calls and responses.
## Usage
# Create a new chat session
chat = Gemini.Chat.new(model: "gemini-2.0-flash-lite", temperature: 0.7)
# Add turns to the conversation
chat = chat
|> Gemini.Chat.add_turn("user", "What's the weather like?")
|> Gemini.Chat.add_turn("model", [%Altar.ADM.FunctionCall{...}])
|> Gemini.Chat.add_turn("user", [%Altar.ADM.ToolResult{...}])
|> Gemini.Chat.add_turn("model", "Based on the weather data...")
# Generate content with the chat history
{:ok, response} = Gemini.generate_content(chat.history, chat.opts)
"""
alias Gemini.Types.Content
alias Altar.ADM.{FunctionCall, ToolResult}
@typedoc """
A chat session containing conversation history and configuration options.
"""
@type t :: %__MODULE__{
history: [Content.t()],
opts: keyword()
}
defstruct history: [], opts: []
@doc """
Create a new chat session with optional configuration.
## Options
All standard Gemini API options are supported:
- `:model` - Model name (defaults to configured default)
- `:temperature` - Generation temperature (0.0-1.0)
- `:max_output_tokens` - Maximum tokens to generate
- `:generation_config` - Full GenerationConfig struct
- `:safety_settings` - List of SafetySetting structs
- `:system_instruction` - System instruction content
- And more...
## Examples
chat = Gemini.Chat.new()
chat = Gemini.Chat.new(model: "gemini-2.5-pro", temperature: 0.3)
"""
@spec new(keyword()) :: t()
def new(opts \\ []) when is_list(opts) do
%__MODULE__{history: [], opts: opts}
end
@doc """
Add a turn to the chat history.
This function handles different types of content based on the role and message type:
- User text messages: `add_turn(chat, "user", "Hello")`
- Model text responses: `add_turn(chat, "model", "Hi there!")`
- Model function calls: `add_turn(chat, "model", [%FunctionCall{...}])`
- User function responses: `add_turn(chat, "user", [%ToolResult{...}])`
Returns a new chat struct with the updated history, preserving immutability.
"""
@spec add_turn(t(), String.t(), String.t() | [map()] | [FunctionCall.t()] | [ToolResult.t()]) ::
t()
def add_turn(%__MODULE__{} = chat, role, message) when role in ["user", "model", "tool"] do
content = build_content(role, message)
%{chat | history: chat.history ++ [content]}
end
# Build Content struct based on role and message type
defp build_content("user", message) when is_binary(message) do
Content.text(message, "user")
end
defp build_content("model", message) when is_binary(message) do
Content.text(message, "model")
end
defp build_content("model", function_calls) when is_list(function_calls) do
# Handle model's function call turn
parts =
Enum.map(function_calls, fn %FunctionCall{} = call ->
%{
function_call: %{
name: call.name,
args: call.args
}
}
end)
%Content{role: "model", parts: parts}
end
defp build_content("tool", tool_results) when is_list(tool_results) do
# Handle tool's function response turn using the Content helper
Content.from_tool_results(tool_results)
end
defp build_content(role, parts) when is_list(parts) do
# Handle generic parts list
%Content{role: role, parts: parts}
end
end