69 lines
2.1 KiB
Elixir
69 lines
2.1 KiB
Elixir
defmodule ElixirAi.AiControllable do
|
|
@moduledoc """
|
|
Behaviour + macro for LiveViews that expose AI-controllable tools.
|
|
|
|
Any LiveView that `use`s this module must implement:
|
|
|
|
- `ai_tools/0` — returns a list of tool spec maps
|
|
- `handle_ai_tool_call(tool_name, args, socket)` — handles a dispatched tool call,
|
|
returns `{result_string, socket}`.
|
|
|
|
The macro injects:
|
|
|
|
- A `handle_info` clause that dispatches `{:page_tool_call, tool_name, args, reply_to}`
|
|
messages to the callback and sends the result back to the caller.
|
|
- An `on_mount` hook registration that joins the `:pg` group keyed by
|
|
`voice_session_id` so VoiceLive can discover sibling page LiveViews.
|
|
|
|
## Usage
|
|
|
|
defmodule MyAppWeb.SomeLive do
|
|
use MyAppWeb, :live_view
|
|
use ElixirAi.AiControllable
|
|
|
|
@impl ElixirAi.AiControllable
|
|
def ai_tools do
|
|
[
|
|
%{
|
|
name: "do_something",
|
|
description: "Does something useful",
|
|
parameters: %{
|
|
"type" => "object",
|
|
"properties" => %{"value" => %{"type" => "string"}},
|
|
"required" => ["value"]
|
|
}
|
|
}
|
|
]
|
|
end
|
|
|
|
@impl ElixirAi.AiControllable
|
|
def handle_ai_tool_call("do_something", %{"value" => val}, socket) do
|
|
{"done: \#{val}", assign(socket, value: val)}
|
|
end
|
|
end
|
|
"""
|
|
|
|
@callback ai_tools() :: [map()]
|
|
@callback handle_ai_tool_call(tool_name :: String.t(), args :: map(), socket :: term()) ::
|
|
{String.t(), term()}
|
|
|
|
defmacro __using__(_opts) do
|
|
quote do
|
|
@behaviour ElixirAi.AiControllable
|
|
|
|
on_mount ElixirAi.AiControllable.Hook
|
|
|
|
def handle_info({:page_tool_call, tool_name, args, reply_to}, socket) do
|
|
{result, socket} = handle_ai_tool_call(tool_name, args, socket)
|
|
send(reply_to, {:page_tool_result, tool_name, result})
|
|
{:noreply, socket}
|
|
end
|
|
|
|
def handle_info({:get_ai_tools, reply_to}, socket) do
|
|
send(reply_to, {:ai_tools_response, self(), ai_tools()})
|
|
{:noreply, socket}
|
|
end
|
|
end
|
|
end
|
|
end
|