Skip to content

Third-party Symfony AI bridges get a malformed provider identifier #32

Description

@martin-helmich

Disclaimer: This bug report was created with AI assistance, but was verified manually.


  • Extension version: 0.4.1
  • TYPO3: 14.3
  • symfony/ai-platform: 0.13.0

PR #25 (fixing #21) switched bridge discovery from the symfony/ai-*-platform name pattern to the symfony-ai-platform Composer package type, so that third-party bridges are found too. Discovery itself works. But the identifier and display name are still derived on the old naming assumption, so the very packages #25 set out to support end up with a broken identifier.

The derivation still strips a hardcoded symfony/ai- prefix

Classes/DependencyInjection/SymfonyAiCompilerPass.php:387 (deriveIdentifier()) and :404 (deriveName()) both start with:

$slug = preg_replace('/^symfony\/ai-/', '', $packageName);
$slug = preg_replace('/-platform$/', '', $slug);

For any vendor other than symfony/, that first pattern does not match, so the vendor prefix — including the slash — survives:

package identifier display name
symfony/ai-open-ai-platform openai Symfony AI: OpenAI
symfony/ai-anthropic-platform anthropic Symfony AI: Anthropic
mittwald/symfony-ai-platform mittwald/symfonyai Symfony AI: Mittwald/symfony Ai
acme/ai-cool-platform acme/aicool Symfony AI: Acme/ai Cool

Why the identifier matters beyond cosmetics

It is not only shown in the backend, it is used as a key in two places:

  • DI service id'aim.symfony_ai.' . $bridge['identifier'] (SymfonyAiCompilerPass.php:107), giving aim.symfony_ai.mittwald/symfonyai.
  • Persisted TCA value'value' => $identifier in Classes/Tca/ItemsProcFunc/AiProvidersItemsProcFunc.php::getAiProviders(), so the slash is written into tx_aim_provider rows and is what every later AiProviderRegistry::hasProvider() / getProvider() lookup keys on.

The display name is a smaller problem but visible to every editor: the provider select in the backend reads "Symfony AI: Mittwald/symfony Ai".

Reproduction

TYPO3 14.3 + b13/aim: ^0.4.1 + any bridge from a non-symfony/ vendor declaring "type": "symfony-ai-platform". Running AiM's own compiler pass against the container:

$c = new ContainerBuilder();
$c->setDefinition(AiProviderRegistry::class, new Definition(AiProviderRegistry::class));
(new SymfonyAiCompilerPass())->process($c);

$calls = $c->findDefinition(AiProviderRegistry::class)->getMethodCalls();
foreach ($calls as $call) {
    echo '  - ' . $call[1][0]->getArgument(0) . ' (' . $call[1][0]->getArgument(1) . ")\n";
}

With mittwald/symfony-ai-platform installed:

  - mittwald/symfonyai (Symfony AI: Mittwald/symfony Ai)

(That bridge additionally had to be fixed on our side first — it shipped the pre-0.8 PlatformFactory::create() rather than Factory::createProvider(), so it never reached this point: mittwald/symfony-ai-platform#18. The output above is from the fixed version.)

Suggested change

The bridge already states its canonical name, and the Symfony AI contract is the place it does so: ProviderInterface::getName(): non-empty-string. Symfony's own bridges declare it right in the factory signature — Factory::createProvider(..., string $name = 'openai') — and a bridge that hardcodes it does so in the new Provider(...) call. It is a routing key inside Symfony AI itself, not prose, and no bridge author has to know AiM exists to have set it.

It can be read at container-compile time, with no API key and no network:

$provider = $factoryClass::createProvider('');
$identifier = $provider->getName();

Against mittwald/symfony-ai-platform that returns 'mittwald' in ~18 ms; against symfony/ai-open-ai-platform it returns 'openai'. Instantiating at compile time inside a try/catch is already the pattern this pass uses for the model catalog a few lines down (SymfonyAiCompilerPass.php:231-241), so it is not a new kind of risk — and a factory that validates its API key eagerly just falls into the catch, where today's derived value can stay as a last-resort fallback for the service id.

That also disposes of the display name. getName() gives openai / anthropic / mittwald — the same names these providers carry in the Symfony AI docs. The existing $nameMap in deriveName() can stay as pure prettification, keyed on that stable slug instead of on the package name, so an unmapped bridge degrades to mittwald rather than to Mittwald/symfony Ai.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions