Langertha-Skeid
view release on metacpan or search on metacpan
.claude/skills/langertha/SKILL.md view on Meta::CPAN
my $server = MCP::Server->new(name => 'my-tools', version => '1.0');
$server->tool(
name => 'search_files',
description => 'Search for files matching a pattern',
input_schema => {
type => 'object',
properties => {
pattern => { type => 'string', description => 'Glob pattern' },
path => { type => 'string', description => 'Directory to search' },
},
required => ['pattern'],
},
code => sub {
my ($tool, $args) = @_;
# $tool is MCP::Tool instance (NOT your class)
my @files = glob("$args->{path}/$args->{pattern}");
return $tool->text_result(join("\n", @files));
# Error: $tool->text_result("Not found", 1); # is_error=1
},
);
```
### Step 2: Create MCP client
```perl
use IO::Async::Loop;
use Net::Async::MCP;
my $loop = IO::Async::Loop->new;
my $mcp = Net::Async::MCP->new(server => $server);
$loop->add($mcp);
await $mcp->initialize;
```
### Step 3: Engine with MCP
```perl
my $engine = Langertha::Engine::Anthropic->new(
api_key => $ENV{ANTHROPIC_API_KEY},
model => 'claude-sonnet-4-6',
mcp_servers => [$mcp], # Pass MCP server(s)
);
# One-shot tool calling
my $response = await $engine->chat_with_tools_f('Find all .pm files in lib/');
say $response;
```
</tool-calling>
<raider>
## Raider â Autonomous Agent
```perl
use Langertha::Raider;
my $raider = Langertha::Raider->new(
engine => $engine, # With MCP servers
mission => 'You are a code reviewer.',
max_iterations => 10, # Max tool rounds per raid
# Optional:
max_context_tokens => 4000,
context_compress_threshold => 0.75,
compression_engine => $cheap_model,
raider_mcp => 1, # Enable self-tools (ask_user, pause, abort)
plugins => ['Langfuse'],
);
# Raid (autonomous tool-calling loop)
my $result = await $raider->raid_f('Review lib/App.pm');
# Result handling
say $result; # Stringified response
say $result->is_question; # Agent asked a question
say $result->is_abort; # Agent aborted
# Continue conversation (has context from previous raids)
my $r2 = await $raider->raid_f('Now suggest improvements.');
# Respond to question
if ($result->is_question) {
my $next = await $raider->respond_f('Yes, go ahead.');
}
# History management
$raider->add_history('user', $content); # Replay from DB
$raider->clear_history; # Reset
# Metrics
my $m = $raider->metrics;
say "Iterations: $m->{iterations}";
say "Tool calls: $m->{tool_calls}";
```
### Raid Loop (simplified)
1. Auto-compress history if context threshold exceeded
2. Gather tools from MCP servers + inline tools + self-tools
3. Build conversation: mission + history + new messages
4. Call LLM with tools
5. If tool calls: execute via MCP, add results to conversation, loop
6. If no tool calls: extract final text, persist to history, return result
7. Max iterations safety limit
</raider>
<plugins>
## Plugin System
```perl
package Langertha::Plugin::MyGuardrails;
use Langertha qw( Plugin );
async sub plugin_before_tool_call {
my ($self, $name, $input) = @_;
return if $name eq 'dangerous_tool'; # Skip tool
return ($name, $input); # Allow tool
}
async sub plugin_after_raid {
my ($self, $result) = @_;
return $result; # Transform result
}
__PACKAGE__->meta->make_immutable;
# Usage
my $raider = Langertha::Raider->new(
engine => $engine,
plugins => ['MyGuardrails', 'Langfuse'],
);
```
### Plugin Hooks (all async sub)
| Hook | Purpose |
|------|---------|
| `plugin_before_raid(@messages)` | Transform input |
| `plugin_build_conversation(@conv)` | Transform assembled conversation |
| `plugin_before_llm_call(@conv, $iter)` | Transform before each LLM call |
| `plugin_after_llm_response($data, $iter)` | Inspect LLM response |
| `plugin_before_tool_call($name, $input)` | Allow/block tool (empty = skip) |
| `plugin_after_tool_call($name, $input, $result)` | Transform tool result |
| `plugin_after_raid($result)` | Transform final result |
</plugins>
<roles>
## Composable Roles
Engines compose feature roles:
| Role | Feature |
|------|---------|
| `Langertha::Role::Chat` | `simple_chat`, `simple_chat_f` |
| `Langertha::Role::Tools` | `chat_with_tools_f` (MCP loop) |
| `Langertha::Role::Streaming` | SSE/NDJSON streaming |
| `Langertha::Role::Embedding` | Vector embeddings |
| `Langertha::Role::Transcription` | Audio-to-text |
| `Langertha::Role::ImageGeneration` | Image generation |
| `Langertha::Role::SystemPrompt` | System prompt management |
| `Langertha::Role::Temperature` | Generation parameters |
| `Langertha::Role::ResponseFormat` | JSON mode / structured output |
| `Langertha::Role::Models` | Model listing |
| `Langertha::Role::Langfuse` | Observability |
( run in 2.117 seconds using v1.01-cache-2.11-cpan-5e09290becf )