NAME

Langertha::Engine::Gemini - Google Gemini API

VERSION

version 0.503

SYNOPSIS

use Langertha::Engine::Gemini;

my $gemini = Langertha::Engine::Gemini->new(
    api_key      => $ENV{GEMINI_API_KEY},
    model        => 'gemini-3-flash-preview',
    response_size => 4096,
    temperature  => 0.7,
);

# Simple chat
my $response = $gemini->simple_chat('Explain quantum computing in simple terms');
print $response;

# Streaming
$gemini->simple_chat_stream(sub {
    my ($chunk) = @_;
    print $chunk->content;
}, 'Write a poem about Perl');

# Async with Future::AsyncAwait
use Future::AsyncAwait;

async sub ask_gemini {
    my $response = await $gemini->simple_chat_f(
        'What are the benefits of functional programming?'
    );
    say $response;
}

# Embeddings (gemini-embedding-001 unless embedding_model is set)
my $vector  = $gemini->simple_embedding('Some text to embed');
my $vectors = $gemini->simple_embedding([ 'first', 'second' ]);

DESCRIPTION

Provides access to Google's Gemini models via the Generative Language API. Gemini models support multimodal input (text, code, images) and long context windows.

Available models include the current stable Flash line gemini-3.8-flash and gemini-3.7-flash (thinkingLevel low|medium|high, no minimal), the gemini-3-flash-preview default (fast with thinking, and still accepts thinkingLevel=minimal), gemini-3.1-pro-preview (most capable), gemini-3.1-flash-lite (cost-efficient workhorse), and the image-generation models gemini-3.1-flash-image-preview and gemini-3-pro-image-preview. The gemini-2.5-* generation is still served but now classed as previous-generation. The default API endpoint is https://generativelanguage.googleapis.com.

Embeddings (Langertha::Role::Embedding) use gemini-embedding-001 by default; gemini-embedding-2 embeds into a different, incompatible vector space, so do not mix vectors of the two. See "embedding_request" for task_type and output_dimensionality.

THIS API IS WORK IN PROGRESS

api_key

The Google Generative Language API key. If not provided, reads from LANGERTHA_GEMINI_API_KEY environment variable. Get your key at https://aistudio.google.com/app/apikey. Required for the Developer API.

Pass api_key => undef explicitly to send no key at all (a keyless proxy or gateway in front of Gemini): the environment variable is then not read, no key query parameter is added to any URL, and nothing warns. Leaving api_key out keeps the default: environment variable, croak when unset.

cached_content

Optional Langertha::CachedContent resource bound to this engine. When set, every chat request (chat, chat_stream, simple_chat_f, …) injects cachedContent => '{name}' into the generateContent body so the model serves the request against the cached context.

A request that names a cache takes its system instruction, tools and tool configuration from the cache: Gemini rejects a generateContent request that sets systemInstruction, tools or toolConfig next to cachedContent (HTTP 400). While a cache is bound those three are therefore not sent, even when the engine's system_prompt, a system message, tools or tool_choice would set them, and the engine carps once. Put them into the cache when creating it ("system_instruction" in Langertha::CachedContent, "tools" in Langertha::CachedContent).

Lifecycle (create / get / list / update / delete) is on the role — "create_cached_content_f" in Langertha::Role::CachedContent and friends. Bind a freshly created resource with $engine->cached_content($cc).

Source URL: https://ai.google.dev/api/generate-content (the cachedContent field on a generateContent body).

gemini_api_version

The API version segment of every endpoint, v1beta for the Generative Language API. Override in a subclass serving a different version. Tool declarations are sent as parametersJsonSchema, which v1 does not have.

gemini_auth_query

The auth seam: returns the credential as a ( name => value ) query pair list, ( key => $self->api_key ) for the Developer API, or the empty list when api_key is undef or empty. A consumer that authenticates by header instead returns the empty list here and sets the header in update_request.

gemini_endpoint

Composes the credential-free endpoint {url}/{gemini_api_version}/{path}. This is the path half of the seam: a consumer whose resources live under an extra prefix (Vertex AI's projects/{p}/locations/{l}/) overrides this one method and every request URL follows. Callers that are about to issue a request want "gemini_url" instead — this one carries no credential.

gemini_url

Builds "gemini_endpoint" and appends the query string: first the pairs from "gemini_auth_query", then any ( name => value ) pairs passed by the caller (e.g. alt => 'sse').

gemini_model_url

Builds the endpoint of one model method, models/{model}:{method}, via "gemini_url". The models/ prefix lives here so a consumer with a different resource path (Vertex AI's publishers/google/models/) overrides one method.

The chat routes pass chat_model as {model}, or a per-request model (from "chat_f" in Langertha::Role::Chat or "model" in Langertha::Chat) for that request; the override is not sent in the body.

embedding_request

my $request = $engine->embedding_request($text, %extra);
my $request = $engine->embedding_request(\@texts,
    task_type => 'RETRIEVAL_DOCUMENT', output_dimensionality => 768);

Builds an embedding request with embedding_model (default gemini-embedding-001). A string goes to models/{model}:embedContent, an ArrayRef of strings to models/{model}:batchEmbedContents as one request per input. The optional task_type, title and output_dimensionality are placed in embedContentConfig (as taskType, title, outputDimensionality), merged with an embedContentConfig you pass yourself; any other key goes into each request unchanged. In a batch every input gets the same settings. "embedding_dimensions" in Langertha::Role::Embedding, when set, is sent as outputDimensionality unless the call passes one.

embedding_response

my $vector  = $engine->embedding_response($http_response);
my $vectors = $engine->embedding_response($http_response, \@texts);

Parses an embedding answer; the parser built by "embedding_request" passes the input itself. For a string it returns embedding.values, for an ArrayRef input embeddings[].values, one vector per input in input order. A count that does not match the number of inputs croaks, and so does a body without a vector, naming the engine and any error it carries; it never returns undef.

chat_response

my $response = $engine->chat_response($http_response);

Parses a generateContent answer into a Langertha::Response from the first candidate; finish_reason is its finishReason as Gemini spells it. A blocked prompt (no candidate, promptFeedback.blockReason) is an answer with content '' and the blockReason as finish_reason (e.g. SAFETY). A body with neither croaks, naming the engine and any error it carries. On a stream, the blocked prompt's chunk is the final chunk, with content '' and the blockReason as finish_reason. A stream chunk with a top-level error object croaks "<engine> stream carried an error: <message> (<code>)", which fails the stream.

list_models

my $model_ids = $engine->list_models;
my $models    = $engine->list_models(full => 1);
my $models    = $engine->list_models(force_refresh => 1);

Fetches available models from the Gemini API using token pagination. Returns an ArrayRef of model ID strings (with the models/ prefix stripped) by default, or full model objects when full = 1> is passed. Results are cached for models_cache_ttl seconds (default: 3600).

SEE ALSO

SUPPORT

Issues

Please report bugs and feature requests on GitHub at https://github.com/Getty/langertha/issues.

IRC

Join #langertha on irc.perl.org or message Getty directly.

CONTRIBUTING

Contributions are welcome! Please fork the repository and submit a pull request.

AUTHOR

Torsten Raudssus <getty@cpan.org>

COPYRIGHT AND LICENSE

This software is copyright (c) 2026 by Torsten Raudssus https://raudssus.de/.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.