Changelog¶
All notable changes to this project are documented here. The format follows Keep a Changelog and the project uses Semantic Versioning.
Unreleased¶
0.2.0 - 2026-09-25¶
Adds the Laravel bridge, released as praveendias1180/a2a-laravel 0.2.0 (both packages are versioned together from here on). The official A2A TCK passes at the MUST level against a queued Laravel app on PHP-FPM + nginx.
Added¶
- Laravel bridge (
praveendias1180/a2a-laravel,packages/laravel), for Laravel 12 and 13 (11 allowed, untested): Route::a2a('/a2a', agentCard: ..., executor: ...)mounts the Agent Card, JSON-RPC and HTTP+JSON, fills the card's interfaces in from the routes, and isroute:cachesafe. Agents can also come fromconfig/a2a.php.QueuedTaskRunner+RunAgentExecutorjob: executors run on queue workers while the web request streams their events live; one run per task at a time (run lease); executor errors fail the call the same way as with the inline runner.RedisQueueManager(Redis Streams,XREAD BLOCK, atomic sequence numbers, expiring keys), or the corePdoQueueManageron the app's connection.- Tasks in the core
PdoTaskStoreon the app's connection; push-notification configs in the database, encrypted with the app key. Owner scoping from the authenticated Laravel user. - Security schemes in the card map to route middleware (
a2a.security_schemes); CSRF is off for the protocol routes. A2A::client()facade; artisana2a:make-executor,a2a:card,a2a:prune,a2a:tck; publishable config and migration.scripts/run-tck-laravel.sh: the official A2A TCK against a real Laravel app on PHP-FPM + nginx with the queued runner and queue workers (also a CI job), and a 20 s long-task proof.ResponseEmitter::streamSse(): the SSE pump, public so framework bridges stream exactly like the plain-PHP emitter.examples/laravel/: the Laravel examples shown in the docs, run by the test suite.- Docs: Laravel guides (install and first agent, queued execution, streaming behind nginx, storage and pruning).
Changed¶
praveendias1180/a2a-laravelrequirespraveendias1180/a2a-php^0.2.tck/TckAgentExecutor.php: the TCK executor moved out oftck/sut-agent.php, so the Laravel TCK app reuses it.
0.1.0 - 2026-09-25¶
First release: A2A 1.0 client and server for PHP 8.2+. The server passes the official A2A TCK at the MUST level (137 passed) over JSON-RPC and HTTP+JSON. The Laravel bridge is not included yet (phase 4).
Added¶
- Wire types generated from the A2A v1.0.0
a2a.proto(A2A\Types\*). A2A\Utils\ConstantsandA2A\Utils\TransportProtocol.- ProtoJSON round-trip tests against the specification's JSON shapes.
- Laravel bridge package skeleton (
packages/laravel). - Errors (
A2A\Utils\Errors\*): one exception per A2A and JSON-RPC error, with the same JSON-RPC codes, HTTP statuses, gRPC statuses and ErrorInfo reasons as the Python SDK (ErrorMapping). A2A\Utils\ErrorHandlers: REST error payloads and JSON-RPC error objects, includinggoogle.rpc.ErrorInfoandgoogle.rpc.BadRequestdetails. Unlike the Python SDK, a non-A2A exception becomes JSON-RPC-32603 "Internal error"without its message, so internal details never reach the caller (REST already hid them).A2A\Utils\ProtoUtils: stream-response wrapping,Struct/Value↔ PHP conversion, REST query-parameter parsing, and REQUIRED-field validation driven by a table generated froma2a.proto(A2A\Types\Meta\RequiredFields,scripts/generate-required-fields.php).A2A\Utils\TaskUtils(history length, page size, page tokens),JsonUtils,VersionValidator(A2A-Versionheader) andPushUrlValidator(SSRF guard for push-notification URLs, with an injectable resolver).A2A\Utils\Jcs: RFC 8785 JSON canonicalization, checked against the a2a-jcs-v01 vector corpus and against ECMAScript number formatting.A2A\Helpers\ProtoHelpersandAgentCardHelpers,A2A\Extensions\Common,A2A\Auth\UserandUnauthenticatedUser.- The client (
A2A\Client\*), in the shape of the Python SDK'sa2a.client:ClientFactory(withcreateClient()andminimalAgentCard()),BaseClient,ClientConfig,ClientCallContext,A2ACardResolver(including the pre-1.0 card field mapping), interceptors (ClientCallInterceptor,BeforeArgs,AfterArgs),AuthInterceptorwithInMemoryContextCredentialStore, service parameters, and the client errors (A2AClientError,A2AClientTimeoutError,AgentCardResolutionError). - JSON-RPC and HTTP+JSON transports (
JsonRpcTransport,RestTransport,TenantTransportDecorator) with every A2A operation. Errors from the agent come back as the matchingA2A\Utils\Errors\*exception. Streams are PHP Generators. A2A\Client\Http\HttpSenderwith senders for Guzzle and Symfony HttpClient (live SSE streaming) and any PSR-18 client (buffered), picked byHttpSenderFactory; an incremental SSE parser (A2A\Client\Sse\EventStreamParser).- Interop tests against the official Python SDK's sample agent (a2a-sdk 1.1.5): every
client operation over JSON-RPC and HTTP+JSON, with Guzzle, Symfony HttpClient and a
PSR-18 client (
scripts/run-python-interop.sh, CI jobpython-interop). - The server (
A2A\Server\*), in the shape of the Python SDK'sa2a.server:AgentExecutor,RequestContext(withisCancelled()),RequestContextBuilder,SimpleRequestContextBuilder,ActiveTask,EventConsumer,ActiveTaskRegistry,EventQueue,InMemoryEventQueue,TaskStore,InMemoryTaskStore,CopyingTaskStore,TaskManager,TaskUpdater,ResultAggregator,PushNotificationConfigStore(in-memory),RequestHandler,DefaultRequestHandler(a port of Python'sDefaultRequestHandlerV2),ServerCallContext,OwnerResolverandIdGenerator/UuidGenerator. - The executor runs in a PHP Fiber: every enqueued event is checked, saved, published
and streamed before the executor continues.
TaskRunner/InlineTaskRunnerdecide where it runs, hold a per-task run lease and finish deferred work after the response. QueueManageras a per-task event log with cancel flags and run leases, so separate PHP processes can subscribe to, stream and cancel the same task:InMemoryQueueManagerandPdoQueueManager(SQLite, PostgreSQL, MySQL).PdoTaskStore(SQLite, PostgreSQL, MySQL; owner scoping, keyset pagination), brought forward from phase 5.- PSR-15 handlers:
JsonRpcDispatcher,RestDispatcher(with tenant prefixes),AgentCardHandler(Cache-Control,ETag,Last-Modified, 304),Router,Routes;ResponseEmitter(per-event SSE flushing, disconnect detection, background work after the response),ServerRequestFactory,Sse\SseStream,DefaultServerCallContextBuilder. examples/hello-world(a port of the Python SDK's sample agent) andtck/sut-agent.php.- Conformance: the official A2A TCK passes at the MUST (137/137), SHOULD and MAY levels
over JSON-RPC and HTTP+JSON (
scripts/run-tck.sh, CI jobtck), and the official Python SDK client works against the PHP server over both transports.
Changed¶
TaskNotCancelableErrormaps to HTTP 409 (the A2A TCK's CORE-CANCEL-002; the released v1.0.0 spec table and the Python SDK say 400). The ErrorInfo reason is unchanged.examples/call-an-agent.php, shown on the docs site and run in CI.
Changed¶
- Requires
php-http/discovery(finds a PSR-18 client when none is given) andpsr/http-factory^1.1.