Repository navigation
[FEATURE] Add an event to modify the HTTP client of Symfony AI bridges - #40
Conversation
o-ba
left a comment
There was a problem hiding this comment.
Hey @foppelfb and thanks a lot for working on this!
The use case makes total sense, and I'd like to get it in. But I ran into a few things with the current approach that I don't think we can fix with small tweaks.
The main problem is that setting the client on ProviderConfiguration from a middleware doesn't reliably reach the request:
-
The adapter caches the platform per configuration, so whichever call creates it first wins. If the connection check or the grading judge happens to run first in a process, your middleware's client is never used.
-
Fallback providers, smart routing and auto model switch all work with their own
ProviderConfigurationinstances, which don't carry the client. So the retry after a timeout, probably the case you care about most, would run with the default timeout again.
I'm also not too happy about having a Symfony type on ProviderConfiguration. AiM doesn't require symfony/http-client-contracts, and I'd rather not add that dependency for everyone just because Symfony AI is optional.
What do you think about going with your "Alternative 1" instead? A PSR-14 event in SymfonyAiPlatformAdapter, fired when the platform is built, with the configuration and a settable client. It runs exactly where the client matters, it covers fallbacks and rerouting automatically, and the Symfony types stay in the Symfony AI part of the code.
A few smaller things:
- Only dispatch the event (and pass
httpClient) if the bridge factory actually declares that parameter; we already reflectendpointandapiKeythe same way. - Since the platform is cached per configuration, the event fires once per provider record. Worth a sentence in the docs so nobody expects per-request control.
- A test that goes through the adapter would be great: a listener sets a client, and the factory receives it.
|
Hi @o-ba I re-set the branch and changed the approach to your preferred Alternative 1, creating an Event which is fired in case the factory exposes an httpClient argument in its factory method(s). One thing I had problems with is getting the EventDispatcherInterface injected at this stage, so I opted for a runtime instantiation. The try/catch is in case the HttpClientInterface is not available. Sadly this Interface is only available in the contracts-library from Symfony, hence the dev-dependency. I added notes in Pipeline.md and added a test for testing the correct handling. I tested it as well against my setup and implementation, again with 3 different providers, and it works as desired. |
o-ba
left a comment
There was a problem hiding this comment.
Thanks @foppelfb, this is much better. A few things before we can merge:
SymfonyAiPlatformAdapter.phpgot a B-Factor/Sudhaus7 copyright header instead of the aim one. Please restore it and use the aim header for the new event too.- What do you think about
ModifySymfonyAiHttpClientEventas naming? - Please add one Test that goes through the adapter: a listener sets a client, and the factory receives it. Right now the new path isn't covered at all.
- Please drop the try/catch. A failing listener would silently fall back to the default client. And a factory that declares
httpClientalready requires the contracts package, so the interface is always there. - Let's move the event to
Provider/SymfonyAi/, since it carries a Symfony type. symfony/http-clientin require-dev isn't needed since the contracts package is enough.- Please add a changelog entry.
|
@o-ba Thanks for the input. The test actually was there, just not added.. |
A Symfony AI bridge creates its own HTTP client unless its factory gets one, so proxies, custom headers or longer timeouts (e.g. for image generation) could not be configured. When a bridge factory declares an `httpClient` argument, the new ModifySymfonyAiHttpClientEvent is dispatched with the provider configuration, and the client a listener sets is passed to the factory. It is dispatched after the argument fallback, so a client never replaces the argument the factory requires. As the provider is cached per configuration, the event fires once per configuration and process. Resolves: b13#33
Tasks:
Resolves: #33
Releases: main