NAME

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

VERSION

version 0.202

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.

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.