NAME

Langertha::Virtual::Rules - Helpers that build the rules of Langertha::Engine::Virtual

VERSION

version 0.504

SYNOPSIS

use Langertha::Engine::Virtual;
use Langertha::Virtual::Rules qw( answer tool tools after error );

my $engine = Langertha::Engine::Virtual->new(
  rules => [
    'Hello'                 => answer('Hi there'),
    qr/\ARead (\S+)\z/      => sub { my ( $req, $path ) = @_; tool( read_file => { path => $path } ) },
    'Look around'           => tools( [ [ bash => { command => 'ls' } ], [ bash => { command => 'pwd' } ] ] ),
    after('read_file')      => answer('I read it.'),
  ],
  fallback => answer('I do not know that one.'),
);

DESCRIPTION

Small functions that build the data Langertha::Engine::Virtual reads as reactions and triggers. They return plain Perl data, so a rule written without them works the same: answer('x') is { answer => 'x' }. Nothing is exported by default; ask for the names, or :all.

after shares its name with the Moose method modifier: import it into a test script or a plain package, not into a Moose class, or call it as Langertha::Virtual::Rules::after(...).

FUNCTIONS

answer

answer('The answer is 42.')
answer( 'The answer is 42.', usage => { prompt_tokens => 12, completion_tokens => 5 } )

The reaction "reply with this text": { answer => $text }. With usage, the reply carries that token usage (see "USAGE" in Langertha::Engine::Virtual): { answer => $text, usage => \%usage }.

tool

tool( read_file => { path => 'a.txt' } )
tool( read_file => { path => 'a.txt' }, usage => { prompt_tokens => 30, completion_tokens => 9 } )

The reaction "call this tool with these arguments": { tool_calls => [ [ $name, \%arguments ] ] }. The arguments default to {}; to give usage, pass them, even as {}.

tools

tools( [ [ read_file => { path => 'a.txt' } ], [ bash => { command => 'ls' } ] ] )
tools( [ tool( read_file => { path => 'a.txt' } ), tool( bash => { command => 'ls' } ) ] )
tools( [ [ read_file => { path => 'a.txt' } ] ], usage => { prompt_tokens => 30, completion_tokens => 18 } )

The reaction "call these tools in one turn", in order. Each element is a [ $name, \%arguments ] pair or a "tool" reaction. usage belongs to the turn, so it is given to tools; a "tool" in the list that carries one croaks.

error

error( 429, 'Rate limit reached' )

The reaction "fail like a server that answers with this status and message": { error => { status => 429, message => '...' } }. The status is an HTTP error status (400 to 599). The caller sees its usual error path: a croak from simple_chat, a failed future from the _f calls.

after

after()                                        # after any tool result
after('read_file')                             # after a read_file result
after( tool => qr/_file\z/ )                   # tool name matches
after( tool => 'bash', result => qr/Exit code: (\d+)/ )

The trigger "the last message is a tool result" - it goes on the left of a rule, after('read_file') => answer('Done.'). tool is the tool's name: a string is compared exactly, a Regexp is matched, and without it any tool counts. result does the same against the result's text. The captures of the Regexps (the tool's first, then the result's) are passed to a sub reaction. Returns { after => { tool => ..., result => ... } }.

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.