-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Creating psr/ai proposal #1342
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Creating psr/ai proposal #1342
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,252 @@ | ||
| # PSR-AI: Common Interface for AI Interaction in PHP | ||
|
|
||
| ## Table Of Contents | ||
|
|
||
| - [1. Introduction](#1-introduction) | ||
| - [2. Conventions Used In This Document](#2-conventions-used-in-this-document) | ||
| - [3. Definitions](#3-definitions) | ||
| - [4. Basic Principles](#4-basic-principles) | ||
| - [5. The AI Client Abstraction](#5-the-ai-client-abstraction) | ||
| - [5.1 The Client Interface](#51-the-client-interface) | ||
| - [5.2 The Message Interface](#52-the-message-interface) | ||
| - [5.3 The Stream Interface](#53-the-stream-interface) | ||
| - [5.4 The Tool Interface](#54-the-tool-interface) | ||
| - [5.5 The Response Interface](#55-the-response-interface) | ||
| - [6. Example Usage](#6-example-usage) | ||
| - [Appendix A. ABNF Definitions](#appendix-a) | ||
| - [Appendix B. References](#appendix-b) | ||
|
|
||
| ## 1. Introduction | ||
|
|
||
| The purpose of this PSR is to define a common interface for interacting with artificial intelligence models in PHP, such as large language models, multimodal models, and reasoning engines. | ||
|
|
||
| This PSR aims to standardize how PHP applications and frameworks: | ||
| - Send messages to AI models. | ||
| - Receive structured and streamed responses. | ||
| - Register callable tools or functions for model invocation. | ||
| - Maintain interoperability with the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/). | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How is this PSR facilitating MCP? Wouldn't an MCP server be implemented using the HTTP PSRs? I suppose the ToolInterface would be the only thing from here that'd make sense to use, unless your MCP exposed tools need to interact with an LLM |
||
|
|
||
| As with prior PSRs (such as PSR-3 and PSR-18), the goal is not to mandate a particular implementation, but to provide an interoperable interface layer allowing frameworks, SDKs, and providers to integrate seamlessly. | ||
|
|
||
| ## 2. Conventions Used In This Document | ||
|
|
||
| The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC 2119](https://tools.ietf.org/html/rfc2119). | ||
|
|
||
| ## 3. Definitions | ||
|
|
||
| - **Model**: A computational system capable of processing input and producing structured or natural-language output. Examples include OpenAI's GPT models, Anthropic's Claude, or local models served via Ollama. | ||
| - **Client**: An implementation of the `Psr\Ai\ClientInterface` responsible for communicating with a model provider or local runtime. | ||
| - **Message**: A discrete input or output unit representing a message exchanged with the model. A message MAY include role metadata (e.g., `system`, `user`, `assistant`) and MAY encapsulate data objects, code, or binary content. | ||
| - **Stream**: A sequence of partial output tokens, chunks, or structured updates emitted during a model's response generation. | ||
| - **Tool**: A callable function or operation that the model MAY invoke during reasoning or message generation. Tools MUST be discoverable and serializable in a format compatible with MCP. | ||
| - **Response**: The final or intermediate result from a model call. Responses MAY include text, structured data, tool calls, or cost metrics. | ||
| - **Session**: A series of related interactions forming a context (e.g., a multi-turn chat or reasoning session). Session handling is out of scope for this PSR, but MAY be implemented on top of it. | ||
|
|
||
| ## 4. Basic Principles | ||
|
|
||
| 1. All AI interactions MUST occur via a `Psr\Ai\ClientInterface`. | ||
| 2. Model inputs and outputs MUST be represented by standardized `MessageInterface` and `ResponseInterface` objects. | ||
| 3. Streaming outputs MUST conform to the `StreamInterface` contract, ensuring consistent event-driven consumption. | ||
| 4. Callable tools MUST implement the `ToolInterface` and MUST be compatible with MCP serialization. | ||
| 5. Implementations SHOULD remain framework-agnostic and transport-neutral. | ||
| 6. The PSR MUST NOT prescribe any particular provider API, HTTP format, or runtime behavior. | ||
|
|
||
| ## 5. The AI Client Abstraction | ||
|
|
||
| ### 5.1. The Client Interface | ||
|
|
||
| The ClientInterface represents the entry point for AI interaction. | ||
|
|
||
| An implementation MUST provide at least the following methods: | ||
|
|
||
| ```php | ||
| namespace Psr\Ai; | ||
|
|
||
| interface ClientInterface | ||
| { | ||
| /** | ||
| * @param MessageInterface|array<MessageInterface> $message | ||
| */ | ||
| public function complete(MessageInterface|array $message): ResponseInterface; | ||
|
|
||
| /** | ||
| * @param MessageInterface|array<MessageInterface> $message | ||
| */ | ||
| public function stream(MessageInterface|array $message): StreamInterface; | ||
|
|
||
| public function invokeTool(ToolInterface $tool, array $arguments): mixed; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this here? What benefit does the client add by running |
||
| } | ||
| ``` | ||
|
|
||
| **Rules:** | ||
| - `complete()` MUST perform a synchronous model call and return a finalized `ResponseInterface`. | ||
| - `stream()` MUST return a `StreamInterface` that yields incremental output as available. | ||
| - `invokeTool()` MUST execute a callable tool in the same process or over MCP. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Huh? So this ClientInterface is both a client for an MCP server and for an LLM API? We probably want to separate the MCP client out to it's own interface or its own PSR. As currently written, the client can't really decide how to invoke a tool, the tool's execution is encompassed by |
||
|
|
||
| ### 5.2. The Message Interface | ||
|
|
||
| The MessageInterface defines a structured input or output exchanged between client and model. | ||
|
|
||
| ```php | ||
| namespace Psr\Ai; | ||
|
|
||
| interface MessageInterface | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This needs to also encompass tool use and tool results. The actual message used will be different depending on the model / api in use. |
||
| { | ||
| public function role(): string; | ||
| public function content(): string|array; | ||
| public function metadata(): array; | ||
| } | ||
| ``` | ||
|
|
||
| **Rules**: | ||
| - `role()` MUST return a string such as system, user, or assistant. | ||
| - `content()` MAY contain plain text or structured data (e.g., JSON, array). | ||
| - Implementations MAY define message classes (e.g., `UserMessage`, `AssistantMessage`) for typed interactions. | ||
| - Message instances MUST be immutable once created. | ||
|
|
||
| ### 5.3. The Stream Interface | ||
|
|
||
| The StreamInterface enables incremental consumption of model output. | ||
|
|
||
| ```php | ||
| namespace Psr\Ai; | ||
|
|
||
| interface StreamInterface extends \Traversable | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It'd be hard to actually consume this without knowing the specific implementation and API that are being used. The actually traversed chunks could be a lot of different things. |
||
| { | ||
| public function onToken(callable $callback): void; | ||
| public function onError(callable $callback): void; | ||
| public function onComplete(callable $callback): void; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMO these methods should go away, if we want this functionality codified, I'd recommend using the event dispatcher PSR. |
||
| } | ||
| ``` | ||
|
|
||
| **Rules:** | ||
| - Implementations MUST emit partial output (e.g., tokens, chunks) through `onToken()`. | ||
| - `onError()` MUST emit any transport or model errors. | ||
| - `onComplete()` MUST be called when the stream has ended. | ||
| - Streams SHOULD be compatible with PSR-7 stream semantics where applicable. | ||
|
|
||
| ### 5.4. The Tool Interface | ||
|
|
||
| The ToolInterface standardizes callable functions the model may request via tool calling. | ||
|
|
||
| ```php | ||
| namespace Psr\Ai; | ||
|
|
||
| interface ToolInterface | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Like I mentioned above, this interface should probably not encompass both the tool metadata like name, description, schema, etc and the execution of a tool. |
||
| { | ||
| public function name(): string; | ||
| public function description(): ?string; | ||
| public function schema(): array; | ||
| public function execute(array $arguments): mixed; | ||
| } | ||
| ``` | ||
|
|
||
| **Rules:** | ||
| - Tools MUST define their input/output schema for validation and serialization. | ||
| - Implementations SHOULD align schema definitions with the [Model Context Protocol](https://modelcontextprotocol.io/). | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What do you mean by this? In general (with a few exceptions) APIs and MCP expects jsonapi. We should codify that the schema is an array that represents valid jsonapi and allow serializers to handle any idiosyncrasies. |
||
| - `execute()` MUST return serializable output or throw an exception. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Executing a tool should modify the message list. A tool typically will output one or more messages that represent the tool output, but we probably also want a path for them to remove messages from the list too. Also a "tool" might take the form of prompting the user for more information or a long running multi-process action that completes after a significant amount of time. We probably want to provide more context to the execute function wherever it ends up, just giving it the arguments and nothing else will stunt the ability of the tools. We might consider a ToolContextInterface that includes the client, an identifier for the model invoking the tool, the current list of messages, etc. |
||
|
|
||
| ### 5.5. The Response Interface | ||
|
|
||
| The ResponseInterface provides a normalized representation of model responses. | ||
|
|
||
| ```php | ||
| namespace Psr\Ai; | ||
|
|
||
| interface ResponseInterface | ||
| { | ||
| public function message(): MessageInterface; | ||
| public function metadata(): array; | ||
| } | ||
| ``` | ||
|
|
||
| **Rules:** | ||
| - The `message()` MUST represent the model's returned message. | ||
| - `metadata()` SHOULD include token usage, cost, latency, or provider-specific data. | ||
| - Responses MAY include nested tool calls or structured outputs. | ||
|
|
||
| ## 6. Example Usage | ||
|
|
||
| ```php | ||
| use Psr\Ai\{ClientInterface, MessageInterface}; | ||
|
|
||
| $message = new UserMessage('What is the capital of France?'); | ||
|
|
||
| $response = $client->complete($message); | ||
|
|
||
| echo $response->message()->content(); // "Paris" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wouldn't this pretty much always be something like: |
||
| ``` | ||
|
|
||
| Streaming example: | ||
|
|
||
| ```php | ||
| $stream = $client->stream(new UserMessage('Write a haiku about PHP.')); | ||
|
|
||
| $stream->onToken(fn($token) => echo $token); | ||
| $stream->onComplete(fn() => echo "\nDone."); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again I don't think this is a very ergonomic way to interact with the stream, instead it should be At the very least you're missing something that actually causes the stream to be read. |
||
| ``` | ||
|
|
||
| Tool registration example: | ||
|
|
||
| ```php | ||
| class WeatherTool implements ToolInterface | ||
| { | ||
| public function name(): string | ||
| { | ||
| return 'getWeather'; | ||
| } | ||
|
|
||
| public function schema(): array | ||
| { | ||
| return [ | ||
| 'location' => 'string', | ||
| ]; | ||
| } | ||
|
|
||
| public function execute(array $args): array | ||
| { | ||
| return [ | ||
| 'temp' => 18, | ||
| 'unit' => 'C', | ||
| ]; | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## Appendix A. ABNF Definitions | ||
|
|
||
|
|
||
| The ABNF below defines general communication semantics: | ||
|
|
||
| ``` | ||
| message = role ":" content | ||
| role = "system" / "user" / "assistant" / "tool" | ||
| content = *CHAR | ||
| ``` | ||
|
|
||
| Streaming token flow: | ||
|
|
||
| ``` | ||
| stream = 1*(token / event) | ||
| token = 1*CHAR | ||
| event = "[" event-type ":" data "]" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This doesn't really match up with my experience using streaming responses from LLMs fwiw. |
||
| ``` | ||
|
|
||
| ## Appendix B. References | ||
|
|
||
| - [RFC 2119](https://tools.ietf.org/html/rfc2119). Key words for use in RFCs to indicate requirement levels. Defines "MUST", "SHOULD", "MAY", etc., for consistent interpretation of requirements. | ||
| - [RFC 5234](https://tools.ietf.org/html/rfc5234). Augmented Backus-Naur Form (ABNF). Defines the ABNF grammar notation used in Appendix A. | ||
| - [PSR-3: Logger Interface](https://www.php-fig.org/psr/psr-3/). Reference for a widely adopted interface standard, demonstrating framework-agnostic design. | ||
| - [PSR-7: HTTP Message Interface](https://www.php-fig.org/psr/psr-7/). Provides streaming and message abstraction patterns referenced in StreamInterface. | ||
| - [PSR-14: Event Dispatcher](https://www.php-fig.org/psr/psr-14/). Illustrates middleware/event pipelines for streaming token handling. | ||
| - [PSR-18: HTTP Client Interface](https://www.php-fig.org/psr/psr-18/). Example of a provider-agnostic client abstraction. | ||
| - [Model Context Protocol (MCP)](https://modelcontextprotocol.io/). Defines a cross-language protocol for tools, structured data, and context integration in AI workflows. | ||
| - [OpenAI API](https://platform.openai.com/docs/api-reference/introduction). Industry-standard example of a large language model API with streaming and tool-calling features. | ||
| - [Anthropic API.](https://docs.anthropic.com/). Provides examples of structured LLM interactions and multi-turn session concepts. | ||
| - [Ollama](https://ollama.com/). Demonstrates locally-hosted model integrations for PHP and other ecosystems. | ||
| - [Fluent Interface Pattern](https://en.wikipedia.org/wiki/Fluent_interface). References common design patterns used in PHP SDKs and streaming APIs. | ||
| - [PHP Iterables](https://www.php.net/manual/en/language.types.iterable.php). Defines iterable types used in StreamInterface and message pipelines. | ||
| - [PHP Resources](https://www.php.net/manual/en/language.types.resource.php). Guidance on representing external streams or handles in PHP. | ||
| - [PHP Callables](https://www.php.net/manual/en/language.types.callable.php). Used in ToolInterface::execute() for callable definitions. | ||
| - [Late Static Binding in PHP](https://www.php.net/manual/en/language.oop5.late-static-bindings.php). Covers use of static in message and response class hierarchies. | ||
| - [DeFacto PHPDoc Specification](http://www.phpdoc.org/docs/latest/index.html). Serves as a reference for structured documentation and interface design. | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where is tool registration codified?