Nous.Messages.Gemini (nous v0.16.3)

View Source

Gemini format message conversion.

Handles conversion between internal Message structs and Google Gemini API format.

Summary

Functions

Build Vertex's tools array from function declarations and native tools.

Convert Gemini format messages to internal Message structs.

Parse Gemini response into a Message.

Derive Gemini's responseMimeType/responseSchema pair from generic settings.

Normalize a list of safety settings into Vertex's safetySettings shape.

Normalize a Nous-shaped thinking_config into Gemini's thinkingConfig.

Normalize a :tool_choice setting into Vertex's toolConfig shape.

Parse a Gemini-format usageMetadata map into a %Nous.Usage{} struct.

Convert messages to Gemini format.

Functions

build_tools(function_declarations, native_tools)

@spec build_tools([map()], [atom() | tuple() | map()] | nil) :: [map()] | nil

Build Vertex's tools array from function declarations and native tools.

  • function_declarations — list of Gemini-shaped function declarations (already converted via Nous.ToolSchema.to_gemini/1). May be empty.
  • native_tools — list of native Vertex tools, each one of:
    • :google_search
    • :url_context
    • :code_execution
    • {atom_or_string, %{config}} — for tools that take configuration
    • a raw map — passed through (e.g. %{"googleSearch" => %{}})

Returns nil when both lists are empty so callers can maybe_put.

from_messages(gemini_messages)

@spec from_messages([map()]) :: [Nous.Message.t()]

Convert Gemini format messages to internal Message structs.

from_response(response)

@spec from_response(map()) :: Nous.Message.t()

Parse Gemini response into a Message.

Examples

iex> response = %{"candidates" => [%{"content" => %{"parts" => [%{"text" => "Hello"}]}}]}
iex> Messages.Gemini.from_response(response)
%Message{role: :assistant, content: "Hello"}

json_config_for_settings(settings)

@spec json_config_for_settings(map() | keyword()) :: map()

Derive Gemini's responseMimeType/responseSchema pair from generic settings.

Honors three settings keys, in priority order:

  • :json_schema (map) — forces JSON mime type and sets the schema.
  • :response_format (map) — accepts %{type: :json_schema, schema: schema} or %{type: :json_object} for cross-provider consistency.
  • :json_response (boolean) — forces JSON mime type without a schema.

Returns a map with "responseMimeType" and (optionally) "responseSchema", or %{} when none apply.

normalize_safety_settings(settings)

@spec normalize_safety_settings([map()] | nil) :: [map()] | nil

Normalize a list of safety settings into Vertex's safetySettings shape.

Accepts atom-keyed (%{category: ..., threshold: ...}) or string-keyed (%{"category" => ..., "threshold" => ...}) entries. Passes unknown keys through so newer Vertex fields (e.g. "method") work without a library bump. Returns nil for nil input.

normalize_thinking_config(config)

@spec normalize_thinking_config(map() | nil) :: map() | nil

Normalize a Nous-shaped thinking_config into Gemini's thinkingConfig.

Accepts either the Elixir shape (%{thinking_budget: 1024, include_thoughts: true}) or the native Vertex shape (%{"thinkingBudget" => 1024, "includeThoughts" => true}). Returns nil when the input is nil.

Unrecognized keys are passed through unchanged so newer Vertex fields work without a library bump.

normalize_tool_choice(map)

@spec normalize_tool_choice(atom() | tuple() | map() | nil) :: map() | nil

Normalize a :tool_choice setting into Vertex's toolConfig shape.

Accepts:

  • :auto → mode AUTO
  • :any / :required → mode ANY (model must call a function)
  • :none → mode NONE
  • {:any, ["name_a", ...]} → mode ANY with allowedFunctionNames
  • a raw map (passed through as-is)
  • nil (returns nil)

parse_usage(usage_data)

@spec parse_usage(map() | nil) :: Nous.Usage.t()

Parse a Gemini-format usageMetadata map into a %Nous.Usage{} struct.

Used by both the non-streaming response parser and the streaming normalizer.

to_format(messages)

@spec to_format([Nous.Message.t()]) :: {String.t() | nil, [map()]}

Convert messages to Gemini format.

Returns {system_prompt, contents} where system prompt is extracted and messages are converted to Gemini contents format.

Examples

iex> messages = [Message.system("Be helpful"), Message.user("Hello")]
iex> Messages.Gemini.to_format(messages)
{"Be helpful", [%{"role" => "user", "parts" => [%{"text" => "Hello"}]}]}