madj2k / ai-core
Framework-independent AI, vector store and indexing core shared by Madj2k integrations.
Requires
- php: ^8.2
- ext-json: *
- ext-mbstring: *
- guzzlehttp/guzzle: ^7.8
- hkulekci/qdrant: ^1.0
- openai-php/client: ^0.10
- psr/http-message: ^1.1 || ^2.0
- psr/log: ^3.0
Requires (Dev)
- phpunit/phpunit: ^10.5 || ^11.0 || ^12.0
This package is auto-updated.
Last update: 2026-08-19 10:14:41 UTC
README
madj2k/ai-core contains the framework-independent assistant runtime plus AI, vector-store and indexing building blocks. The indexing core owns source identities, chunking, embedding generation, vector replacement and indexer discovery.
It has no TYPO3 or Symfony container dependency. Applications provide configuration objects and
compose connectors and resolvers through constructor injection.
TYPO3 source discovery, persistence, TCA, controllers, session-backed memory, persistent logging and HTTP integration remain in madj2k/ai-assistant.
Requirements
- PHP 8.2 or newer
- JSON and mbstring extensions
Installation
composer require madj2k/ai-core
Tests
composer install
composer test
The test suite is framework-independent and does not bootstrap TYPO3.
Chat options
Host applications pass user-facing preferences as one compact ChatOptions object on each
AssistantRequest. It contains the normalized response language, its optional BCP 47 code and
the plain-language preference. The response language overrides language inferred from the
question, quoted text or retrieved documents.
The prompt builder applies these preferences only to answer generators and quality gates. Query optimization and retrieval remain unaffected. Technical accessibility such as keyboard support, focus handling and screen-reader semantics belongs to the host application's frontend and is not an optional core setting.
For explicit utility interactions, the orchestrator also provides handleDirect(). It uses the
assistant profile's configured AI connector and default model but bypasses all pipeline processors,
retrieval and vector-store access. The caller decides when this route is appropriate; AI Core does
not classify user input. Direct interactions can optionally be written to conversation memory.
Public API and extension points
Integrations should depend on the provided interfaces, DTOs, configuration contracts and public facades. Custom pipeline processors, prompt context builders, connectors, client factories, indexers and file adapters are integrated through their corresponding interfaces or abstract base classes.
Classes marked with @internal are bundled implementations or provider-specific helpers. They may
change without backward-compatibility guarantees and should not be extended or referenced by
integrations. The annotation does not restrict direct use in tests.
Pipeline configuration
Pipeline steps run in their configured order. Their stage describes the semantic position of the step; it does not reorder the pipeline. A common retrieval-augmented pipeline is:
- Query optimizer (
pre_retrieval) - Retriever (
retrieval) - Optional query optimizer (
post_retrieval) - Optional second retriever (
retrieval) - Context optimizer (
post_retrieval) - Answer generator (
pre_answer) - Optional quality gate (
post_answer)
Every retriever step has a unique, prompt-visible title and an optional collection override. The title also names the retrieval group. Each retriever appends its group to the retrievals collected so far. Context chunk and character limits are applied to every group independently before the consuming LLM step applies its final global context limit. Vector store connections resolve from the retriever-step override and then the assistant-profile default. Collections resolve from the step override and then the effective connection default. Collection overrides must be included in that connection's configured collection list.
The validator uses the following stage and dependency rules:
| Processor type | Expected stage | Dependency |
|---|---|---|
| Query optimizer | pre_retrieval or post_retrieval |
A post-retrieval optimizer should follow a retriever or memory step. |
| Retriever | retrieval |
None |
| Context optimizer | post_retrieval |
Must follow a retriever or memory step. |
| Answer generator | pre_answer |
Must not run after a quality gate. |
| Quality gate | post_answer |
Must follow an answer generator. |
| Memory | Any | None |
Invalid dependencies, duplicate persisted step UIDs, unknown processors and processor/type mismatches stop execution before the first processor runs. Unexpected stages, multiple answer generators or quality gates, and unusual failure strategies are reported as validation warnings. This permits custom pipelines without silently accepting configurations that cannot work.
Failure strategies apply when a processor throws an exception:
stopaborts the pipeline and rethrows the exception.continuelogs the failure and runs the next step.fallbackis a deprecated alias ofcontinue; it does not execute a separate fallback action.
Answer generators and quality gates should normally use stop, because they define the visible
answer. During streaming, only the final answer-producing step streams to the user. Once that step
has emitted data, its failure always stops execution to avoid returning a partial answer as if it
were complete.
Logging and diagnostics
The core does not select a log file or storage backend. Applications inject a
PipelineLoggerInterface implementation and decide whether events are written to a database,
PSR logger, file or observability service. Validation warnings use the event name
pipeline.validation.warning; failed steps use step.failed.
The TYPO3 madj2k/ai-assistant integration stores pipeline events in
tx_aiassistant_pipeline_trace. Configure tracing under AI Assistant > Configuration:
chat.pipelineLog.mode = errorsstores failed events only.chat.pipelineLog.mode = verbosestores the complete pipeline trace, including validation warnings.chat.pipelineLog.writePsrLog = 1additionally forwards enabled events to TYPO3's PSR logger.
Stored traces can be inspected under AI Assistant > Diagnostics and filtered by chat identifier. This is the primary place to follow one request through its pipeline steps.
The extension configures its PSR log file as var/log/tx_aiassistant.log. General TYPO3 errors are
usually written to files matching var/log/typo3_*.log. In a DDEV project, the files can be followed
from the project root with:
ddev exec tail -f /var/www/html/var/log/tx_aiassistant.log ddev exec sh -c 'tail -f /var/www/html/var/log/typo3_*.log'
Normal pipeline events are debug-level diagnostics and are most reliably inspected in the backend
Diagnostics view with pipeline log mode set to verbose. File output depends on the application's
PSR log-level configuration.
Connector resilience
OpenAI and Qdrant clients are created through injectable factories. The default factories use Guzzle with explicit request and connection timeouts. Provider requests use bounded exponential backoff for transient network errors, rate limits and selected HTTP status codes.
The default policy uses three attempts, a 250 ms initial delay, a 2 second maximum delay, a 30 second request timeout and a 10 second connection timeout. Streaming requests are retried only before the first response chunk has been emitted, preventing duplicate output.
Applications can adjust the policy without implementing a provider connector:
use Madj2k\AiCore\Connection\Ai\OpenAiConnector; use Madj2k\AiCore\Connection\Resilience\RetryPolicy; $connector = new OpenAiConnector( retryPolicy: new RetryPolicy( maxAttempts: 4, initialDelayMilliseconds: 500, timeoutSeconds: 45.0, connectTimeoutSeconds: 10.0, ), );
For isolated tests or custom transports, implement OpenAiClientFactoryInterface or
QdrantClientFactoryInterface and inject the factory into the connector. Final provider errors
expose the provider, operation, HTTP status, retryability and number of attempts through
ApiException or VectorDatabaseException.
License
GNU General Public License 2.0 or later. See LICENSE.