-
Notifications
You must be signed in to change notification settings - Fork 167
Add default auth model provider #1996
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Add default auth model provider #1996
Conversation
|
cc @sberyozkin |
This comment has been minimized.
This comment has been minimized.
| <artifactId>quarkus-langchain4j-core</artifactId> | ||
| <version>${project.version}</version> | ||
| </dependency> | ||
| <dependency> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @hubert123490
I'm not sure this dependency belongs at the OpenAI common level... It should be at the Azure OpenAI level and the filter should be shipped there. Somehow it needs to replace the one checked at the OpenAI common level, may be by extending the QuarkusOpenAIClient, or being an Alternative CDI bean, it is a bit tricky but should be doable, thanks
This comment has been minimized.
This comment has been minimized.
|
@sberyozkin fair point |
| } | ||
|
|
||
| private void throwIfApiKeysNotConfigured(String apiKey, String adToken, boolean authProviderAvailable, String configName) { | ||
| if ((apiKey != null) == (adToken != null) && !authProviderAvailable) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does this check have to be removed ?
| import io.quarkiverse.langchain4j.auth.ModelAuthProvider; | ||
| import io.quarkus.rest.client.reactive.QuarkusRestClientBuilder; | ||
|
|
||
| public class DefaultOpenAiRestApiFilterResolver implements RestApiFilterResolver { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm just wondering, AFAIK, so far this filter can only be used with Azure OpenAI, I believe for direct OpenAI calls, OpenAI API Key is not passed as a bearer token, @geoand, is it correct ?
Perhaps we can just move this filter out of OpenAI common ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I'm not following. With vanilla OpenAI, the authentication is a bearer token
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, so this filter has to stay
This comment has been minimized.
This comment has been minimized.
| import io.quarkiverse.langchain4j.openai.common.RestApiFilterResolver; | ||
| import io.quarkus.rest.client.reactive.QuarkusRestClientBuilder; | ||
|
|
||
| public class AzureRestApiFilterResolver implements RestApiFilterResolver { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe it has to become a synthetic CDI bean - you can see an example of how such beans are created in AzureOpenAI recorder - and you'd have the config properties available to the function that creates it
| .resolve(builder.configName) | ||
| .ifPresent(modelAuthProvider -> restApiBuilder | ||
| .register(new OpenAiRestApi.OpenAIRestAPIFilter(modelAuthProvider))); | ||
| Map<String, String> configMap = new HashMap<>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the original code should stay
| import io.quarkus.arc.InstanceHandle; | ||
| import io.smallrye.mutiny.infrastructure.Infrastructure; | ||
|
|
||
| public class AzureModelAuthProviderFilter implements ResteasyReactiveClientRequestFilter { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should probably extend the Open AI common one
| private final ModelAuthProvider authorizer; | ||
|
|
||
| public AzureModelAuthProviderFilter() { | ||
| this.authorizer = new ApplicationDefaultAuthProvider(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should make sure it is loaded only when no other custom model auth providers are available, for example, I linked earlier to the demo where an access token acquired after an Entra ID authorization code flow completion is propagated
| MultivaluedMap<String, Object> headers) implements ModelAuthProvider.Input { | ||
| } | ||
|
|
||
| private static class ApplicationDefaultAuthProvider implements ModelAuthProvider { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if we really need the filter resolver at all, and instead, only have this default model auth provider registered as a synthetic CDI bean in the if neither api or ad tokens or custom mode providers are available (this is the check that this PR removes but it should not)
|
Thanks @hubert123490 for working on this PR, I agree it is quite hard to make it work, IMHO this PR should probably be rewritten, please investigate how you can register the default Azure Open AI model auth provider as the synthetic CDI bean. Effectively, the PR should only have the code for the default provider, and updates in the AzureOpenAI recorder and build step processor - the recorder is called by the processor to optionally register this default provider as a cdi bean if neither api key or id token or other model auth provider is registered. |
|
Thanks @sberyozkin for the great insight! I’ll give it a try. |
|
@hubert123490 Np at all, hopefully it will be possible to do something along those lines. You can probably copy and paste one of the functions there in the AzureOpenAI recorder, alongside a matching build step and register your default application model auth provider in a similar fashion. The only problem that may have to be solved is ensure this registration is done, before the check that this PR attempts to remove is run, i.e, the build step that registers the default model auth provider must run earlier, typically this is achieved by the step that must run earlier producing a custom build item for the next build step to expect it as one of the input parameters, @geoand can also advise. So it should be doable |
|
I've tried to add synthetic bean for model auth provider I added in azure recorder but that resulted in However I was successful with BuildConfig approach, such as I added
and in processor And that approach I've already pushed. Since it's default bean it also can be overwritten. Only downside is that even when api-key is provided with quarkus.langchain4j.azure-openai.azure-default-credentials-enabled, the azure model auth provider is used, but maybe it can be handled by warning or exception. Anyways please let me know if it is acceptable one. |
Status for workflow
|
| Status | Name | Step | Failures | Logs | Raw logs |
|---|---|---|---|---|---|
| ✔️ | JVM tests - model-providers - Java 17 | Logs | Raw logs | ||
| ✔️ | JVM tests - model-providers - Java 21 | Logs | Raw logs | ||
| ❌ | JVM tests - model-providers - Java 24 | Set up JDK 24 |
Logs | Raw logs | |
| ❌ | Native tests - multiple-providers | Setup JBang |
Logs | Raw logs | |
| ❌ | Native tests - rag | Setup JBang |
Logs | Raw logs | |
| ❌ | Native tests - rag-pgvector-flyway | Setup JBang |
Logs | Raw logs |

My solution for default azure auth model provider. Please note that Azure advises to use different authentication method for production https://learn.microsoft.com/en-us/dotnet/api/azure.identity.defaultazurecredential?view=azure-dotnet.
However it should be sufficient for development purposes and further collaboration.