[AI Bundle][Platform] Add result text normalizer chain#2114
Open
wachterjohannes wants to merge 3 commits into
Open
[AI Bundle][Platform] Add result text normalizer chain#2114wachterjohannes wants to merge 3 commits into
wachterjohannes wants to merge 3 commits into
Conversation
wachterjohannes
commented
May 23, 2026
| ->tag('kernel.event_subscriber') | ||
|
|
||
| // result normalizers | ||
| ->set('ai.platform.result_normalizer.json_fence_strip', JsonFenceStripNormalizer::class) |
Contributor
Author
There was a problem hiding this comment.
not sure if we should add a configuration for that or if that should be default initialized
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`.
562d831 to
82e6a75
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR adds a normalizer pipeline that cleans the textual content of
TextResult(and its parts insideMultiPartResult) after a model call. The fence/Unicode quirks are model-output problems, not provider problems, so the wiring lives inplatformand applies across every bridge.What ships
Symfony\AI\Platform\Result\Normalizer\TextNormalizerInterface:supports()receives the original$optionsso 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 forresponse_format: json/json_schema, or when the converted result is already anObjectResult.UnicodeNormalizer— removes UnicodeCf(format control) characters such as zero-width spaces and BOM, and converts non-breaking space (U+00A0) to a regular space. Always active.PlatformSubscriberlistens toResultEventat priority10(before structured-output processing) and walks the registered normalizers in order. Non-text results pass through untouched;MultiPartResultparts are normalized individually.TextResultgets awithContent()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
TextNormalizerInterfaceimplementation withai.platform.result_normalizer. No user-facing config — normalizers are enabled by default.