use nexus proxy instead of provider-specific embeddings#3250
use nexus proxy instead of provider-specific embeddings#3250
Conversation
| @@ -0,0 +1,143 @@ | |||
| defmodule Console.AI.Nexus do | |||
There was a problem hiding this comment.
This should basically just wrap up to the the openai provider, like how it's done in the AzureOpenAI one. Also, it needs to be definable in DeploymentSettings via graphql + kubernetes api, and not via env var.
5abe0fd to
33d979e
Compare
Greptile SummaryThis PR introduces a Key changes:
Issues found:
Confidence Score: 3/5
Last reviewed commit: 33d979e |
| def embeddings(text, opts \\ []) do | ||
| settings = Settings.cached() | ||
| with {:ok, %mod{} = client} <- client(settings, opts[:client] || :embedding), | ||
| do: mod.embeddings(client, text) | ||
| case settings do | ||
| %DeploymentSettings{ai: %AI{nexus: %{url: url} = nexus}} when is_binary(url) -> | ||
| Nexus.new(nexus) |> Nexus.embeddings(text) | ||
| _ -> | ||
| with {:ok, %mod{} = client} <- client(settings, opts[:client] || :embedding), | ||
| do: mod.embeddings(client, text) | ||
| end | ||
| end |
There was a problem hiding this comment.
The embeddings/2 function ignores the opts[:client] hint when Nexus is configured. This is inconsistent with the documented behavior in the @doc block (line 125), which lists :client as a valid option.
When a caller explicitly passes client: :embedding or client: :tool, that hint is silently discarded in the Nexus branch. Since the :client option is documented as supported but not actually used by the Nexus path, either:
- Update the docs to clarify that
:clientis ignored when Nexus is configured, or - Modify the logic to only use Nexus when
:clientis not explicitly set to something other than:embedding(if provider-specific routing is needed in the future)
Current behavior seems correct (Nexus should always take priority for embeddings), but the interface is misleading.
lib/console/ai/nexus.ex
Outdated
| def embeddings(%__MODULE__{url: url, token: token, embedding_model: model}, text) do | ||
| OpenAI.new(%{ | ||
| base_url: Path.join(url, "/v1"), | ||
| access_token: token, | ||
| embedding_model: model || @default_embedding_model | ||
| }) | ||
| |> OpenAI.embeddings(text) | ||
| end |
There was a problem hiding this comment.
Path.join/2 requires both arguments to be binaries. If url is nil (a valid state since the struct field is String.t() | nil), calling this function directly will raise a FunctionClauseError rather than returning an error tuple, violating the @spec contract.
While Provider.embeddings/2 guards against this with when is_binary(url), direct callers to Nexus.embeddings/2 would not be protected. Add a guard or a separate clause to handle the nil case gracefully:
| def embeddings(%__MODULE__{url: url, token: token, embedding_model: model}, text) do | |
| OpenAI.new(%{ | |
| base_url: Path.join(url, "/v1"), | |
| access_token: token, | |
| embedding_model: model || @default_embedding_model | |
| }) | |
| |> OpenAI.embeddings(text) | |
| end | |
| def embeddings(%__MODULE__{url: url, token: token, embedding_model: model}, text) | |
| when is_binary(url) do | |
| OpenAI.new(%{ | |
| base_url: Path.join(url, "/v1"), | |
| access_token: token, | |
| embedding_model: model || @default_embedding_model | |
| }) | |
| |> OpenAI.embeddings(text) | |
| end | |
| def embeddings(%__MODULE__{url: nil}, _text), | |
| do: {:error, "Nexus url is not configured"} |
michaeljguarino
left a comment
There was a problem hiding this comment.
some of the greptile comments should also be handled I think too
lib/console/ai/nexus.ex
Outdated
| """ | ||
| @spec completion(t(), Console.AI.Provider.history(), keyword) :: Console.error | ||
| def completion(%__MODULE__{}, _messages, _opts) do | ||
| {:error, "completion not implemented for Nexus provider - use chat endpoints directly"} |
There was a problem hiding this comment.
you should be able to call into the openai provider for all of the other callbacks here too
lib/console/ai/nexus.ex
Outdated
| """ | ||
| def new(opts \\ %{}) do | ||
| %__MODULE__{ | ||
| url: Map.get(opts, :url), |
There was a problem hiding this comment.
this is actually deployed as a sidecar, so you should be able to auto-configure it against "http://localhost:8080/...", for instance, you can see it configured here: https://console.plrldemo.onplural.sh/cd/clusters/a1748282-ce8b-48ab-ae7e-326e74fce04e/services/2a95775e-4865-449a-b160-75de27590a0d/pods/plrl-console/console-74dd89c868-jk7v6
(if you auto-configure it you'll need to ensure its using the correct path, can ask sebastian what the path will be for openai endpoints)
lib/console/ai/nexus.ex
Outdated
| } | ||
| end | ||
|
|
||
| defp get_url(opts) do |
There was a problem hiding this comment.
use function head matches here (always more readable and terser)
lib/console/ai/provider.ex
Outdated
| with {:ok, %mod{} = client} <- client(settings, opts[:client] || :embedding), | ||
| do: mod.embeddings(client, text) | ||
| case settings do | ||
| %DeploymentSettings{ai: %AI{nexus: %{url: url} = nexus}} when is_binary(url) -> |
There was a problem hiding this comment.
why does this need to be special cased? It should just use the configured nexus client.
There was a problem hiding this comment.
ok i see the issue, the client/2 function below doesn't properly select a nexus client, and my guess is the AI didn't appropriately add it there. Two things:
- You'd need more test coverage to actually uncover the issue here, my guess is only embeddings are tested and AI force-fixed here.
- Worth actually reading contextual code to catch these prior to review.
3191414 to
dd41d9d
Compare
use nexus proxy instead of provider-specific embeddings. Haven't deleted provider-specific embeddings yet for safety, first I think we make sure this is working before doing any deletions.
Test Plan
unit tests
Checklist
Plural Flow: console