# `ConduitMcp.Client.Adapters.Gemini`
[🔗](https://github.com/nyo16/conduit_mcp/blob/v0.11.0/lib/conduit_mcp/client/adapters/gemini.ex#L1)

Converts between a `ConduitMcp.Client.ToolSet` and Gemini API
(`generateContent`) function calling. Pure functions over string-keyed
maps; no HTTP.

> #### Experimental {: .warning}
>
> This adapter is experimental: its shapes come from the Gemini API
> reference, not from end-to-end runs against the API, and may change in
> a minor release.

    {toolset, _} = ConduitMcp.Client.Naming.build([{"files", tools}])
    request = %{"contents" => contents,
                "tools" => [%{"functionDeclarations" => Gemini.function_declarations(toolset)}]}

    {calls, rejected} = Gemini.function_calls(response, toolset)
    # run each %ToolCall{} through the client pipeline (or let
    # ConduitMcp.Client.Adapters.execute_tool_calls/4 do all of this), then:
    parts = Enum.map(outcomes, fn {call, outcome} ->
      {:ok, name} = ConduitMcp.Client.ToolSet.exposed_name(toolset, call.server_id, call.name)
      Gemini.function_response(name, outcome, id: call.call_id)
    end)
    # next turn: %{"role" => "user", "parts" => rejected ++ parts}

## Verified rules (2026-10-17)

From the `FunctionDeclaration`, `FunctionCall` and `FunctionResponse`
reference at https://ai.google.dev/api/generate-content and the guide at
https://ai.google.dev/gemini-api/docs/function-calling:

  * `FunctionDeclaration.name` may contain `a-z A-Z 0-9 _ : . -`, at most
    128 characters. The toolset's exposed names (`^[A-Za-z0-9_-]{1,64}$`)
    are a subset.
  * `parametersJsonSchema` takes the parameters as JSON Schema (an object
    schema); `parameters` takes the OpenAPI 3.0 `Schema` subset instead.
    The two are mutually exclusive. This adapter sends the MCP
    `inputSchema` unchanged as `parametersJsonSchema`.
  * `description` is required, so a tool without one gets `""`.
  * `FunctionCall` is `{id?, name, args?}`; `FunctionResponse` is
    `{id?, name, response}` where `response` must be a JSON object. By the
    reference's convention the output goes under `"output"` and a failure
    under `"error"`.

## Results

`function_response/3` puts the result under `response.output`: the
`structuredContent` object when present (default `structured: :prefer`),
otherwise the content as text, with media as placeholders such as
`"[image: image/png, 1024 bytes]"`. A result with `is_error: true`, or a
`ConduitMcp.Client.Error`, goes under `response.error` as text.
Descriptions have invisible characters removed and are capped at 4 KiB
(PI-1); only tools in the toolset are emitted (PO-7).

# `function_calls`

```elixir
@spec function_calls(map() | [map()], ConduitMcp.Client.ToolSet.t()) ::
  {[ConduitMcp.Client.ToolCall.t()], [map()]}
```

Extracts the function calls from a response.

Accepts a `generateContent` response (the first candidate's content is
used), a `Content` (`"parts"`), or a list of parts. Each `functionCall`
part whose `name` resolves in `toolset` becomes a
`ConduitMcp.Client.ToolCall` with `call_id` set to the call's `id` (which
Gemini may omit, giving `nil`).

A call naming a tool not in the toolset, or with `args` that are not an
object, produces no call (HB-2). Instead it yields a `functionResponse`
part with an `"error"`, returned in the second list, to send back to the
model. Other parts are ignored.

# `function_declarations`

```elixir
@spec function_declarations(ConduitMcp.Client.ToolSet.t()) :: [map()]
```

The `functionDeclarations` for `toolset`, in toolset order. Wrap them as
`%{"functionDeclarations" => declarations}` in the request's `tools`.

# `function_response`

```elixir
@spec function_response(
  String.t(),
  ConduitMcp.Client.ToolResult.t() | ConduitMcp.Client.Error.t(),
  keyword()
) :: map()
```

Builds the `functionResponse` part answering a call to `name` (the
exposed name the model used).

## Options

  * `:id` - the `functionCall.id` being answered, when Gemini sent one.
  * `:structured` - `:prefer` (default) sends `structuredContent` itself
    as `output` when present; `:auto`, `:append` and `:ignore` render the
    content as text, handling `structuredContent` as described in
    `ConduitMcp.Client.Adapters.OpenAI.tool_output/3`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
