What an agent is doing in a room, seen by the people in it, and their hand on it: a task, its steps and how far it is, and Pause, Resume and Stop.
{:ok, claude} = Issho.Agents.join(MyApp.Issho, agent, "board:42", on_behalf_of: ada)
:ok = Issho.Work.start(claude, "Plan the release", ["Read the board", "Group the cards", "Write the summary"])
:ok = Issho.Work.progress(claude, "Read the board", :done)
:ok = Issho.Work.finish(claude, "Grouped 14 cards in 3 columns.")The task is in the agent's state in the room ("task", see
Issho.Awareness), so each page shows it as it goes
(Issho.Components.agents/1), and each start and finish is an event of
the room ("agent.started", "agent.finished"). Agents that reach your
app over MCP do the same with the start_task, progress and
finish_task tools.
Pause, Resume, Stop
The person an agent acts for may pause, resume or stop it in a room,
and so may anyone your policy allows :interrupt (Issho.Policy). A
paused or stopped agent changes nothing more in the room: its next
transaction is refused ({:error, {:interrupted, ...}}), and its next
tool call, but those that only read, says who paused or stopped it and
what to do. A transaction is whole: what the agent changed before is
there, nothing is half done. A paused agent waits for "agent.resumed";
a stopped one finishes (finish/2 lets it go on in another task).
Each is an event of the room: "agent.interrupted" (data: %{agent: key, action: "pause" | "stop"}) and "agent.resumed", by the person
who did it.
An agent whose work runs under Issho (Issho.Agents.run/5) is stopped
at once: its work ends wherever it is. One that crashes says so
(failed/2).
What is yours
Issho keeps the task, its state and its events; it decides nothing of
what a page shows of them. Issho.Components.agents/1 is a default, to
use or to leave: the task is in each agent's state in the room
(Issho.Awareness), and its events are the room's (Issho.Events), to
draw your own way.
Summary
Functions
Says the agent's work failed: its task, if it has one, is "failed",
and the room hears "agent.failed" (data: %{agent: key, title: title, reason: kind}). The people in the room learn only the kind of
failure ("error", "timeout", "killed" or "exit"), not its
details, which may say more than they should know; your app has them
in the [:issho, :agent, :failed] telemetry event (metadata :room,
:agent, :reason), to log or to tell in its own words.
Finishes the task, with a few words of what was done; a stop is over with it.
Pauses, resumes or stops the agent key in a room, for by (an actor
or an identity), from your server: no policy is asked. From a person's
page, the agents bar does it through their session, under the policy.
Says how far the task is: a step (its label or its index) is :done
(the next one pending becomes active), :active, :skipped or
:pending. Options: :add, more steps at the end; :note, a few words
of where it is.
Starts a task: its title and its steps (labels; the first is active).
A task the agent had is replaced. A paused agent starts none until it
is resumed ({:error, {:interrupted, ...}}); a stopped one may.
Types
Functions
@spec failed(GenServer.server(), term()) :: :ok
Says the agent's work failed: its task, if it has one, is "failed",
and the room hears "agent.failed" (data: %{agent: key, title: title, reason: kind}). The people in the room learn only the kind of
failure ("error", "timeout", "killed" or "exit"), not its
details, which may say more than they should know; your app has them
in the [:issho, :agent, :failed] telemetry event (metadata :room,
:agent, :reason), to log or to tell in its own words.
Issho.Agents.run/5 calls it when the work it runs crashes; call it
yourself for a work that fails another way.
@spec finish(GenServer.server(), String.t() | nil) :: :ok | {:error, term()}
Finishes the task, with a few words of what was done; a stop is over with it.
Pauses, resumes or stops the agent key in a room, for by (an actor
or an identity), from your server: no policy is asked. From a person's
page, the agents bar does it through their session, under the policy.
@spec progress( GenServer.server(), String.t() | non_neg_integer() | nil, step_state(), keyword() ) :: :ok | {:error, term()}
Says how far the task is: a step (its label or its index) is :done
(the next one pending becomes active), :active, :skipped or
:pending. Options: :add, more steps at the end; :note, a few words
of where it is.
@spec start(GenServer.server(), String.t(), [String.t()]) :: :ok | {:error, term()}
Starts a task: its title and its steps (labels; the first is active).
A task the agent had is replaced. A paused agent starts none until it
is resumed ({:error, {:interrupted, ...}}); a stopped one may.