helgesverre / pagent
A Pest-inspired LLM Agent Framework for PHP with multi-provider support, automatic tool calling, safety guards, and multi-agent orchestration
Installs: 0
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
pkg:composer/helgesverre/pagent
Requires
- php: ^8.3
- ext-curl: *
- guzzlehttp/guzzle: ^7.10
- nyholm/psr7: ^1.8
- open-telemetry/api: ^1.7
- open-telemetry/exporter-otlp: ^1.3
- open-telemetry/sdk: ^1.9
- open-telemetry/sem-conv: ^1.37
- psr/http-client: ^1.0
- psr/http-factory: ^1.0
- psr/log: ^3.0
- swaggest/json-schema: ^0.12.43
- symfony/process: ^7.3
- teamtnt/tntsearch: ^3.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.0
- laravel/pint: ^1.24
- nunomaduro/phpinsights: ^2.13
- pestphp/pest: ^4.0
- phpstan/phpstan: ^1.10
- spatie/ray: ^1.42
- vlucas/phpdotenv: ^5.6
This package is auto-updated.
Last update: 2025-11-20 14:01:23 UTC
README
A Pest-inspired LLM Agent Framework for PHP
Build intelligent agents with automatic tool calling, multi-provider support, safety guards, and multi-agent orchestrationβall with a clean, fluent API.
Why Pagent?
- π§ͺ Pest-Inspired API - Fluent, expressive syntax that feels natural
- π Real-Time Streaming - SSE streaming for ChatGPT-like experiences
- πΎ Memory & Persistence - SQLite, File, and custom storage adapters
- π§ Automatic Tool Calling - JSON schema generation from PHP functions
- π€ Multi-Provider - Anthropic Claude, OpenAI GPT, Ollama (local), Mock (for testing)
- π‘οΈ Safety Guards - PII detection, content filtering, prompt injection prevention
- π Evaluation Framework - Test datasets with automated metrics and reports
- π Multi-Agent Orchestration - Pipeline, handoff, and delegation patterns
- π‘ Observability & Tracing - OpenTelemetry instrumentation with Jaeger, Zipkin, OTLP support
- β‘ Production Ready - 630+ tests, PHPStan level 9, PHP 8.3+ type safety
Installation
composer require helgesverre/pagent
Requirements:
- PHP 8.3 or higher
- Composer 2.x
Quick Start
// Configure an agent agent('assistant') ->provider('anthropic') ->system('You are a helpful assistant') ->temperature(0.7); // Use the agent $response = agent('assistant')->prompt('Hello!'); echo $response->content; // Or stream responses in real-time agent('assistant')->streamTo('Tell me a story', function ($chunk) { if ($chunk->isText()) { echo $chunk->content; flush(); } }); // Persist conversations across sessions agent('support') ->memory('sqlite', ['path' => 'storage/conversations.db']) ->sessionId('user-123') ->contextWindow(100000) ->prompt('Hello');
π Explore: Streaming Guide | Memory & Persistence
Providers
Mock Provider (for testing)
$mock = mock([ 'Hello' => 'Hi there!', 'How are you?' => 'I am doing great!' ]); $response = $mock->prompt('Hello'); echo $response->content; // "Hi there!"
Anthropic (Claude)
export ANTHROPIC_API_KEY="your-key"
$claude = anthropic(); $response = $claude->prompt('Hello!', [ 'model' => 'claude-3-sonnet-20240229', 'max_tokens' => 100 ]);
OpenAI (GPT)
export OPENAI_API_KEY="your-key"
$gpt = openai(); $response = $gpt->prompt('Hello!', [ 'model' => 'gpt-4', 'temperature' => 0.8 ]);
Ollama (Local LLMs)
Run models locally with complete privacy and zero API costs:
# Install Ollama and pull models
ollama pull qwen3:8b
ollama pull gpt-oss:20b
ollama serve
$ollama = ollama(); $response = $ollama->prompt('Hello!', [ 'model' => 'qwen3:8b', 'temperature' => 0.7 ]);
Benefits:
- π Complete privacy - all data stays local
- π° Zero API costs
- β‘ Low latency
- π οΈ Full tool calling support (qwen3, llama3.1, mistral)
- π‘ NDJSON streaming
π Full Guide: Ollama Integration
Agent Pattern
Agents provide a higher-level abstraction with conversation history:
// Define an agent agent('support') ->provider('anthropic') ->system('You are a customer support agent') ->model('claude-3-haiku-20240307') ->temperature(0.3); // Have a conversation $agent = agent('support'); $agent->prompt('I need help with my order'); $agent->prompt('Order number is 12345'); // Access conversation history foreach ($agent->messages as $message) { echo "[{$message['role']}]: {$message['content']}\n"; }
Provider Configuration
Pagent supports two ways to configure providers:
String-Based (Simple)
Use provider names for quick setup with default configuration:
agent('assistant') ->provider('anthropic') // String name ->system('You are helpful'); // With config options agent('custom') ->provider('ollama', ['base_url' => 'http://custom:11434', 'timeout' => 180]) ->model('qwen3:8b');
Instance-Based (Advanced)
Use helper functions or direct instantiation for custom configuration:
// Using helper functions agent('assistant') ->provider(anthropic(['api_key' => 'custom-key'])) ->prompt('Hello'); agent('local') ->provider(ollama(['timeout' => 300, 'base_url' => 'http://10.0.0.5:11434'])) ->model('llama3.1'); // Direct instantiation use Pagent\Providers\OpenAI; agent('custom') ->provider(new OpenAI(['api_key' => getenv('CUSTOM_KEY')])) ->prompt('Hello');
When to use each:
- String-based: Quick setup, standard configuration
- Instance-based: Custom config, multiple providers with same name, testing
Provider-Specific Features
The library is intentionally "leaky" - you can use provider-specific features:
// Anthropic-specific models $response = anthropic()->prompt('Complex analysis task', [ 'model' => 'claude-3-opus-20240229', 'max_tokens' => 4096 ]); // OpenAI-specific features $response = openai()->prompt('Generate JSON data', [ 'model' => 'gpt-3.5-turbo-1106', 'response_format' => ['type' => 'json_object'] ]);
Tool Calling
Define tools using PHP closures with automatic JSON schema generation:
use Pagent\Tool\Tool; // Create a tool from a closure $weatherTool = Tool::fromClosure( 'get_weather', 'Get the current weather for a location', fn(string $location, bool $include_forecast = false) => "Weather data..." ); // Add tools to an agent $agent = agent('assistant') ->provider('anthropic') ->tool('calculate', 'Perform calculations', fn(int $a, int $b) => $a + $b) ->tool('get_time', 'Get current time', fn(string $tz = 'UTC') => date('H:i:s')); // Execute tools $result = $agent->executeTool('calculate', [10, 5]); // 15 // Generate provider-specific schemas $anthropicSchema = $weatherTool->toAnthropicSchema(); $openaiSchema = $weatherTool->toOpenAISchema();
Type hints are automatically converted to JSON schema types:
stringβ"string"intβ"integer"floatβ"number"boolβ"boolean"arrayβ"array"
Class-Based Tools
Pagent includes 9 production-ready class-based tools in the Pagent\Tools namespace:
use Pagent\Tools\FileRead; use Pagent\Tools\FileWrite; use Pagent\Tools\WebFetch; use Pagent\Tools\Bash; use Pagent\Tools\Grep; use Pagent\Tools\Glob; use Pagent\Tools\PdfReader; use Pagent\Tools\DataExtract; use Pagent\Tools\SearchTool; // Use class-based tools with agents $agent = agent('assistant') ->provider('anthropic') ->tool(new FileRead()) ->tool(new WebFetch()) ->prompt('Read the file data.json and fetch https://api.example.com/data'); // Add multiple tools at once $agent = agent('file-assistant') ->provider('anthropic') ->tools([ new FileRead(baseDir: '/project'), new FileWrite(baseDir: '/project'), new Glob(baseDir: '/project'), new Grep(baseDir: '/project'), ]) ->prompt('List all PHP files and show me the config'); // Create custom class-based tools use Pagent\Tools\Tool; class DatabaseQuery extends Tool { public function name(): string { return 'query_database'; } public function description(): string { return 'Execute a database query and return results'; } public function parameters(): array { return [ 'type' => 'object', 'properties' => [ 'query' => ['type' => 'string', 'description' => 'SQL query to execute'], 'limit' => ['type' => 'integer', 'description' => 'Maximum rows to return'], ], 'required' => ['query'], ]; } public function execute(array $params): mixed { // Your implementation here return ['results' => []]; } } // Use your custom tool agent('assistant')->tool(new DatabaseQuery());
Both closure-based and class-based tools implement ToolInterface and work seamlessly with all providers.
SearchTool - Full-Text Search
The SearchTool provides powerful full-text search capabilities powered by TNTSearch, enabling agents to search through documents, files, and databases:
use Pagent\Tools\SearchTool; // Search through an array of documents (RAG pattern) $documents = [ ['id' => 1, 'title' => 'PHP Guide', 'content' => 'Learn PHP programming...'], ['id' => 2, 'title' => 'Laravel Tutorial', 'content' => 'Build web apps with Laravel...'], ]; agent('docs-assistant') ->tools([searchDocuments($documents)]) ->prompt('Find information about PHP'); // Search through files in a directory agent('codebase-helper') ->tools([new SearchTool(paths: ['docs/', 'src/'])]) ->prompt('Find all documentation about API endpoints'); // Use a pre-built search index agent('knowledge-bot') ->tools([searchIndex('knowledge/docs.index')]) ->prompt('Search the knowledge base for deployment guides'); // Database-backed search agent('db-search') ->tools([ new SearchTool( query: 'SELECT id, title, content FROM articles', connection: ['driver' => 'mysql', 'host' => 'localhost', 'database' => 'mydb'] ) ]) ->prompt('Find articles about Laravel');
Key Features:
- Multiple Document Sources: Arrays, files, directories, databases, or pre-built indexes
- Fuzzy Matching: Handles typos and approximate matches
- BM25 Ranking: Industry-standard relevance scoring
- Flexible Returns: Get just IDs or full document content
- Fast Performance: Sub-millisecond to millisecond search times
- UTF-8 Support: Works with international characters
Configuration Options:
new SearchTool( documents: $docs, // Array of documents to index returnContent: true, // Return full documents vs just IDs fuzzy: true, // Enable fuzzy search fuzziness: 2, // Levenshtein distance (1-3) maxResults: 20, // Max results to return storage: ':memory:', // Index storage location stemmer: PorterStemmer::class // Custom stemmer class );
Search Results:
[
'hits' => 3,
'execution_time' => '1.5ms',
'results' => [
['id' => 1, 'score' => 4.2, 'document' => [...]],
['id' => 2, 'score' => 3.8, 'document' => [...]],
]
]
Perfect for building:
- RAG (Retrieval-Augmented Generation) systems
- Documentation search agents
- Knowledge base assistants
- Semantic code search
- Content discovery tools
Observability & Distributed Tracing
Pagent includes comprehensive OpenTelemetry instrumentation for monitoring and debugging your LLM agents in production.
Quick Start
use function Pagent\{agent, telemetry_console}; // Enable console telemetry for debugging telemetry_console(verbose: true); agent('assistant') ->provider('anthropic') ->telemetry(true) // Enable tracing for this agent ->prompt('Hello!'); // Console shows: // ββ Span: agent.prompt // β Duration: 1.23s // β Attributes: // β - gen_ai.system: anthropic // β - gen_ai.usage.total_tokens: 125 // ββ
Production Monitoring
Connect to Jaeger, Zipkin, or any OpenTelemetry-compatible platform:
use function Pagent\{agent, telemetry_jaeger}; // Export to Jaeger telemetry_jaeger('http://localhost:14268/api/traces'); // All operations automatically traced agent('support') ->telemetry(true) ->tool('search', 'Search knowledge base', $searchFn) ->prompt('Help me find documentation'); // View traces at http://localhost:16686
What Gets Traced
- Agent Operations - Every prompt, stream, and tool execution
- LLM Requests - Provider calls with token usage
- Tool Executions - Arguments, results, and duration
- Guard Checks - Security validations
- Memory Operations - Load/save operations
- Workflows - Multi-agent pipeline orchestration
Supported Platforms
- Jaeger - Open-source distributed tracing
- Zipkin - Distributed tracing system
- OTLP - Generic protocol (Datadog, New Relic, Honeycomb, etc.)
- Console - Local debugging output
Multi-Agent Workflow Tracing
use function Pagent\{agent, pipeline, telemetry_jaeger}; telemetry_jaeger('http://localhost:14268/api/traces'); // Enable telemetry on agents agent('researcher')->provider('anthropic')->telemetry(true); agent('writer')->provider('anthropic')->telemetry(true); // Run workflow - creates hierarchical trace pipeline('content-creation') ->step('research', agent('researcher')) ->step('write', agent('writer')) ->run('Write article about PHP'); // Trace shows: // workflow.pipeline // ββ workflow.step (research) // β ββ agent.prompt β llm.request β tool.execute // ββ workflow.step (write) // ββ agent.prompt β llm.request
Benefits
- Debug Complex Workflows - Visualize multi-agent interactions
- Performance Monitoring - Track latency and bottlenecks
- Token Usage Tracking - Real-time token consumption
- Cost Visibility - Understand API usage patterns
- Compliance - Complete audit trail
π Full Guide: Observability Documentation
Development
Quick Commands
# Setup project just setup # Install dependencies and git hooks # Testing just test # Run all tests just coverage # Run tests with coverage report # Code Quality just format # Fix code style (PHP + Markdown) just analyse # Run PHPStan static analysis just pr # Prepare for PR (fix, analyse, test) # Observability Stack just obs-up # Start observability tools (Jaeger, Phoenix, Langfuse, etc.) just obs-down # Stop and remove observability stack
Manual Testing
# Run unit tests (no API calls) ./vendor/bin/pest --exclude-group=api # Run API integration tests (requires API keys) cp .env.example .env # Add your keys to .env ./vendor/bin/pest --group=api
Documentation
Learning Guides
We've created 5 different guide styles so you can learn in the way that works best for you:
- Getting Started (Conversational) - Friendly, interactive introduction with examples
- Recipes (Task-Oriented) - Step-by-step solutions for common tasks
- Quick Start (Minimal) - TL;DR reference for when you're in a hurry
- Concepts (Deep Dive) - Understand the architecture and design decisions
- API Reference (Technical) - Complete technical documentation
New to Pagent? Start with the Getting Started Guide.
Need something specific? Check the Recipes Guide.
In a hurry? The Quick Start has you covered.
Integration Guides
Learn how to integrate Pagent into your application:
- Vanilla PHP - Pure PHP integration without frameworks
- Slim Framework Integration - Complete Slim 4.x setup with DI and middleware
- Laravel Integration - Laravel setup with service providers and facades
- Symfony Integration - Symfony bundle integration with DI container
Feature Guides
Deep-dive into specific features:
- Streaming Guide - Real-time SSE streaming implementation
- Memory & Persistence - SQLite, File, and custom storage adapters
- Orchestration Workflows - Multi-agent patterns: pipelines, handoffs, delegation
See the docs/ folder for all guides.
Contributing
We welcome contributions! Please see CONTRIBUTING.md for details on:
- Development setup
- Running tests
- Code style guidelines
- Pull request process
Read our Code of Conduct and Security Policy.
Changelog
See CHANGELOG.md for recent changes.
License
MIT License. See LICENSE for details.
Credits
Created by Helge Sverre.
Inspired by Pest's elegant API design.