symfony/ai-open-responses-platform
Symfony AI Platform integration for Open Responses. Use the Open Responses specification and OpenAI Responses API contract to build and run responses consistently within Symfony, with links to docs, spec, source, and contribution resources.
Install Dependencies:
composer require symfony/ai-platform:^0.9 symfony/ai-open-responses-platform:^0.8
Ensure your project uses PHP 8.2+ and Laravel 10+ (or Symfony components if not using Laravel).
Configure the Client:
Create a service to initialize the Open Responses client. Example in app/Providers/AppServiceProvider.php:
use Symfony\AI\OpenResponses\Client\ModelClient;
use Symfony\AI\OpenResponses\Provider\OpenResponsesProvider;
public function register()
{
$this->app->singleton(ModelClient::class, function ($app) {
return new ModelClient('https://your-openresponses-endpoint/api/v1');
});
$this->app->singleton(OpenResponsesProvider::class, function ($app) {
return new OpenResponsesProvider($app->make(ModelClient::class));
});
}
First Use Case: Basic Completion Inject the provider into a service and call a simple completion:
use Symfony\AI\OpenResponses\Provider\OpenResponsesProvider;
class ChatService {
public function __construct(private OpenResponsesProvider $provider) {}
public function generateResponse(string $prompt): string
{
$response = $this->provider->complete($prompt);
return $response->getContent();
}
}
Call it from a controller:
public function ask(ChatService $chatService)
{
$answer = $chatService->generateResponse("Explain Laravel dependency injection");
return response()->json(['answer' => $answer]);
}
Verify with Open Responses Endpoint: Ensure your Open Responses server (e.g., Ollama, LM Studio, or a custom backend) is running and accessible.
Leverage the Provider abstraction to dynamically switch between providers (e.g., OpenAI, Anthropic, or a self-hosted model). Example:
// app/Services/AiRouter.php
use Symfony\AI\OpenResponses\Provider\OpenResponsesProvider;
use Symfony\AI\OpenResponses\Provider\ProviderInterface;
class AiRouter implements ProviderInterface {
public function __construct(
private ProviderInterface $openAiProvider,
private ProviderInterface $anthropicProvider,
private string $defaultProvider = 'openai'
) {}
public function complete(string $prompt): string
{
$provider = $this->defaultProvider === 'openai'
? $this->openAiProvider
: $this->anthropicProvider;
return $provider->complete($prompt);
}
}
Use Case: Route low-priority requests to a cheaper provider (e.g., self-hosted) while using OpenAI for high-quality responses.
Use DeltaInterface for real-time streaming (e.g., chat UIs). Example in a controller:
use Symfony\AI\OpenResponses\Client\StreamingResponse;
use Symfony\Contracts\Stream\Stream;
public function streamResponse(ChatService $chatService)
{
$stream = $chatService->streamCompletion("Explain Laravel middleware");
return response()->stream(function () use ($stream) {
foreach ($stream as $delta) {
echo $delta->getContent();
flush();
}
}, 200, ['Content-Type' => 'text/event-stream']);
}
Frontend Integration: Use JavaScript to consume SSE (Server-Sent Events) for progressive content loading.
Serialize tool calls for OpenAI-compatible workflows. Example:
use Symfony\AI\OpenResponses\Client\ToolCall;
$tools = [
new ToolCall('get_user_data', ['user_id' => 123]),
new ToolCall('send_email', ['to' => 'user@example.com', 'body' => 'Hello']),
];
$response = $this->provider->complete(
"Fetch user data and send a welcome email.",
tools: $tools
);
Use Case: Integrate with Laravel services (e.g., Mail::send(), User::find()) via tool calls.
Extend the ProviderInterface for self-hosted models (e.g., Ollama). Example:
use Symfony\AI\OpenResponses\Provider\ProviderInterface;
class OllamaProvider implements ProviderInterface {
public function complete(string $prompt, array $options = []): string
{
$response = Http::post('http://localhost:11434/api/generate', [
'model' => 'llama3',
'prompt' => $prompt,
]);
return $response->json()['response'];
}
}
Register it in config/ai.php:
'providers' => [
'ollama' => \App\Providers\OllamaProvider::class,
],
Service Container Binding:
Bind the ModelClient and OpenResponsesProvider in AppServiceProvider for dependency injection:
$this->app->bind(ModelClient::class, function ($app) {
return new ModelClient(config('ai.openresponses.endpoint'));
});
Configuration:
Add to config/ai.php:
'openresponses' => [
'endpoint' => env('OPENRESPONSES_ENDPOINT', 'http://localhost:8000/api/v1'),
'default_provider' => env('AI_DEFAULT_PROVIDER', 'openai'),
],
Queue Jobs for Async Processing: Use Laravel queues to offload AI requests:
use Symfony\AI\OpenResponses\Provider\OpenResponsesProvider;
class GenerateAnswerJob implements ShouldQueue {
public function handle(OpenResponsesProvider $provider) {
$this->provider->complete($this->prompt);
}
}
Middleware for API Rate Limiting: Protect Open Responses endpoints with Laravel middleware:
Route::middleware(['throttle:60,1'])->group(function () {
Route::post('/ai/complete', [AiController::class, 'complete']);
});
Provider Abstraction Mismatch:
ProviderInterface fully. Missing methods (e.g., stream()) will throw BadMethodCallException.AbstractProvider (if available) or implement all required methods:
class CustomProvider implements ProviderInterface {
public function complete(string $prompt, array $options = []): string { ... }
public function stream(string $prompt, array $options = []): StreamingResponse { ... }
public function chat(array $messages, array $options = []): string { ... }
}
Streaming Delta Handling:
DeltaInterface requires proper type handling. Untyped chunks (pre-v0.7.0) may cause serialization errors.foreach ($stream as $delta) {
if (!$delta instanceof DeltaInterface) {
throw new \RuntimeException('Invalid delta type');
}
echo $delta->getContent();
}
Tool Call Serialization:
$tools = [
new ToolCall('function_name', ['arg1' => 'value1'], 'description'),
];
Endpoint Configuration:
.env:
OPENRESPONSES_ENDPOINT=https://api.your-openresponses.org/v1
Symfony AI Dependency Conflicts:
spatie/laravel-ai or other AI packages if they use different Symfony AI versions.composer.json:
"require": {
"symfony/ai-platform": "^0.9",
"symfony/ai-open-responses-platform": "^0.8"
}
Enable Verbose Logging:
Configure the ModelClient to log requests/responses:
$client = new ModelClient('https://endpoint', [
'debug' => true,
'logger' => new \Monolog\Logger('ai', [new \Monolog\Handler\StreamHandler(storage_path('logs/ai.log'))]),
]);
Validate Open Responses Spec Compliance: Use the Open Responses validator to check payloads:
curl -X POST
How can I help you explore Laravel packages today?