adachsoft / ai-integration-anthropic
Anthropic Claude tool-calling SPI adapter for adachsoft/ai-integration.
Package info
gitlab.com/a.adach/ai-integration-anthropic
pkg:composer/adachsoft/ai-integration-anthropic
Requires
- php: >=8.3
- adachsoft/ai-integration: ^0.8.0
- adachsoft/http-transport: ^0.2
- guzzlehttp/guzzle: ^7.0 || ^8.0
Requires (Dev)
- adachsoft/ai-integration-cost: ^0.1
- adachsoft/ai-model-list: ^0.5
- adachsoft/llm-cost-calculator: ^0.1
- adachsoft/php-code-style: ^0.4.2
- friendsofphp/php-cs-fixer: ^3.94
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^13.0
- rector/rector: ^2.3
- vlucas/phpdotenv: ^5.6
README
Integration of Anthropic Claude (tool calling) with the adachsoft/ai-integration library.
Requirements
- PHP
>= 8.3 guzzlehttp/guzzle^7.0 || ^8.0adachsoft/ai-integration^0.8.0
Installation
composer require adachsoft/ai-integration-anthropic
Basic usage
Example of wiring the Anthropic SPI provider with the tool-calling facade from adachsoft/ai-integration:
use AdachSoft\AiIntegration\PublicApi\Builder\ToolCallingChatFacadeBuilder;
use AdachSoft\AiIntegrationAnthropic\AnthropicToolCallingChatSpiFactory;
$apiKey = getenv('ANTHROPIC_KEY');
$factory = new AnthropicToolCallingChatSpiFactory();
$builder = new ToolCallingChatFacadeBuilder();
$builder->withSpiProvider('anthropic', $factory->create($apiKey));
$facade = $builder->build();
Transport modes
AnthropicToolCallingChatSpiFactory::create() supports two transport modes:
non_streaming(default) - legacy buffered mode using classic non-streaming HTTP response read.streaming- request is sent as SSE stream and reconstructed back to the Anthropic JSON response format.
Factory parameters (transportMode, streamingPerChunkTimeoutSeconds) define application-level defaults.
Per-request parameters have higher priority and can override these defaults:
ai_integration-transport_mode(non_streamingorstreaming)ai_integration-streaming_per_chunk_timeout_seconds(positive integer, only for effectivestreamingmode)
Example request-level override:
$request = new ToolCallingChatSpiRequest(
model: 'claude-sonnet-4-20250514',
messages: $messages,
tools: $tools,
parameters: [
'ai_integration-transport_mode' => 'streaming',
'ai_integration-streaming_per_chunk_timeout_seconds' => 45,
],
);
ToolCallingContext::$timeoutSeconds keeps the same SPI meaning in both modes: it is the total request timeout.
In streaming mode, idle timeout between chunks is configured separately via ai_integration-streaming_per_chunk_timeout_seconds (or factory default).
Streaming mode requires allow_url_fopen=1. If it is disabled, the adapter throws a fail-fast SpiException with guidance to enable allow_url_fopen or switch to non_streaming.
With default non_streaming, long-running generations may again be exposed to idle connection drops in some environments.
When this matters, enable streaming explicitly per request.
Anthropic cache configuration
This package exposes explicit cache configuration via ToolCallingChatSpiRequest::$parameters.
All cache-related keys are prefixed with ai_integration-.
Supported cache sections:
ai_integration-cache_system– cache for the system prompt (off,5min,1hour).ai_integration-cache_tools– cache for tool definitions (off,5min,1hour).ai_integration-cache_messages– cache for conversation messages (off,5min,1hour).ai_integration-cache_automatic– Anthropic automatic cache mode (off,5min,1hour).
When ai_integration-cache_messages is enabled (5min or 1hour), you can select strategy with:
ai_integration-cache_messages_strategy– supported strategies:offfirst_userlast_userthreshold_tokens
Additional parameters for threshold_tokens strategy:
ai_integration-cache_messages_threshold_tokens– positive integer threshold (default5000).ai_integration-cache_messages_last_cached_message_id– optional last cached user message identifier.
The cache layer is opt-in and non-intrusive: if you do not provide any ai_integration-* keys,
cache behaviour is disabled.
ai_integration-cache_automatic is mutually exclusive with explicit cache TTL keys (cache_system,
cache_tools, cache_messages). If both modes are enabled, configuration validation fails before request execution.
Response metadata
Cache-aware responses may include these metadata keys:
raw_responseraw_usagecache_breakpoint_message_id
Billing token counters are exposed through tokenUsage->details, not response metadata.
Token usage details
tokenUsage->details contains every numeric field from Anthropic's usage object, recursively flattened with _ (up to three nested levels). Known cache fields include:
| Detail key | Meaning |
|---|---|
cache_creation_input_tokens | Aggregate input tokens written to cache |
cache_read_input_tokens | Input tokens read from cache |
cache_creation_ephemeral_5m_input_tokens | Input tokens written with a five-minute TTL |
cache_creation_ephemeral_1h_input_tokens | Input tokens written with a one-hour TTL |
The set of detail keys is open: new numeric fields returned by Anthropic are exposed automatically.
totalTokens includes base input tokens, cache-write tokens, cache-read tokens and output tokens because
these input categories are mutually exclusive in the Anthropic API.
Request cost
The Anthropic usage mapping can be passed to the optional cost bridge and registered on the facade:
use AdachSoft\AiIntegration\PublicApi\Builder\ToolCallingChatFacadeBuilder;
use AdachSoft\AiIntegrationCost\PublicApi\Factory\SpiCostCalculatorFactory;
use AdachSoft\AiIntegrationCost\PublicApi\Vo\UsageKindMapVo;
use AdachSoft\AiIntegrationAnthropic\Cost\AnthropicUsageKindMap;
$costCalculator = SpiCostCalculatorFactory::create(
$pricingProvider,
new UsageKindMapVo(
AnthropicUsageKindMap::mappings(),
AnthropicUsageKindMap::ignoredDetailKeys(),
),
);
$facade = ToolCallingChatFacadeBuilder::create()
->withSpiProvider('anthropic', $anthropicProvider)
->withCostCalculator($costCalculator)
->build();
$response = $facade->chat($request);
$cost = $response->cost;
When cost->details['is_complete'] is false, the amount is understated. A non-empty
unknown_usage_keys list identifies a billing item that is not covered by the usage mapping.
For full details (TTL semantics, beta headers, strategy behaviour and payload rules), see:
docs/CACHE_STRATEGIES.mddocs/architecture.md
Tests
The default phpunit.xml configuration defines two test suites:
unit– standard tests.production– production/integration tests that require external credentials.
Example commands:
# All tests
vendor/bin/phpunit
# Unit tests only
vendor/bin/phpunit --testsuite unit
# Production tests only
ANTHROPIC_KEY=... vendor/bin/phpunit --testsuite production