adachsoft / ai-agent-config-repository
AI agent configuration repository library for AdachSoft projects.
Package info
gitlab.com/a.adach/ai-agent-config-repository
pkg:composer/adachsoft/ai-agent-config-repository
Requires
- php: ^8.3
- adachsoft/ai-agent: ^0.9 || ^0.10
- adachsoft/ai-integration: ^0.7
- adachsoft/ai-tool-call: ^2.0
- adachsoft/collection: ^3.0
Requires (Dev)
- adachsoft/php-code-style: ^0.3
- friendsofphp/php-cs-fixer: ^3.89
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^12.4
- rector/rector: ^2.3
README
Framework-agnostic library for storing and using AI agent configuration for agents built with the adachsoft/ai-agent runtime.
This package provides:
- a model of agent configuration (VO/DTO/Collection/Exception),
- SPI repository contracts for agent configurations, system prompts, and group catalogs,
- a Public API for creating
AiAgentFacadeInterfaceinstances based on configuration loaded from repositories.
Requirements
- PHP:
^8.3 adachsoft/collection:^3.0adachsoft/ai-agent:^0.9 || ^0.10adachsoft/ai-integration:^0.7adachsoft/ai-tool-call:^2.0
Installation
composer require adachsoft/ai-agent-config-repository
Package structure
Root namespace:
AdachSoft\AiAgentConfigRepository\...
Directory layout:
src/AiAgentConfigRepository/PublicApiVo– value objects for agent, prompt, tool, tool group, agent group, and conversation context profile identifiersDto– agent configuration, group definition, and policies DTOsCollection– typed immutable collectionsException– exceptions exposed by the Public APIAiAgentFromConfigFactoryInterface– factory creatingAiAgentFacadeInterfacefrom config
src/AiAgentConfigRepository/SPIRepository– repository contracts for configurations, prompts, and group catalogsMapper– mapper interface from agent definition to DTOs fromadachsoft/ai-agent
src/AiAgentConfigRepository/InfrastructureRepository/InMemory– in-memory reference implementationsRepository/JsonFile– JSON file-based group catalog implementationsFactory– implementation ofAiAgentFromConfigFactoryInterface
Public API
Value Objects (VO)
AdachSoft\AiAgentConfigRepository\PublicApi\Vo\AgentIdVoAdachSoft\AiAgentConfigRepository\PublicApi\Vo\AgentGroupIdVoAdachSoft\AiAgentConfigRepository\PublicApi\Vo\PromptIdVoAdachSoft\AiAgentConfigRepository\PublicApi\Vo\ToolIdVoAdachSoft\AiAgentConfigRepository\PublicApi\Vo\ToolGroupIdVoAdachSoft\AiAgentConfigRepository\PublicApi\Vo\ConversationContextProfileIdVo
Each VO is a readonly wrapper around a string exposed as public string $value. Every VO validates its invariant in the constructor and throws its dedicated Invalid…Exception for invalid identifiers: empty, whitespace-only, outer-whitespace, and (where applicable) disallowed characters or path traversal / absolute paths.
DTOs
AdachSoft\AiAgentConfigRepository\PublicApi\Dto\AgentPoliciesDto- retry / backoff / limits / timeouts / trimming / tools-related policies
AdachSoft\AiAgentConfigRepository\PublicApi\Dto\AgentDefinitionDto- provider-agnostic, complete agent definition containing identifier, name, description, provider and model IDs, prompt ID and system prompt text, model parameters, timeout, allowed tool IDs and tool group IDs, agent group IDs the agent belongs to (optional, may be null), agent policies, and an optional conversation context strategy profile identifier used to resolve shared conversation context profiles
AdachSoft\AiAgentConfigRepository\PublicApi\Dto\ToolGroupDefinitionDto- tool group identifier, optional name and description, and tool IDs
AdachSoft\AiAgentConfigRepository\PublicApi\Dto\AgentGroupDefinitionDto- agent group identifier, name, and description
AdachSoft\AiAgentConfigRepository\PublicApi\Dto\ConversationContextProfileDto- raw contents of a single conversation context profile (identifier, optional parent profile, optional strategy identifier, and parameters map)
AdachSoft\AiAgentConfigRepository\PublicApi\Dto\ResolvedConversationContextStrategyDto- fully resolved conversation context strategy identifier and parameters after applying the extends chain
Collections
AdachSoft\AiAgentConfigRepository\PublicApi\Collection\ToolIdVoCollectionAdachSoft\AiAgentConfigRepository\PublicApi\Collection\ToolGroupIdVoCollectionAdachSoft\AiAgentConfigRepository\PublicApi\Collection\AgentGroupIdVoCollectionAdachSoft\AiAgentConfigRepository\PublicApi\Collection\ToolGroupDefinitionDtoCollectionAdachSoft\AiAgentConfigRepository\PublicApi\Collection\AgentGroupDefinitionDtoCollection
All collections extend AdachSoft\Collection\AbstractImmutableCollection and are strongly typed to their declared element type.
Exceptions
Namespace:
AdachSoft\AiAgentConfigRepository\PublicApi\Exception
Defined exceptions include:
AgentNotFoundExceptionAgentAlreadyExistsExceptionSystemPromptNotFoundExceptionSystemPromptAlreadyExistsExceptionAgentRuntimeBuildFailedExceptionInvalidAgentIdExceptionInvalidPromptIdExceptionInvalidToolIdExceptionInvalidToolGroupIdExceptionInvalidAgentGroupIdExceptionInvalidConversationContextProfileIdExceptionToolGroupNotFoundExceptionToolGroupAlreadyExistsExceptionAgentGroupNotFoundExceptionConversationContextProfileNotFoundExceptionInvalidToolGroupFileExceptionInvalidAgentGroupsFileExceptionInvalidConversationContextProfileFileExceptionCircularConversationContextProfileException
SPI layer
AgentConfigRepositoryInterface
AdachSoft\AiAgentConfigRepository\SPI\Repository\AgentConfigRepositoryInterface is the full CRUD contract for agent configuration, operating on AgentDefinitionDto instances identified by AgentIdVo.
SystemPromptRepositoryInterface
AdachSoft\AiAgentConfigRepository\SPI\Repository\SystemPromptRepositoryInterface is the full CRUD contract for system prompts, operating on prompt contents identified by PromptIdVo.
ToolGroupRepositoryInterface
AdachSoft\AiAgentConfigRepository\SPI\Repository\ToolGroupRepositoryInterface is the full CRUD contract for tool group definitions.
ConversationContextProfileRepositoryInterface
AdachSoft\AiAgentConfigRepository\SPI\Repository\ConversationContextProfileRepositoryInterface is a read-only contract for named conversation context profiles, operating on ConversationContextProfileDto instances identified by ConversationContextProfileIdVo. Conversation context profile catalogs are maintained by people in JSON files, so a write API is intentionally not exposed.
AgentGroupRepositoryInterface
AdachSoft\AiAgentConfigRepository\SPI\Repository\AgentGroupRepositoryInterface is a read-only contract for agent group definitions. Agent group catalogs are maintained by people in a JSON file, so a write API is intentionally not exposed.
AgentDefinitionMapperInterface
AdachSoft\AiAgentConfigRepository\SPI\Mapper\AgentDefinitionMapperInterface transforms an AgentDefinitionDto into the DTOs required by the adachsoft/ai-agent runtime and wires the required ports.
In-memory implementations
The library ships with reference in-memory repository implementations:
InMemoryAgentConfigRepositoryInMemorySystemPromptRepositoryInMemoryToolGroupRepositoryInMemoryAgentGroupRepository
The agent group repository accepts an AgentGroupDefinitionDtoCollection at construction time. The tool group repository starts empty and provides full CRUD.
File-based implementations
JsonFileToolGroupRepository
JsonFileToolGroupRepository implements the tool group CRUD contract using one JSON file per group in a configured directory. A group file is named <group-id>.json and has this format:
{
"name": "PHP developer tools",
"description": "",
"tool_ids": ["current_datetime", "file_read", "phpunit_runner"]
}
name and description may be null; tool_ids must be an array of non-empty tool identifiers.
JsonFileAgentGroupRepository
JsonFileAgentGroupRepository implements the read-only agent group contract using one JSON file for the complete catalog:
{
"developer": {
"name": "Developers",
"description": "All developer agents"
},
"developer_php": {
"name": "PHP developers",
"description": ""
}
}
Every group requires a non-empty name and a description string. Unknown keys are rejected to prevent catalog typos.
Agent factory from configuration
AiAgentFromConfigFactoryInterface creates AiAgentFacadeInterface instances based on AgentIdVo values. Its infrastructure implementation uses the agent configuration repository, system prompt repository, mapper, tool calling port, tool call port, and AiAgentBuilder to build the final runtime agent.
Tool availability filtering
Agents built by this library get their tool list from two sources: the static agent definition (tool_ids) and the actual tool layer provided by AiToolCallFacadeInterface. Without synchronisation between these sources the runtime may fail with an AgentConfigurationException("Configured tool not found in system: <name>") thrown by AdachSoft\AiAgent\Infrastructure\Adapter\Tool\AiToolPortAdapter::listTools() when allowAllTools === false.
To address this, the library exposes:
- an SPI port
ToolAvailabilityFilterInterfacethat lets you decide which tools are actually available at runtime, - a public service
AgentConfigToolFilterthat applies aToolAvailabilityFilterInterfaceto anAgentConfigDtoproduced by the mapper fromadachsoft/ai-agent.
Port signature:
namespace AdachSoft\AiAgentConfigRepository\SPI\ToolAvailability;
interface ToolAvailabilityFilterInterface
{
public function isAvailable(string $toolName): bool;
}
The implementation:
- must be stateless with respect to a single call,
- must not perform I/O operations (no network, filesystem, database, etc.),
- returns
trueif the tool with the given name is available in the current runtime,falseotherwise.
The public factory integrates the filter as an optional argument:
public function createById(
AgentIdVo $agentIdVo,
?PublicEventPublisherInterface $publicEventPublisher = null,
?ToolAvailabilityFilterInterface $toolAvailabilityFilter = null,
): AiAgentFacadeInterface;
Passing null keeps the previous behaviour: all tools declared in the agent configuration are passed through without filtering.
A minimal usage example:
use AdachSoft\AiAgentConfigRepository\PublicApi\AiAgentFromConfigFactoryInterface;
use AdachSoft\AiAgentConfigRepository\PublicApi\Vo\AgentIdVo;
use AdachSoft\AiAgentConfigRepository\SPI\ToolAvailability\ToolAvailabilityFilterInterface;
final class ProductionToolAvailabilityFilter implements ToolAvailabilityFilterInterface
{
public function isAvailable(string $toolName): bool
{
// Example: disable expensive or unsafe tools in production
return !in_array($toolName, ['debug_shell', 'unsafe_http'], true);
}
}
/** @var AiAgentFromConfigFactoryInterface $factory */
$filter = new ProductionToolAvailabilityFilter();
$agent = $factory->createById(
new AgentIdVo('my-agent'),
publicEventPublisher: null,
toolAvailabilityFilter: $filter,
);
If filtering removes all tools, the resulting agent will simply run without tools; this is a valid configuration and no exception is thrown.
Conversation context profiles
Conversation context profiles are named, shared configuration fragments for conversation context strategies. They live in a dedicated directory as JSON files and can be referenced from AgentDefinitionDto by ConversationContextProfileIdVo.
Each profile is stored in a separate file named <profile-id>.json:
{
"extends": "php_dev_base",
"strategy_id": "tool_window_compaction",
"params": {
"tool_identifier_fields": {
"task": ["operation", "id", "task_id"]
}
}
}
Supported keys:
extends(optional) – non-empty string identifier of the parent profile;strategy_id(optional) – non-empty string identifier of the conversation context strategy;params(optional) – map of non-empty string keys to arbitrary JSON values.
Unknown keys are rejected to prevent typos.
Extends chain and parameter merging
AdachSoft\\AiAgentConfigRepository\\PublicApi\\Service\\ConversationContextProfileResolver walks the extends chain starting from the requested profile up to the root profile, detects cycles, and then merges configuration from root to leaf.
strategy_id– the effective value is taken from the closest profile to the leaf that defines it; if no profile in the chain defines a strategy, anInvalidConversationContextProfileFileExceptionis thrown.params– merged with a depth of exactly two levels:- top-level keys are merged; child keys override parent keys;
- if both parent and child values for a given top-level key are arrays, their keys are merged shallowly and child values replace parent values for conflicting keys;
- in all other cases (at least one non-array value), the child value replaces the parent value entirely.
Cycle detection uses the full chain of visited identifiers and throws CircularConversationContextProfileException when a cycle is found. Missing profiles in the chain result in ConversationContextProfileNotFoundException.
Usage example
use AdachSoft\\AiAgentConfigRepository\\Infrastructure\\Repository\\JsonFile\\JsonFileConversationContextProfileRepository;
use AdachSoft\\AiAgentConfigRepository\\PublicApi\\Service\\ConversationContextProfileResolver;
use AdachSoft\\AiAgentConfigRepository\\PublicApi\\Vo\\ConversationContextProfileIdVo;
$repository = new JsonFileConversationContextProfileRepository(__DIR__ . '/config/conversation_context_profiles');
$resolver = new ConversationContextProfileResolver($repository);
$resolved = $resolver->resolve(new ConversationContextProfileIdVo('php_dev_base'));
$strategyId = $resolved->strategyId;
$params = $resolved->params;
The profile repository contract is intentionally read-only; profiles are edited by humans in JSON files and consumed via the resolver.
Usage example
use AdachSoft\AiAgentConfigRepository\Infrastructure\Factory\AiAgentFromConfigFactory;
use AdachSoft\AiAgentConfigRepository\Infrastructure\Repository\InMemory\InMemoryAgentConfigRepository;
use AdachSoft\AiAgentConfigRepository\Infrastructure\Repository\InMemory\InMemorySystemPromptRepository;
use AdachSoft\AiAgentConfigRepository\PublicApi\Vo\AgentIdVo;
$agentConfigRepository = new InMemoryAgentConfigRepository();
$systemPromptRepository = new InMemorySystemPromptRepository();
$agentId = new AgentIdVo('my-agent');
// Compose the remaining runtime dependencies and create the factory.
Upgrade guide 0.1.x → 0.2.0
| 0.1.x | 0.2.0 |
|---|---|
PublicApi\Vo\AgentId | PublicApi\Vo\AgentIdVo |
PublicApi\Vo\PromptId | PublicApi\Vo\PromptIdVo |
PublicApi\Vo\ToolId | PublicApi\Vo\ToolIdVo |
PublicApi\Vo\ToolGroupId | PublicApi\Vo\ToolGroupIdVo |
PublicApi\Vo\AgentGroupId | PublicApi\Vo\AgentGroupIdVo |
PublicApi\Collection\ToolIdCollection | PublicApi\Collection\ToolIdVoCollection |
PublicApi\Collection\ToolGroupIdCollection | PublicApi\Collection\ToolGroupIdVoCollection |
PublicApi\Collection\AgentGroupIdCollection | PublicApi\Collection\AgentGroupIdVoCollection |
The renamed value objects now validate their constructor input and throw a dedicated Invalid…Exception; empty, whitespace-only, and outer-whitespace identifiers must be corrected by consumers.
Tests and quality
The project is configured with PHPUnit, PHPStan, Rector, and PHP CS Fixer.
vendor/bin/phpunit
vendor/bin/phpstan analyse src tests
vendor/bin/rector process src tests --dry-run
vendor/bin/php-cs-fixer fix --dry-run --diff