swisnl / ag-ui-server
PHP server integration for AG-UI - standardized AI agent frontend communication via Server-Sent Events
Fund package maintenance!
:vendor_name
Installs: 0
Dependents: 0
Suggesters: 0
Security: 0
Stars: 1
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/swisnl/ag-ui-server
Requires
- php: ^8.2
- psr/event-dispatcher: ^1.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.74
- phpstan/phpstan: ^2.1.11
- phpunit/phpunit: ^11.5.15
This package is auto-updated.
Last update: 2025-10-24 10:02:55 UTC
README
A PHP server integration package for AG-UI - standardized AI agent frontend communication via Server-Sent Events and other transport methods.
AG-UI provides a real-time, event-driven protocol for streaming AI agent responses, tool calls, and state updates to frontends. This package makes it easy to integrate AG-UI into your PHP AI projects.
Features
- Complete AG-UI Event Support - All event types: messages, tool calls, lifecycle, state management
- Flexible Message API - Simple one-shot messages or streaming with closures/iterables
- Pluggable Transporters - SSE included, easily extend with WebSocket, polling, etc.
- Adaptive Delta Buffering - Optimized streaming performance
- PSR-14 Compatible - Interoperable with existing event systems
- Type Safe - PHPStan types for better developer experience
- Framework Agnostic - Works with Laravel, Symfony, or any PHP application
Installation
composer require swis/ag-ui-server
Quick Start
<?php use Swis\AgUiServer\AgUiState; use Swis\AgUiServer\Transporter\SseTransporter; // Initialize state $state = new AgUiState(); // Start a conversation run $threadId = 'thread_' . uniqid(); $runId = 'run_' . uniqid(); $state->startRun($threadId, $runId); // Simple message $state->addMessage('Hello! How can I help you?'); // Streaming message from LLM $state->addMessage(function() { return $this->llm->streamCompletion($prompt); // Returns iterable }); // Tool call $state->addToolCall('web_search', '{"query": "weather today"}'); // Finish the run $state->finishRun();
Core Concepts
AG-UI Events
The package supports all AG-UI event types:
- Lifecycle:
RunStarted,RunFinished,RunError,StepStarted,StepFinished - Messages:
TextMessageStart,TextMessageContent,TextMessageEnd - Reasoning:
ReasoningStart,TextReasoningMessageStart,TextReasoningMessageContent,TextReasoningMessageEnd,TextReasoningEnd - Tool Calls:
ToolCallStart,ToolCallArgs,ToolCallEnd - State:
StateSnapshot,StateDelta,MessagesSnapshot - Special:
Raw,Custom
Flexible Message API
// String content - sent as single message $state->addMessage('Complete response here'); // Closure returning string $state->addMessage(function() { return $this->llm->complete($prompt); }); // Closure returning iterable - streamed as deltas $state->addMessage(function() { return $this->llm->streamCompletion($prompt); }; // Direct iterable $state->addMessage(['Hello ', 'world', '!']); // Manual control for complex scenarios $messageId = $state->startMessage(); foreach ($complexStream as $chunk) { $state->addMessageContent($messageId, $chunk); } $state->finishMessage($messageId);
Transporters
Easily swap transport methods:
// Server-Sent Events (default) $transporter = new SseTransporter(); $transporter->initialize(); // Sends headers // Custom headers $transporter = new SseTransporter([ 'Access-Control-Allow-Origin' => 'https://yourapp.com', 'Cache-Control' => 'no-cache', ]); $transporter->initialize(); // Sends headers // Future: WebSocket support // $transporter = new WebSocketTransporter($connection);
RAG Integration Example
public function handleChatRequest(Request $request) { $userMessage = $request->input('message'); $threadId = $request->input('threadId') ?? 'thread_' . uniqid(); $runId = 'run_' . uniqid(); $state = new AgUiState(); $state->startRun($threadId, $runId); try { // Step 1: Analyze query $state->startStep('analyzing_query'); // ... analysis logic ... $state->finishStep(); // Step 2: Retrieve context $state->startStep('retrieving_context'); $state->addToolCall(null, 'vector_search', json_encode([ 'query' => $userMessage, 'top_k' => 5 ])); $documents = $this->vectorSearch($userMessage); $state->finishStep(); // Step 3: Generate response $state->startStep('generating_response'); $state->addMessage(null, function() use ($userMessage, $documents) { return $this->llm->streamWithContext($userMessage, $documents); }, 'assistant'); $state->finishStep(); $state->finishRun(); } catch (\Exception $e) { $state->errorRun($e->getMessage()); } }
Advanced Features
Manual Event Triggering
While AgUiState provides a convenient high-level API for typical AI workflows, you can also trigger events manually for complete control over your application's behavior:
use Swis\AgUiServer\Events\TextMessageStartEvent; use Swis\AgUiServer\Events\TextMessageContentEvent; use Swis\AgUiServer\Events\TextMessageEndEvent; use Swis\AgUiServer\Transporter\SseTransporter; use Psr\EventDispatcher\EventDispatcherInterface; // Set up event dispatcher and transporter $dispatcher = $container->get(EventDispatcherInterface::class); $transporter = new SseTransporter(); $transporter->initialize(); // Sends headers $transporter->setEventDispatcher($dispatcher); // Now trigger events from your application $messageId = 'msg_' . uniqid(); // The transporter will automatically listen for these events and send them $dispatcher->dispatch(new TextMessageStartEvent( messageId: $messageId, role: 'assistant' )); $dispatcher->dispatch(new TextMessageContentEvent( messageId: $messageId, content: 'Hello from my custom application!' )); $dispatcher->dispatch(new TextMessageEndEvent( messageId: $messageId ));
Direct Event Dispatching (Without PSR-14)
If you prefer not to use PSR-14, you can send events directly:
$transporter = new SseTransporter(); $transporter->initialize(); // Send events directly $event = new TextMessageStartEvent( messageId: 'msg_123', role: 'assistant' ); $transporter->send($event); $transporter->close();
When to Use Manual Events vs AgUiState
- Use
AgUiStatefor typical AI agent workflows with automatic state management, message streaming, and tool calls - Use manual events when you need:
- Complete control over event timing and data
- Integration with existing event-driven architectures
- Custom event flows that don't fit the standard AI agent pattern
- Building your own higher-level abstractions
Adaptive Delta Buffering
Delta buffering is optional and can be enabled to optimize streaming performance:
// Without delta buffering (default) $state = new AgUiState(); // With delta buffering for optimized streaming $state = (new AgUiState())->withDeltaBuffering( deltaBufferThreshold: 150, // chars deltaFlushInterval: 0.3 // seconds );
PSR-14 Event Integration
All AG-UI events implement PSR-14 interfaces:
use Psr\EventDispatcher\EventDispatcherInterface; // Your existing PSR-14 dispatcher $dispatcher = $container->get(EventDispatcherInterface::class); // Listen to AG-UI events $dispatcher->addListener(TextMessageStartEvent::class, function($event) { // Log message start $this->logger->info('Message started', ['messageId' => $event->messageId]); });
Custom Transporters
Implement your own transport:
class WebSocketTransporter implements TransporterInterface { public function __construct(private $connection) {} public function initialize(): void { // Setup WebSocket connection } public function send(AgUiEvent $event): void { $this->connection->send($event->toJson()); } public function sendComment(string $comment): void { // WebSocket doesn't need comments } public function close(): void { $this->connection->close(); } }
Event Types Reference
Message Events
TextMessageStart- Begin streaming a messageTextMessageContent- Content chunk (delta)TextMessageEnd- Message complete
Reasoning Events
ReasoningStart- Begin reasoning state (optional)ReasoningMessageStart- Begin streaming a reasoning messageReasoningMessageContent- Content chunk (delta)ReasoningMessageEnd- Reasoning message completeReasoningStart- End reasoning state (optional)
Tool Call Events
ToolCallStart- Begin tool executionToolCallArgs- Tool arguments (can be streamed)ToolCallEnd- Tool execution complete
Lifecycle Events
RunStarted- Agent run beginsRunFinished- Agent run completes successfullyRunError- Agent run failedStepStarted- Processing step beginsStepFinished- Processing step completes
State Events
StateSnapshot- Complete stateStateDelta- State changes (JSON Patch)MessagesSnapshot- All conversation messages
Changelog
Please see CHANGELOG for more information on what has changed recently.
Security Vulnerabilities
Please review our security policy on how to report security vulnerabilities.
Credits
License
This package is open-sourced software licensed under the MIT license.
This package is Treeware. If you use it in production, then we ask that you buy the world a tree to thank us for our work. By contributing to the Treeware forest you’ll be creating employment for local families and restoring wildlife habitats.
SWIS ❤️ Open Source
SWIS is a web agency from Leiden, the Netherlands. We love working with open source software.