Wardrik.Agent (wardrik_protocol v0.1.0-rc.6)

Copy Markdown

An agent, and the operations on one.

Wardrik.Agent.ask(scope, "agt_1", "What's on fire?")
#=> {:ok, %Wardrik.Message{id: "msg_Xq3f...", cursor: "W1siYWd0XzEiLG51bGwsNDFdXQ"}}

Wardrik.Agent.read(scope, "agt_1")
#=> {:ok, %Wardrik.Agent{id: "agt_1", status: :running, node: "wardrik@box1", pending: 0, ...}}

A conversation shares its agent's definition, with its own history:

Wardrik.Agent.ask(scope, "agt_1", "What's on fire?", conversation: "C1")
Wardrik.Agent.approve(scope, agent: "agt_1", interrupt: "call_1", conversation: "C1")

Fields

  • :id - the agent's ID, as your app chose it.
  • :conversation - the conversation's ID, or nil for the main one.
  • :status - :idle, :running, :parked or :asleep.
  • :node - the node it runs on.
  • :pending - how many messages wait behind the current one.
  • :next_run - when it next runs.
  • :spent_today - what it has spent today.
  • :activity - what it's doing now. See Wardrik.Activity.
  • :interrupts - the calls it waits on a person for. See Wardrik.Interrupt.
  • :cursor - where its event log stands.

Wardrik.Agents.list/2 leaves out :activity, :interrupts and :cursor.

Summary

Functions

Approve a pending tool call.

Send a message to an agent.

Read the authorization URL for a pending call.

List an agent's running tool calls.

Cancel an agent's current turn.

Clear an agent's history.

Approve or reject pending tool calls.

Read an agent's definition.

Reject a pending tool call.

Delete an agent.

Builds one from the protocol's JSON.

Builds an agent from one item of agents.list's output.

Stop a tool call.

Move an agent to another node.

Read an agent's current status.

Sends the agent a message and returns its answer once the run ends.

Read what an agent gets.

Read an agent's runs and their cost.

Read an agent's resource use.

Start an agent.

Sends the agent a message and streams the text of its answer.

Read an agent's events, then follow new events as they arrive. Returns {:ok, stream} of {%Wardrik.Event{}, cursor} pairs.

Read an agent's conversation.

Returns it as the protocol's JSON, without fields that are nil.

Remove an agent's trigger.

Create or update an agent's trigger.

Types

t()

@type t() :: %Wardrik.Agent{
  activity: term(),
  conversation: term(),
  cursor: term(),
  id: term(),
  interrupts: term(),
  next_run: term(),
  node: term(),
  pending: term(),
  spent_today: term(),
  status: term()
}

Functions

approve(scope, input)

@spec approve(Wardrik.Scope.t(), keyword()) ::
  term() | :ok | {:error, Wardrik.Error.t()}

Approve a pending tool call.

Wardrik.Agent.approve(scope, agent: "agt_1", interrupt: "call_1")

Same as agent.decide with one approval. Recorded under the caller.

Add conversation: "C1" to act on one of the agent's conversations.

POST /v1/agents/{agent}/interrupts/{interrupt}/approve

ask(scope, agent, input \\ [], opts \\ [])

@spec ask(Wardrik.Scope.t(), String.t() | struct(), term(), keyword()) ::
  term() | :ok | {:error, Wardrik.Error.t()}

Send a message to an agent.

Wardrik.Agent.ask(scope, "agt_1", input)

Add conversation: "C1" to act on one of the agent's conversations.

POST /v1/agents/{agent}/messages

authorization(scope, input)

@spec authorization(Wardrik.Scope.t(), keyword()) ::
  term() | :ok | {:error, Wardrik.Error.t()}

Read the authorization URL for a pending call.

Wardrik.Agent.authorization(scope, agent: "agt_1", interrupt: "call_1")

Add conversation: "C1" to act on one of the agent's conversations.

GET /v1/agents/{agent}/interrupts/{interrupt}/authorization

calls(scope, agent, opts \\ [])

@spec calls(Wardrik.Scope.t(), String.t() | struct(), keyword()) ::
  term() | :ok | {:error, Wardrik.Error.t()}

List an agent's running tool calls.

Wardrik.Agent.calls(scope, "agt_1")

Returns not_found while the agent is asleep.

Add conversation: "C1" to act on one of the agent's conversations.

GET /v1/agents/{agent}/calls

cancel(scope, agent, opts \\ [])

@spec cancel(Wardrik.Scope.t(), String.t() | struct(), keyword()) ::
  term() | :ok | {:error, Wardrik.Error.t()}

Cancel an agent's current turn.

Wardrik.Agent.cancel(scope, "agt_1")

Add conversation: "C1" to act on one of the agent's conversations.

POST /v1/agents/{agent}/cancel

clear(scope, agent, opts \\ [])

@spec clear(Wardrik.Scope.t(), String.t() | struct(), keyword()) ::
  term() | :ok | {:error, Wardrik.Error.t()}

Clear an agent's history.

Wardrik.Agent.clear(scope, "agt_1")

Deletes the agent's history. The agent, its definition and its other conversations are kept. Returns conflict while the agent is running a turn or waiting for an approval.

Add conversation: "C1" to act on one of the agent's conversations.

DELETE /v1/agents/{agent}/conversation

decide(scope, input)

@spec decide(Wardrik.Scope.t(), keyword()) ::
  term() | :ok | {:error, Wardrik.Error.t()}

Approve or reject pending tool calls.

Wardrik.Agent.decide(scope, agent: "agt_1", decisions: decisions)

All decisions are applied together and recorded under the caller. A rejection's reason is sent to the model instead of the tool's result. An approval's note is sent with the result.

Add conversation: "C1" to act on one of the agent's conversations.

POST /v1/agents/{agent}/decisions

define(scope, agent, input \\ [])

@spec define(Wardrik.Scope.t(), String.t() | struct(), term()) ::
  term() | :ok | {:error, Wardrik.Error.t()}

Define an agent.

Wardrik.Agent.define(scope, "agt_1", input)

Creates the agent from this definition, or updates a running agent from its next turn. Each call replaces the whole definition. An unsupported key returns not_supported with the key's name.

PUT /v1/agents/{agent}

definition(scope, agent)

@spec definition(Wardrik.Scope.t(), String.t() | struct()) ::
  term() | :ok | {:error, Wardrik.Error.t()}

Read an agent's definition.

Wardrik.Agent.definition(scope, "agt_1")

GET /v1/agents/{agent}/definition

deny(scope, input)

@spec deny(Wardrik.Scope.t(), keyword()) :: term() | :ok | {:error, Wardrik.Error.t()}

Reject a pending tool call.

Wardrik.Agent.deny(scope, agent: "agt_1", interrupt: "call_1")

Same as agent.decide with one rejection. Recorded under the caller.

Add conversation: "C1" to act on one of the agent's conversations.

POST /v1/agents/{agent}/interrupts/{interrupt}/deny

events(scope, agent, input \\ [], opts \\ [])

@spec events(Wardrik.Scope.t(), String.t() | struct(), term(), keyword()) ::
  term() | :ok | {:error, Wardrik.Error.t()}

Read an agent's events.

Wardrik.Agent.events(scope, "agt_1", input)

Add conversation: "C1" to act on one of the agent's conversations.

GET /v1/agents/{agent}/events

forget(scope, agent)

@spec forget(Wardrik.Scope.t(), String.t() | struct()) ::
  term() | :ok | {:error, Wardrik.Error.t()}

Delete an agent.

Wardrik.Agent.forget(scope, "agt_1")

DELETE /v1/agents/{agent}

from_json(json)

@spec from_json(map()) :: t()

Builds one from the protocol's JSON.

from_summary(summary)

@spec from_summary(map()) :: t()

Builds an agent from one item of agents.list's output.

kill(scope, input)

@spec kill(Wardrik.Scope.t(), keyword()) :: term() | :ok | {:error, Wardrik.Error.t()}

Stop a tool call.

Wardrik.Agent.kill(scope, agent: "agt_1", call: "call_1")

Add conversation: "C1" to act on one of the agent's conversations.

DELETE /v1/agents/{agent}/calls/{call}

move(scope, agent, input \\ [], opts \\ [])

@spec move(Wardrik.Scope.t(), String.t() | struct(), term(), keyword()) ::
  term() | :ok | {:error, Wardrik.Error.t()}

Move an agent to another node.

Wardrik.Agent.move(scope, "agt_1", input)

Restarts the agent on the given node, with its state. A turn in progress is stopped, and pending approvals are dropped. Send the request again after the move.

Add conversation: "C1" to act on one of the agent's conversations.

POST /v1/agents/{agent}/move

read(scope, agent, opts \\ [])

@spec read(Wardrik.Scope.t(), String.t() | struct(), keyword()) ::
  term() | :ok | {:error, Wardrik.Error.t()}

Read an agent's current status.

Wardrik.Agent.read(scope, "agt_1")

Add conversation: "C1" to act on one of the agent's conversations.

GET /v1/agents/{agent}

reply(scope, agent, input, opts \\ [])

@spec reply(Wardrik.Scope.t(), String.t() | t(), term(), keyword()) ::
  {:ok, Wardrik.Reply.t()}
  | {:waiting, [Wardrik.Interrupt.t()]}
  | {:error, Wardrik.Error.t()}

Sends the agent a message and returns its answer once the run ends.

Wardrik.Agent.reply(scope, "agt_1", "What's on fire?")
#=> {:ok, %Wardrik.Reply{message: "msg_Xq3f...", run: "0af76519...", text: "Nothing's on fire."}}

Returns {:waiting, interrupts} if the run waits on a person, or {:error, %Wardrik.Error{}}. Takes stream/4's :conversation and :timeout.

resolved(scope, agent)

@spec resolved(Wardrik.Scope.t(), String.t() | struct()) ::
  term() | :ok | {:error, Wardrik.Error.t()}

Read what an agent gets.

Wardrik.Agent.resolved(scope, "agt_1")

Returns what the app gives the agent: who it works for, its policies, MCP servers and their tools, notify targets, channels and workspaces.

GET /v1/agents/{agent}/resolved

runs(scope, agent, opts \\ [])

@spec runs(Wardrik.Scope.t(), String.t() | struct(), keyword()) ::
  term() | :ok | {:error, Wardrik.Error.t()}

Read an agent's runs and their cost.

Wardrik.Agent.runs(scope, "agt_1")

Add conversation: "C1" to act on one of the agent's conversations.

GET /v1/agents/{agent}/runs

runtime(scope, agent)

@spec runtime(Wardrik.Scope.t(), String.t() | struct()) ::
  term() | :ok | {:error, Wardrik.Error.t()}

Read an agent's resource use.

Wardrik.Agent.runtime(scope, "agt_1")

Returns the memory, mailbox size and work of a running agent's processes. Returns not_found while the agent is asleep.

GET /v1/agents/{agent}/runtime

spawn(scope, agent)

@spec spawn(Wardrik.Scope.t(), String.t() | struct()) ::
  term() | :ok | {:error, Wardrik.Error.t()}

Start an agent.

Wardrik.Agent.spawn(scope, "agt_1")

POST /v1/agents/{agent}/spawn

stop(scope, agent, opts \\ [])

@spec stop(Wardrik.Scope.t(), String.t() | struct(), keyword()) ::
  term() | :ok | {:error, Wardrik.Error.t()}

Stop an agent.

Wardrik.Agent.stop(scope, "agt_1")

Add conversation: "C1" to act on one of the agent's conversations.

POST /v1/agents/{agent}/stop

stream(scope, agent, input, opts \\ [])

@spec stream(Wardrik.Scope.t(), String.t() | t(), term(), keyword()) ::
  Enumerable.t() | {:ok, reference()}

Sends the agent a message and streams the text of its answer.

scope |> Wardrik.Agent.stream("agt_1", "What's on fire?") |> Enum.each(&IO.write/1)
  • The stream ends when the run ends or fails. reply/4 says how it ended.
  • Raises Wardrik.Error if the agent can't be reached.
  • With to: pid, returns {:ok, ref}. pid receives {Wardrik, ref, {:text, chunk}}, then {:done, %Wardrik.Reply{}}, {:waiting, interrupts} or {:failed, why}.

Options

  • :conversation - the conversation to send it to. The main one unless set.
  • :to - a pid to send the answer to, in place of returning a stream.
  • :timeout - milliseconds to wait for each part of the answer. Ten minutes unless set.

stream_events(scope, agent, input \\ [], opts \\ [])

@spec stream_events(Wardrik.Scope.t(), String.t() | struct(), term(), keyword()) ::
  {:ok, Enumerable.t()} | :ok | {:error, Wardrik.Error.t()}

Read an agent's events, then follow new events as they arrive. Returns {:ok, stream} of {%Wardrik.Event{}, cursor} pairs.

Wardrik.Agent.stream_events(scope, "agt_1", input)

Add conversation: "C1" to act on one of the agent's conversations.

GET /v1/agents/{agent}/events

timeline(scope, agent, opts \\ [])

@spec timeline(Wardrik.Scope.t(), String.t() | struct(), keyword()) ::
  term() | :ok | {:error, Wardrik.Error.t()}

Read an agent's conversation.

Wardrik.Agent.timeline(scope, "agt_1")

Add conversation: "C1" to act on one of the agent's conversations.

GET /v1/agents/{agent}/timeline

to_json(value)

@spec to_json(t()) :: map()

Returns it as the protocol's JSON, without fields that are nil.

trigger_remove(scope, input)

@spec trigger_remove(Wardrik.Scope.t(), keyword()) ::
  term() | :ok | {:error, Wardrik.Error.t()}

Remove an agent's trigger.

Wardrik.Agent.trigger_remove(scope, agent: "agt_1", trigger: "daily")

DELETE /v1/agents/{agent}/triggers/{trigger}

trigger_set(scope, input)

@spec trigger_set(Wardrik.Scope.t(), keyword()) ::
  term() | :ok | {:error, Wardrik.Error.t()}

Create or update an agent's trigger.

Wardrik.Agent.trigger_set(scope, agent: "agt_1", trigger: "daily")

Creates or updates one trigger and saves it in the agent's definition. Returns not_found if the agent has no definition. If every and timezone don't change, the next run time is kept.

PUT /v1/agents/{agent}/triggers/{trigger}