adachsoft/ai-tool-call

Unified AI tool-calling abstraction for PHP 8.3 with a clean Public API and an extensible SPI for custom tools.

Installs: 19

Dependents: 4

Suggesters: 0

Security: 0

Stars: 0

Forks: 0

pkg:composer/adachsoft/ai-tool-call

2.0.0 2025-12-04 18:02 UTC

This package is not auto-updated.

Last update: 2025-12-05 05:33:19 UTC


README

Unified AI tool-calling abstraction for PHP 8.3 with a clean Public API and an extensible SPI for custom tools.

  • Public API to list and call tools via a simple facade.
  • SPI to implement your own tools (factories) in a framework-agnostic way.
  • Zero framework assumptions, manual wiring via a small Builder.
  • Uses adachsoft/collection for strict, immutable collections.

Requirements

  • PHP ^8.3
  • adachsoft/collection ^3.0

Installation

composer require adachsoft/ai-tool-call

Quick Start (SPI with factories)

use AdachSoft\AiToolCall\PublicApi\Builder\AiToolCallFacadeBuilder;
use AdachSoft\AiToolCall\PublicApi\Dto\ToolCallRequestDto;
use AdachSoft\AiToolCall\SPI\Collection\ConfigMap;
use AdachSoft\AiToolCall\SPI\Collection\KeyValueMap;
use AdachSoft\AiToolCall\SPI\Collection\TagsCollection;
use AdachSoft\AiToolCall\SPI\Dto\ToolCallRequestDto as SpiRequestDto;
use AdachSoft\AiToolCall\SPI\Dto\ToolCallResultDto as SpiResultDto;
use AdachSoft\AiToolCall\SPI\Dto\ToolDefinitionDto;
use AdachSoft\AiToolCall\SPI\Exception\ToolConfigurationException;
use AdachSoft\AiToolCall\SPI\Factory\ToolFactoryInterface;
use AdachSoft\AiToolCall\SPI\ToolInterface;

final class EchoTool implements ToolInterface
{
    public static function getDefinition(): ToolDefinitionDto
    {
        return new ToolDefinitionDto(
            name: 'echo',
            description: 'Returns input as output',
            parametersSchema: [
                'type' => 'object',
                'properties' => [
                    'text' => ['type' => 'string'],
                ],
            ],
            tags: new TagsCollection(['demo']),
            enabled: true,
        );
    }

    public function callTool(SpiRequestDto $request): SpiResultDto
    {
        return new SpiResultDto(
            'echo',
            new KeyValueMap(['text' => $request->parameters->get('text')])
        );
    }
}

final class EchoToolFactory implements ToolFactoryInterface
{
    public function getToolClass(): string
    {
        return EchoTool::class;
    }

    public function create(ConfigMap $config): ToolInterface
    {
        if ($config->has('invalid')) {
            throw new ToolConfigurationException('Invalid configuration for EchoTool.');
        }

        return new EchoTool();
    }
}

$facade = AiToolCallFacadeBuilder::new()
    ->withSpiFactories([new EchoToolFactory()])
    ->withToolConfigs([
        'echo' => new ConfigMap([]),
    ])
    ->build();

// List available tools (includes built-in current_datetime and your SPI tools)
$tools = $facade->listAvailableTools();
foreach ($tools as $tool) {
    echo $tool->name . PHP_EOL;
}

// Call a SPI tool
$result = $facade->callTool(new ToolCallRequestDto(
    toolName: 'echo',
    parameters: ['text' => 'hello'],
));

var_dump($result->result);

// Call the built-in current_datetime tool
$currentDateTimeResult = $facade->callTool(new ToolCallRequestDto(
    toolName: 'current_datetime',
    parameters: [],
));

var_dump($currentDateTimeResult->result);

Public API

  • Facade: AdachSoft\AiToolCall\PublicApi\AiToolCallFacadeInterface
    • callTool(ToolCallRequestDto): ToolCallResultDto
    • listAvailableTools(): AvailableToolCollection
    • listAvailableToolsByTags(array $tags): AvailableToolCollection

DTOs

  • ToolCallRequestDto(string $toolName, array $parameters)
  • ToolCallResultDto(string $toolName, mixed $result)
  • AvailableToolDto(string $name, string $description, array $parametersSchema, array $tags)
  • AvailableToolCollection

SPI (Service Provider Interface)

Implement custom tools by fulfilling the SPI contracts.

  • AdachSoft\AiToolCall\SPI\ToolInterface

    • callTool(ToolCallRequestDto): ToolCallResultDto
    • static getDefinition(): ToolDefinitionDto
  • AdachSoft\AiToolCall\SPI\Factory\ToolFactoryInterface

    • getToolClass(): string
    • create(ConfigMap $config): ToolInterface
  • ToolDefinitionDto

    • name: string
    • description: string
    • parametersSchema: array<string, mixed>
    • tags: TagsCollection
    • enabled: bool
  • Collections used in SPI:

    • TagsCollection (immutable list of strings)
    • KeyValueMap (immutable map string->mixed)
    • ConfigMap (immutable map string->mixed)
    • ToolCollection (immutable collection of SPI tools)
    • ToolFactoryCollection (immutable collection of SPI tool factories)

Minimal tool example (SPI-only)

use AdachSoft\AiToolCall\SPI\ToolInterface;
use AdachSoft\AiToolCall\SPI\Collection\ToolCollection as SpiToolCollection;
use AdachSoft\AiToolCall\SPI\Dto\ToolDefinitionDto;
use AdachSoft\AiToolCall\SPI\Dto\ToolCallRequestDto as SpiRequest;
use AdachSoft\AiToolCall\SPI\Dto\ToolCallResultDto as SpiResult;
use AdachSoft\AiToolCall\SPI\Collection\TagsCollection;
use AdachSoft\AiToolCall\SPI\Collection\KeyValueMap;

final class EchoTool implements ToolInterface
{
    public static function getDefinition(): ToolDefinitionDto
    {
        return new ToolDefinitionDto(
            name: 'echo',
            description: 'Returns input as output',
            parametersSchema: ['type' => 'object', 'properties' => ['text' => ['type' => 'string']]],
            tags: new TagsCollection(['demo']),
            enabled: true,
        );
    }

    public function callTool(SpiRequest $request): SpiResult
    {
        return new SpiResult('echo', new KeyValueMap(['text' => $request->parameters->get('text')]));
    }
}

$tools = new SpiToolCollection([new EchoTool()]);

Tool discovery & registration

  • No autoscan. The builder does not scan directories.
  • Register tools via:
    • SPI factories using withSpiFactories() and optional withToolConfigs() for configuration maps, or
    • Direct SPI tools using withSpiTools() when tools are already fully configured.
  • The builder always registers CurrentDateTimeToolCaller as a built-in domain tool by default.

Error handling

  • Public API throws PublicApi\Exception\ToolCallFailedException on errors during tool execution.
  • Public API throws PublicApi\Exception\ToolRegistrationException when tool registration or configuration fails while building the facade (e.g. duplicate tool names or invalid factory/config types).
  • SPI exceptions:
    • SPI\Exception\InvalidToolCallException
    • SPI\Exception\ToolExecutionException
    • SPI\Exception\ToolConfigurationException These are mapped through the adapter when calling SPI tools through the Domain.

Versioning

  • Semantic Versioning.
  • Package version is controlled by Git tags (do not set version in composer.json).

License

MIT