Current section
Files
Jump to
Current section
Files
config/tools/call_subagent.exs
defmodule Eai.Tool.CallSubagent do
@behaviour Eai.Tool
@impl true
def schema do
%{type: "function", function: %{
name: "call_subagent",
description: """
Dispatch a sub-task to an independent AI agent. Returns a subagent_task_id immediately (async).
Use get_subagent_result to poll for the answer. Do not use recursively.
""",
parameters: %{type: "object",
properties: %{
message: %{type: "string", description: "The task or question for the sub-agent."},
pty_session_id: %{type: "string", description: "Optional PTY session ID for the sub-agent. Defaults to a unique ID."}
},
required: ["message"]
}
}}
end
@impl true
def execute(args, _pty_session_id, _chat_session_id) do
message = Map.get(args, "message", "")
pty_session_id = Map.get(args, "pty_session_id", "subagent_#{System.unique_integer([:positive])}")
subagent_task_id = "satask_#{System.unique_integer([:positive, :monotonic])}"
Eai.Naming.cache().put("subagent_result:#{subagent_task_id}", %{
status: "running",
started_at: System.monotonic_time(:millisecond)
})
Task.start(fn ->
result_entry =
try do
case Eai.Naming.chat().send(message, pty_session_id: pty_session_id, chat_session_id: "default") do
{:ok, response} -> %{status: "complete", answer: response, pty_session_id: pty_session_id}
{:error, reason} -> %{status: "error", reason: inspect(reason), pty_session_id: pty_session_id}
end
rescue
e -> %{status: "error", reason: Exception.message(e), pty_session_id: pty_session_id}
end
Eai.Naming.cache().put("subagent_result:#{subagent_task_id}", result_entry)
end)
%{subagent_task_id: subagent_task_id, status: "queued", pty_session_id: pty_session_id}
|> Eai.Utils.sanitize_value()
|> Jason.encode!()
end
end