import claude/agent.{type AgentError, type AgentEvent, type AgentResult, Started} import claude/agent/config.{type AgentConfig} import claude/types/message import gleam/erlang/process.{type Pid, type Subject} import gleam/int import gleam/list /// Returns the current system time in native time units (typically nanoseconds). /// Used to generate unique session IDs for each agent run. @external(erlang, "erlang", "system_time") fn system_time() -> Int /// Run the agent loop, calling the provided callback with events at each step. /// /// This is a synchronous function that blocks until the agent completes. /// The `on_event` callback is invoked at each notable step, giving the caller /// visibility into the agent's progress. /// /// ## Example /// /// ```gleam /// actor.run_with_events(config, "Hello", fn(event) { /// case event { /// agent.Started(id) -> io.println("Started: " <> id) /// agent.Done(result) -> io.println("Done!") /// _ -> Nil /// } /// }) /// ``` pub fn run_with_events( config: AgentConfig, prompt: String, on_event: fn(AgentEvent) -> Nil, ) -> Result(AgentResult, AgentError) { let session_id = "agent-" <> int.to_string(system_time()) on_event(Started(session_id: session_id)) let initial_messages = [message.new_user(prompt)] agent.event_loop( config, list.reverse(initial_messages), 0, 0, 0, on_event, ) } /// Start an agent in a new BEAM process, sending events to the given subject. /// /// The agent runs asynchronously in a spawned process. Events are sent to /// the caller's subject as they occur, so the caller can receive them from /// their mailbox. /// /// Returns the Pid of the spawned agent process. /// /// ## Example /// /// ```gleam /// let events = process.new_subject() /// let pid = actor.start(config, "Hello", events) /// /// // Receive events from the agent /// case process.receive(events, 30_000) { /// Ok(agent.Started(id)) -> io.println("Agent started: " <> id) /// Ok(agent.Done(result)) -> io.println("Agent done!") /// _ -> io.println("Timeout or other event") /// } /// ``` pub fn start( config: AgentConfig, prompt: String, caller: Subject(AgentEvent), ) -> Pid { process.spawn(fn() { let _result = run_with_events(config, prompt, fn(event) { process.send(caller, event) }) Nil }) }