NAME

Langertha::Role::OpenAICompatible - Role for OpenAI-compatible API format

VERSION

version 0.300

SYNOPSIS

# This role is not used directly - it's composed by engines
# that implement the OpenAI-compatible API format.

package My::Engine;
use Moose;

with 'Langertha::Role::'.$_ for (qw(
    JSON HTTP OpenAICompatible OpenAPI Models Temperature
    ResponseSize SystemPrompt Streaming Chat
));
with 'Langertha::Role::Tools';

sub _build_api_key { $ENV{MY_API_KEY} || die "needs api_key" }
sub default_model { 'my-model' }

__PACKAGE__->meta->make_immutable;

DESCRIPTION

This role provides the OpenAI API format methods for chat completions, embeddings, transcription, streaming, and tool calling. Engines that use the OpenAI-compatible API format (whether OpenAI itself, Ollama's /v1 endpoint, or other compatible providers) can compose this role instead of inheriting from Langertha::Engine::OpenAI.

The role provides default implementations for all OpenAI-format operations. Engines can override individual methods to customize behavior (e.g., different operation IDs for Mistral, or disabling unsupported features).

Engines should also compose these roles:

Engines using this role: Langertha::Engine::OpenAI, Langertha::Engine::DeepSeek, Langertha::Engine::Groq, Langertha::Engine::Mistral, Langertha::Engine::vLLM, Langertha::Engine::NousResearch, Langertha::Engine::Perplexity, Langertha::Engine::OllamaOpenAI, Langertha::Engine::AKIOpenAI.

api_key

Optional API key for Bearer token authentication. Override _build_api_key in engines that require authentication (typically from an environment variable). When undef, no Authorization header is sent.

update_request

$role->update_request($http_request);

Adds Authorization: Bearer {api_key} header to outgoing requests when an API key is configured. Skipped when api_key is undef (e.g. for local servers like vLLM or llama.cpp).

openapi_file

my ($type, $path) = $role->openapi_file;

Returns the OpenAI OpenAPI spec file path used for request generation. Override in an engine to use a provider-specific spec (e.g., Mistral).

list_models_request

my $request = $engine->list_models_request;

Generates an HTTP GET request for the /v1/models endpoint. Returns an HTTP request object.

list_models_response

my $models = $engine->list_models_response($http_response);

Parses the /v1/models response. Returns an ArrayRef of model objects (each with at least an id field).

list_models

my $model_ids = $engine->list_models;
# Returns: ['gpt-4o', 'gpt-4o-mini', ...]

my $models = $engine->list_models(full => 1);
# Returns: [{id => 'gpt-4o', created => ..., ...}, ...]

my $fresh = $engine->list_models(force_refresh => 1);

Fetches available models from the /v1/models endpoint with caching. By default returns an ArrayRef of model ID strings. Pass full => 1 for full model objects. Results are cached for models_cache_ttl seconds (default: 3600). Pass force_refresh => 1 to bypass the cache.

embedding_request

my $request = $engine->embedding_request($input, %extra);

Generates an OpenAI-format embedding request for the given $input string. Uses embedding_model (default: text-embedding-3-large). Returns an HTTP request object.

embedding_response

my $vector = $engine->embedding_response($http_response);

Parses an OpenAI-format embedding response. Returns an ArrayRef of floats representing the embedding vector.

chat_request

my $request = $engine->chat_request($messages, %extra);

Generates an OpenAI-format chat completion request. Includes model, messages, max_tokens, temperature, response_format (if set), and stream => false. Returns an HTTP request object.

chat_response

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

Parses an OpenAI-format chat completion response. Returns a Langertha::Response object with content, model, finish_reason, usage, created, and raw.

transcription_request

my $request = $engine->transcription_request($file_path, %extra);

Generates an OpenAI-format transcription request for the given audio file. Uses transcription_model (default: whisper-1). Returns an HTTP request object.

transcription_response

my $text = $engine->transcription_response($http_response);

Parses an OpenAI-format transcription response. Returns the transcribed text as a string.

stream_format

my $format = $engine->stream_format;

Returns 'sse' (Server-Sent Events), indicating the streaming format used by OpenAI-compatible APIs. Used by Langertha::Role::Chat to select the correct stream parser.

chat_stream_request

my $request = $engine->chat_stream_request($messages, %extra);

Generates an OpenAI-format streaming chat request (stream => true). Returns an HTTP request object for use with streaming execution.

parse_stream_chunk

my $chunk = $engine->parse_stream_chunk($data, $event);

Parses a single SSE data payload from an OpenAI-format stream. Returns a Langertha::Stream::Chunk with content, is_final, finish_reason, model, and usage, or undef if the chunk has no content.

format_tools

my $tools = $engine->format_tools($mcp_tools);

Converts an ArrayRef of MCP tool definitions to OpenAI function calling format. Each tool becomes { type => 'function', function => { name, description, parameters } }.

response_tool_calls

my $tool_calls = $engine->response_tool_calls($raw_data);

Extracts the tool call objects from a raw OpenAI-format response hashref. Returns an ArrayRef of tool call objects (may be empty).

extract_tool_call

my ($name, $args) = $engine->extract_tool_call($tool_call);

Extracts the function name and decoded argument hashref from a single OpenAI tool call object. JSON-decodes the arguments string if needed.

response_text_content

my $text = $engine->response_text_content($raw_data);

Extracts the assistant message text content from a raw OpenAI-format response hashref. Returns an empty string if no content.

format_tool_results

my @messages = $engine->format_tool_results($raw_data, $results);

Converts tool execution results into OpenAI-format messages to append to the conversation. Returns a list: first the assistant message (with tool calls), then one role => 'tool' message per result.

image_request

my $request = $engine->image_request($prompt, %extra);

Generates an OpenAI-format image generation request for the given $prompt. Uses image_model (default: gpt-image-1). Accepts optional size, quality, n, response_format via %extra. Returns an HTTP request object.

image_response

my $images = $engine->image_response($http_response);

Parses an OpenAI-format image generation response. Returns an ArrayRef of image objects, each with url or b64_json and optionally revised_prompt.

simple_image

my $images = $engine->simple_image('A cat in space');

Sends an image generation request and returns the result. Blocks until the request completes. Returns an ArrayRef of image objects.

SEE ALSO

SUPPORT

Issues

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

CONTRIBUTING

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

AUTHOR

Torsten Raudssus <torsten@raudssus.de> https://raudss.us/

COPYRIGHT AND LICENSE

This software is copyright (c) 2026 by Torsten Raudssus.

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