Skip to content

[AI Bundle][Platform] Add result text normalizer chain#2114

Open
wachterjohannes wants to merge 3 commits into
symfony:mainfrom
wachterjohannes:platform-result-text-normalizer-chain
Open

[AI Bundle][Platform] Add result text normalizer chain#2114
wachterjohannes wants to merge 3 commits into
symfony:mainfrom
wachterjohannes:platform-result-text-normalizer-chain

Conversation

@wachterjohannes

@wachterjohannes wachterjohannes commented May 23, 2026

Copy link
Copy Markdown
Contributor
Q A
Bug fix? no
New feature? yes
Docs? no
Issues -
License MIT

This PR adds a normalizer pipeline that cleans the textual content of TextResult (and its parts inside MultiPartResult) after a model call. The fence/Unicode quirks are model-output problems, not provider problems, so the wiring lives in platform and applies across every bridge.

What ships

Symfony\AI\Platform\Result\Normalizer\TextNormalizerInterface:

public function supports(Model $model, ResultInterface $result, array $options): bool;
public function normalize(string $text): string;

supports() receives the original $options so a normalizer can react to e.g. response_format.

Two implementations:

  • JsonFenceStripNormalizer — strips ```json … ``` (and bare ``` … ```) wrappers when the fenced body is valid JSON. Active when the request asks for response_format: json / json_schema, or when the converted result is already an ObjectResult.
  • UnicodeNormalizer — removes Unicode Cf (format control) characters such as zero-width spaces and BOM, and converts non-breaking space (U+00A0) to a regular space. Always active.

PlatformSubscriber listens to ResultEvent at priority 10 (before structured-output processing) and walks the registered normalizers in order. Non-text results pass through untouched; MultiPartResult parts are normalized individually.

TextResult gets a withContent() helper that returns a new instance with replaced content, preserving signature and metadata. Streaming results are intentionally out of scope for this PR.

AI Bundle wiring

The bundle ships both normalizers and the subscriber as services and auto-tags any TextNormalizerInterface implementation with ai.platform.result_normalizer. No user-facing config — normalizers are enabled by default.

@carsonbot carsonbot added AI Bundle Issues & PRs about the AI integration bundle Feature New feature Platform Issues & PRs about the AI Platform component Status: Needs Review labels May 23, 2026
@carsonbot carsonbot changed the title [Platform][AI Bundle] Add result text normalizer chain [AI Bundle][Platform] Add result text normalizer chain May 23, 2026
@wachterjohannes wachterjohannes marked this pull request as draft May 23, 2026 20:38
->tag('kernel.event_subscriber')

// result normalizers
->set('ai.platform.result_normalizer.json_fence_strip', JsonFenceStripNormalizer::class)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure if we should add a configuration for that or if that should be default initialized

@wachterjohannes wachterjohannes marked this pull request as ready for review May 23, 2026 20:50
Add `Result\Normalizer\TextNormalizerInterface` plus a `PlatformSubscriber`
that applies tagged normalizers to text-bearing results after invocation.

Two provider-agnostic normalizers ship:
 - `JsonFenceStripNormalizer` strips Markdown code fences around JSON output
   when `response_format` is `json` / `json_schema` or the result is an
   `ObjectResult`.
 - `UnicodeNormalizer` removes Unicode `Cf` characters (zero-width spaces,
   BOM, etc.) and converts non-breaking spaces to regular spaces.

`TextResult` gets a `withContent()` method returning a new instance with
the swapped content while preserving signature and metadata.

AI Bundle registers both normalizers, the subscriber, and auto-tags any
`TextNormalizerInterface` implementation with `ai.platform.result_normalizer`.
@wachterjohannes wachterjohannes force-pushed the platform-result-text-normalizer-chain branch from 562d831 to 82e6a75 Compare May 27, 2026 07:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI Bundle Issues & PRs about the AI integration bundle Feature New feature Platform Issues & PRs about the AI Platform component Status: Needs Review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants