adachsoft/ai-integration

Unified AI tool-calling chat abstraction for PHP 8.3 with pluggable SPI providers (OpenAI, Deepseek) and a clean Public API.

Installs: 16

Dependents: 2

Suggesters: 0

Security: 0

Stars: 0

Forks: 0

pkg:composer/adachsoft/ai-integration

0.5.0 2025-12-27 12:52 UTC

This package is not auto-updated.

Last update: 2026-01-10 12:06:27 UTC


README

Unified AI tool-calling chat abstraction for PHP 8.3 with pluggable providers and a clean, framework-agnostic Public API.

  • Public API: simple facade to send chat messages, define tools (function-calling), and receive results.
  • Built-in providers: OpenAI and Deepseek.
  • SPI: implement your own provider by fulfilling a tiny interface and DTO set.
  • HTTP logging: optional, via a small logger interface.
  • Zero-framework: no container required; everything is manually wired with a builder.

Requirements

  • PHP 8.3+
  • ext-json, ext-mbstring (standard in most PHP installations)

Installation

composer require adachsoft/ai-integration

Quick start (Public API)

use AdachSoft\AiIntegration\PublicApi\Builder\ToolCallingChatFacadeBuilder;
use AdachSoft\AiIntegration\PublicApi\ToolCalling\Dto\ChatMessageDto;
use AdachSoft\AiIntegration\PublicApi\ToolCalling\Dto\ChatRoleEnum;
use AdachSoft\AiIntegration\PublicApi\ToolCalling\Dto\Collection\ChatMessageDtoCollection;
use AdachSoft\AiIntegration\PublicApi\ToolCalling\Dto\Collection\ToolDefinitionDtoCollection;
use AdachSoft\AiIntegration\PublicApi\ToolCalling\Dto\ToolCallingChatRequestDto;
use AdachSoft\AiIntegration\PublicApi\ToolCalling\Dto\ToolDefinitionDto;

$builder = ToolCallingChatFacadeBuilder::create()
    ->withOpenAi(apiKey: getenv('OPENAI_API_KEY'));

$messages = new ChatMessageDtoCollection([
    ChatMessageDto::createSystemMessage('You are a helpful assistant.'),
    ChatMessageDto::createUserMessage('Add 2 and 3 using a tool and show the token.'),
]);

$tools = new ToolDefinitionDtoCollection([
    new ToolDefinitionDto(
        name: 'sum',
        description: 'Returns JSON {result: string, token: string}',
        parametersSchema: [
            'type' => 'object',
            'properties' => [
                'a' => ['type' => 'number'],
                'b' => ['type' => 'number'],
            ],
            'required' => ['a', 'b'],
            'additionalProperties' => false,
        ],
    ),
]);

$request = new ToolCallingChatRequestDto(
    messages: $messages,
    tools: $tools,
    providerId: 'openai',
    modelId: 'gpt-4o-mini',
    parameters: [
        // Free-form provider parameters.
        // They are forwarded 1:1 to the provider payload (no defaults are injected).
        // Example (only if your model supports it):
        // 'temperature' => 0.0,
    ],
);

$facade = $builder->build();
$response = $facade->chat($request);

if ($response->result !== null) {
    echo $response->result; // final model answer (should include tool token if your prompt enforces it)
}

foreach ($response->toolCalls as $call) {
    // inspect tool calls if needed
}

Chat messages and tool calls (Public API)

ChatMessageDto is the main DTO used to build a conversation:

public function __construct(
    public ChatRoleEnum $role,
    public string $content,
    public ToolCallDtoCollection $toolCalls,
    public array $metadata = [],
) { }

To make common cases easier and to guarantee that toolCalls is never null, use the static factories:

ChatMessageDto::createSystemMessage(string $content, array $metadata = []): self;
ChatMessageDto::createUserMessage(string $content, array $metadata = []): self;
ChatMessageDto::createAssistantMessage(string $content, ToolCallDtoCollection $toolCalls, array $metadata = []): self;
ChatMessageDto::createToolMessage(string $content, ToolCallDtoCollection $toolCalls, array $metadata = []): self;

Typical patterns:

  • system/user messages: empty ToolCallDtoCollection (created by the factory),
  • assistant messages: may include tool calls when the model proposes or summarizes tool usage,
  • tool messages: should carry tool results and the corresponding ToolCallDto instances in toolCalls.

Generation parameters (parameters)

Generation settings are a free-form associative array and are provider-specific. The library forwards them 1:1 to the provider payload.

Important:

  • Do not rely on implicit defaults (e.g. temperature). If you do not pass a key, it is not sent.
  • Passing unsupported parameters may result in a provider error.

Providers

If you pass modelId as null, each provider uses its default. For OpenAI, a safe starter is gpt-4o-mini; for Deepseek: deepseek-chat.

HTTP logging and CLI example

You can inject your own HTTP traffic logger via the builder. A convenient demonstration script is included:

php bin/test-ai-tool-chat.php --provider=openai --model=gpt-4o-mini --show-meta=on --log-http=1 --log-headers=0

The script runs 3 scenarios (smoke and two tool-calling flows) and optionally pretty-prints HTTP request/response payloads.

SPI (Service Provider Interface)

Do not depend on internals. External integrations should use only:

  • AdachSoft\AiIntegration\PublicApi - the facade and DTOs to call the model.
  • AdachSoft\AiIntegration\Spi - the small interface and DTOs to implement your own provider.

All other namespaces (Application, Domain, Infrastructure) are internal and may change at any time.

For a complete SPI guide (interface, DTOs, exceptions, examples), see:

  • docs/SPI.md

Testing

  • Run unit and integration tests:
    composer test
    
  • Production checks (require API keys): see tests/Production and bin/test-ai-tool-chat.php.