using providers
Some checks failed
CI/CD Pipeline / build (push) Failing after 4s

This commit is contained in:
2026-03-13 15:55:05 -06:00
parent 4de7db6f56
commit 179149b986
7 changed files with 80 additions and 37 deletions

View File

@@ -40,11 +40,11 @@ defmodule ElixirAi.ChatUtils do
}
end
def request_ai_response(server, messages, tools) do
def request_ai_response(server, messages, tools, provider) do
Task.start(fn ->
api_url = Application.fetch_env!(:elixir_ai, :ai_endpoint)
api_key = Application.fetch_env!(:elixir_ai, :ai_token)
model = Application.fetch_env!(:elixir_ai, :ai_model)
api_url = provider.completions_url
api_key = provider.api_token
model = provider.model_name
if is_nil(api_url) or api_url == "" do
Logger.warning("AI endpoint is empty or nil")

View File

@@ -38,12 +38,18 @@ defmodule ElixirAi.ChatRunner do
last_message = List.last(messages)
provider =
case Conversation.find_provider(name) do
{:ok, p} -> p
_ -> nil
end
if last_message && last_message.role == :user do
Logger.info(
"Last message role was #{last_message.role}, requesting AI response for conversation #{name}"
)
ElixirAi.ChatUtils.request_ai_response(self(), messages, tools(self(), name))
ElixirAi.ChatUtils.request_ai_response(self(), messages, tools(self(), name), provider)
end
{:ok,
@@ -53,9 +59,7 @@ defmodule ElixirAi.ChatRunner do
streaming_response: nil,
pending_tool_calls: [],
tools: tools(self(), name),
ai_provider_url: Application.get_env(:elixir_ai, :ai_provider_url),
ai_model: Application.get_env(:elixir_ai, :ai_model),
ai_token: Application.get_env(:elixir_ai, :ai_token)
provider: provider
}}
end
@@ -107,7 +111,13 @@ defmodule ElixirAi.ChatRunner do
store_message(state.name, new_message)
new_state = %{state | messages: state.messages ++ [new_message]}
ElixirAi.ChatUtils.request_ai_response(self(), new_state.messages, state.tools)
ElixirAi.ChatUtils.request_ai_response(
self(),
new_state.messages,
state.tools,
state.provider
)
{:noreply, new_state}
end
@@ -296,7 +306,13 @@ defmodule ElixirAi.ChatRunner do
if new_pending_tool_calls == [] do
broadcast_ui(state.name, :tool_calls_finished)
ElixirAi.ChatUtils.request_ai_response(self(), state.messages ++ [new_message], state.tools)
ElixirAi.ChatUtils.request_ai_response(
self(),
state.messages ++ [new_message],
state.tools,
state.provider
)
end
{:noreply,

View File

@@ -52,25 +52,16 @@ defmodule ElixirAi.ConversationManager do
def handle_call(
{:create, name, ai_provider_id},
_from,
%{conversations: conversations, subscriptions: subscriptions} = state
%{conversations: conversations} = state
) do
if Map.has_key?(conversations, name) do
{:reply, {:error, :already_exists}, state}
else
case Conversation.create(name, ai_provider_id) do
:ok ->
case start_and_subscribe(name, subscriptions) do
{:ok, pid, new_subscriptions} ->
{:reply, {:ok, pid},
%{
state
| conversations: Map.put(conversations, name, []),
subscriptions: new_subscriptions
}}
{:error, _reason} = error ->
{:reply, error, state}
end
reply_with_started(name, state, fn new_state ->
%{new_state | conversations: Map.put(new_state.conversations, name, [])}
end)
{:error, _} = error ->
{:reply, error, state}
@@ -81,16 +72,10 @@ defmodule ElixirAi.ConversationManager do
def handle_call(
{:open, name},
_from,
%{conversations: conversations, subscriptions: subscriptions} = state
%{conversations: conversations} = state
) do
if Map.has_key?(conversations, name) do
case start_and_subscribe(name, subscriptions) do
{:ok, pid, new_subscriptions} ->
{:reply, {:ok, pid}, %{state | subscriptions: new_subscriptions}}
{:error, _reason} = error ->
{:reply, error, state}
end
reply_with_started(name, state)
else
{:reply, {:error, :not_found}, state}
end
@@ -148,6 +133,17 @@ defmodule ElixirAi.ConversationManager do
end
end
defp reply_with_started(name, state, update_state \\ fn s -> s end) do
case start_and_subscribe(name, state.subscriptions) do
{:ok, pid, new_subscriptions} ->
new_state = update_state.(%{state | subscriptions: new_subscriptions})
{:reply, {:ok, pid}, new_state}
{:error, _reason} = error ->
{:reply, error, state}
end
end
defp start_and_subscribe(name, subscriptions) do
result =
case Horde.DynamicSupervisor.start_child(

View File

@@ -113,5 +113,23 @@ defmodule ElixirAi.Conversation do
end
end
def find_provider(name) do
sql = """
SELECT p.name, p.model_name, p.api_token, p.completions_url
FROM conversations c
JOIN ai_providers p ON c.ai_provider_id = p.id
WHERE c.name = $(name)
LIMIT 1
"""
params = %{"name" => name}
case DbHelpers.run_sql(sql, params, "conversations", Provider.schema()) do
{:error, _} -> {:error, :db_error}
[] -> {:error, :not_found}
[row | _] -> {:ok, struct(Provider, row)}
end
end
defp now, do: DateTime.truncate(DateTime.utc_now(), :second)
end

View File

@@ -48,7 +48,10 @@ defmodule ElixirAi.MessageStorageTest do
test "run_sql is called with user message params" do
conv_name = setup_conversation()
stub(ElixirAi.ChatUtils, :request_ai_response, fn _server, _messages, _tools -> :ok end)
stub(ElixirAi.ChatUtils, :request_ai_response, fn _server, _messages, _tools, _provider ->
:ok
end)
ElixirAi.ChatRunner.new_user_message(conv_name, "hello world")
@@ -60,7 +63,7 @@ defmodule ElixirAi.MessageStorageTest do
test "run_sql is called with assistant message params" do
conv_name = setup_conversation()
stub(ElixirAi.ChatUtils, :request_ai_response, fn server, _messages, _tools ->
stub(ElixirAi.ChatUtils, :request_ai_response, fn server, _messages, _tools, _provider ->
id = make_ref()
send(server, {:start_new_ai_response, id})
send(server, {:ai_text_chunk, id, "Hello from AI"})
@@ -80,7 +83,7 @@ defmodule ElixirAi.MessageStorageTest do
conv_name = setup_conversation()
# First AI call triggers the tool; subsequent calls (after tool completes) are no-ops.
expect(ElixirAi.ChatUtils, :request_ai_response, fn server, _messages, _tools ->
expect(ElixirAi.ChatUtils, :request_ai_response, fn server, _messages, _tools, _provider ->
id = make_ref()
send(server, {:start_new_ai_response, id})
@@ -93,7 +96,9 @@ defmodule ElixirAi.MessageStorageTest do
:ok
end)
stub(ElixirAi.ChatUtils, :request_ai_response, fn _server, _messages, _tools -> :ok end)
stub(ElixirAi.ChatUtils, :request_ai_response, fn _server, _messages, _tools, _provider ->
:ok
end)
ElixirAi.ChatRunner.new_user_message(conv_name, "store something")

View File

@@ -39,7 +39,11 @@ defmodule ElixirAiWeb.ConnCase do
setup _tags do
stub(ElixirAi.Data.DbHelpers, :run_sql, fn _sql, _params, _topic -> [] end)
stub(ElixirAi.Data.DbHelpers, :run_sql, fn _sql, _params, _topic, _schema -> [] end)
stub(ElixirAi.ChatUtils, :request_ai_response, fn _server, _messages, _tools -> :ok end)
stub(ElixirAi.ChatUtils, :request_ai_response, fn _server, _messages, _tools, _provider ->
:ok
end)
{:ok, conn: Phoenix.ConnTest.build_conn()}
end
end

View File

@@ -13,7 +13,11 @@ defmodule ElixirAi.TestCase do
setup do
stub(ElixirAi.Data.DbHelpers, :run_sql, fn _sql, _params, _topic -> [] end)
stub(ElixirAi.Data.DbHelpers, :run_sql, fn _sql, _params, _topic, _schema -> [] end)
stub(ElixirAi.ChatUtils, :request_ai_response, fn _server, _messages, _tools -> :ok end)
stub(ElixirAi.ChatUtils, :request_ai_response, fn _server, _messages, _tools, _provider ->
:ok
end)
:ok
end
end