← Laragents 18 / 18

Reference

Laragents

Everything is optional and everything has a default. Call none of it and you get a package that talks to OpenAI, meters nothing, redacts nothing, and has the two memory tools.

Laragents::tools($classOrArray) Add tools to the catalogue. Class names resolve through the container.
Laragents::skills($classOrArray) Add skills. Held as class names, resolved lazily.
Laragents::talkWith($client) Which ChatClient answers by default.
Laragents::meterWith($recorder) Who records what a run spends. Bound scoped.
Laragents::redactWith($redactor) Who keeps personal data out of what leaves.
Laragents::speakWith($speaker) Text to speech. Nothing in the package calls it.
Laragents::drawWith($illustrator) Images. Nothing in the package calls it.

AgentLoop

$loop->run(
    array $messages,
    string $model,
    ChatSession $session,
    ToolContext $context,
    array $tools = [],
    bool $persist = true,
    array $capabilities = [],
): Response

Override to change behaviour:

outbound(array $messages): array Messages on the way to the provider.
inbound(string $content): string The model's text on the way back.
inboundToolCalls(array $calls): array Tool arguments, before the tools run.
arguments(string $tool, array $args, ToolContext $c): array Add caller data to every call.
afterTool(string $tool, array $result, ToolContext $c): array Annotate a result.
watchEmptyStreak(array $result): array The stop-searching guard.
foundSomething(array $result): ?bool Whether a result found anything. Null = cannot say.

Response

content, inputTokens, outputTokens, model, toolCalls, finishReason, cacheCreationTokens, cacheReadTokens, reasoning, citations, all readonly.

hasToolCalls(), totalTokens(), wasTruncated(), hasReasoning(), hasCitations().

Tools\Tool

name(): string abstract. snake_case, what the model calls it by.
description(): string abstract. Written for the model, not for the reader.
execute(array $args, ToolContext $c): array abstract. $args untrusted, $c trusted.
schema(): array Override this. ['field' => JsonSchema::string()].
parameters(): array The JSON Schema. Built from schema() unless you override it.
isAction(): bool A flag for your UI. Nothing in the package reads it.
tags(): array Runtime tags. Beats the #[Tags] attribute.

Tools\ToolContext

make(array), with($key, $value) (returns a new one), get($key, $default), has($key), require($key) (throws), all().

The loop adds session and model before any tool runs.

Tools\ToolRegistry

register(Tool), get($name), all(), for(?array $tags, ?array $whitelist), definitions(?array $tags, ?array $whitelist).

Models\Memory / Models\Rule

scopedTo(array $memorables, ?Model $context, ?Model $tenant) The three axes as a query.
forSession(ChatSession $s) The same, resolved from a session.
promptBlock(ChatSession $s, int $limit) Ready to paste. Empty string when there is nothing.
Memory::search($session, $query, $limit) Similarity when embeddings are on, recency otherwise.

Relations on both: tenant(), memorable(), holder() (the memory morph), createdBy().

Memory::SOURCE_DISTILLED, Memory::SOURCE_EXPLICIT.

Models\ChatSession

tenant(), actor(), sessionable(), messages(), addTokens(int), updateSummary(string, int).

Models\Agent

isActive(), Agent::activeStatus(), setting($key, $default), maxIterations(), listensTo($event), isDue(?DateTimeInterface), tasks(), logs(), tenant(), createdBy().

Models\AgentTask

markRunning(), markCompleted(array $output, int $in, int $out, int $credits), markFailed(string $error), agent(), taskable(), logs().

AgentTrigger

fire(string $event, Model $owner, ?Model $subject, array $context): int due(?iterable $subjects): int

Both return how many tasks were dispatched.

Console commands

laragents:run-due-agents                       every minute
laragents:cleanup-stale-tasks                  every five minutes
laragents:distil-inactive-sessions [--limit=50] every thirty minutes

Registered on the scheduler automatically. Turn that off with agents.schedule => false.

Publish tags

laragents-config             config/laragents.php
laragents-migrations         the seven tables
laragents-optout-migration   share_memories on your users table

Configuration

'chat' => [
    'max_tool_iterations'    => 7,       // ceiling on the loop
    'max_tool_result_chars'  => 16000,   // truncation before a result goes back
    'empty_streak_after'     => 2,       // consecutive empty searches before the hint
    'result_keys'            => ['items', 'results', 'matches', 'passages', 'data'],
    'empty_streak_hint'      => null,    // ':count' is the streak
    'max_history_tokens'     => 6000,    // budget for the replayed conversation
    'recent_messages_min'    => 4,       // never compressed, whatever the budget says
    'max_response_tokens'    => null,
],

'openai' => [
    'api_key'                          => env('OPENAI_API_KEY'),
    'transcription_model'              => 'whisper-1',
    'transcription_tokens_per_minute'  => 1000,
    'speech_model'                     => 'tts-1',
    'voice'                            => 'alloy',
    'image_model'                      => 'gpt-image-1',
],

'anthropic' => ['api_key' => env('ANTHROPIC_API_KEY')],

'failover' => [],   // [['client' => AnthropicClient::class, 'model' => '...']]

'privacy' => [
    'enabled' => false,
    'except'  => ['person'],
    'keys'    => ['content', 'tool_calls.*.function.arguments'],
],

'memory' => [
    'model'                 => 'gpt-4o-mini',
    'min_messages'          => 4,
    'existing_context'      => 30,
    'lock_seconds'          => 120,
    'prompt'                => null,
    'embeddings'            => false,
    'embedding_model'       => 'text-embedding-3-small',
    'candidate_pool'        => 200,
    'tools'                 => true,
    'share_memories'        => true,
    'actor_table'           => 'users',
    'distil_on_compress'    => true,
    'sweep'                 => true,
    'inactive_after_minutes'=> 30,
    'queue'                 => 'default',
],

'agents' => [
    'active_status'       => 'active',
    'schedule'            => true,
    'queue'               => 'default',
    'debounce_seconds'    => 30,
    'stale_after_minutes' => 30,
],

'events' => [],   // YourEvent::class => YourResolver::class

'rules' => ['headings' => []],

'usage_recorder' => null,   // or 'larameter', or your class

built and maintained by Edu Lazaro · MIT license