Langertha
view release on metacpan or search on metacpan
lib/Langertha/Engine/AnthropicBase.pm view on Meta::CPAN
package Langertha::Engine::AnthropicBase;
# ABSTRACT: Base class for Anthropic-compatible engines
our $VERSION = '0.502';
use Moose;
use Carp qw( croak );
use JSON::MaybeXS;
use Langertha::ToolChoice;
use Langertha::Tool;
use Langertha::Response;
use Langertha::ToolCall;
extends 'Langertha::Engine::Remote';
with map { 'Langertha::Role::'.$_ } qw(
Models
Chat
Temperature
ResponseSize
SystemPrompt
ResponseFormat
Streaming
Tools
);
sub default_response_size { 1024 }
sub content_format { 'anthropic' }
has api_key => (
is => 'ro',
lazy_build => 1,
);
sub _build_api_key {
my ( $self ) = @_;
return croak "".(ref $self)." requires api_key to be set";
}
has api_version => (
is => 'ro',
lazy_build => 1,
);
sub _build_api_version { '2023-06-01' }
has effort => (
is => 'ro',
isa => 'Str',
predicate => 'has_effort',
);
has inference_geo => (
is => 'ro',
isa => 'Str',
predicate => 'has_inference_geo',
);
sub update_request {
my ( $self, $request ) = @_;
$request->header('x-api-key', $self->api_key);
$request->header('content-type', 'application/json');
$request->header('anthropic-version', $self->api_version);
}
sub default_model { croak "".(ref $_[0])." requires model to be set" }
sub chat_request {
my ( $self, $messages, %extra ) = @_;
# Anthropic has no native response_format. Translate json_object /
# json_schema response_format hashes into a synthesized tool + forced
# named tool_choice; the response parser will pull the structured
# output out of the resulting tool_use block.
$self->_translate_response_format(\%extra);
$self->_normalize_tool_params(\%extra);
my @msgs;
my $system = "";
for my $message (@{$messages}) {
if ($message->{role} eq 'system') {
$system .= "\n\n" if length $system;
$system .= $message->{content};
} else {
push @msgs, $message;
}
}
if ($system and scalar @msgs == 0) {
push @msgs, {
role => 'user',
content => $system,
};
$system = undef;
}
return $self->generate_http_request( POST => $self->url.'/v1/messages', sub { $self->chat_response(shift) },
model => $self->chat_model,
messages => \@msgs,
max_tokens => $self->get_response_size, # must be always set
$self->has_temperature ? ( temperature => $self->temperature ) : (),
$self->has_effort ? ( effort => $self->effort ) : (),
$self->has_inference_geo ? ( inference_geo => $self->inference_geo ) : (),
$system ? ( system => $system ) : (),
%extra,
);
}
# Anthropic has no response_format; emulate via a synthetic tool plus
# a forced tool_choice. The response_call will detect the synthetic
# tool_use block and lift its input back into the response content.
my $SYNTH_RF_TOOL_NAME = '__langertha_response_format__';
sub _translate_response_format {
my ( $self, $extra ) = @_;
return unless $self->has_response_format;
my $rf = $self->response_format;
return unless ref($rf) eq 'HASH';
my $type = $rf->{type} // '';
my ( $name, $schema, $description );
( run in 1.937 second using v1.01-cache-2.11-cpan-75ffa21a3d4 )