Skip to content

Agents and Workflows

Multi-agent orchestration, nested agents, and A2A protocol tools.

← Prebuilt Tools overview

ToolExtraDescription
graphbaseMulti-agent graphs with nodes and handoff edges.
agent_graphbasePersistent agent graphs with shared state.
journalbaseDaily markdown journal files and execution logs on disk.
write_todosbaseSession task list on agent.state["todos"] for multi-step agent work.
swarmbaseCoordinate specialist agents with handoffs.
handoff_to_userbasePause for human input or full handoff.
use_agentbaseSpawn a nested agent event loop.
thinkbaseParallel reasoning branches.
use_llmbaseNested LLM call with custom prompt.
workflowbaseSequenced task pipelines with dependencies.
batchbaseInvoke multiple tools in one model turn.
a2a_discover_agenta2a-clientDiscover remote A2A agents. Register via A2AClientToolProvider.
a2a_list_discovered_agentsa2a-clientList discovered A2A agents.
a2a_send_messagea2a-clientSend a message to a remote A2A agent.

graph

Multi-agent graphs with nodes and handoff edges.

python
from elsai_tools.graph import graph
ParameterTypeRequiredDescription
actionstrYescreate, execute, status, list, or delete
graph_idstrNoGraph identifier
topologyDictNoNodes and edges
taskstrNoTask for execute
model_providerstrNoModel provider
toolsList[str]NoTool names

A2A isolation

On A2A servers, graph declares PER_CONTEXT scope. Each context_id gets its own GraphTool instance. Graph IDs are automatically prefixed with the context_id so in-memory graph definitions cannot collide across concurrent conversations.

Using on an A2A server

python
from elsai import Agent

# Register the tool on the template agent; PER_CONTEXT cloning is automatic.
agent = Agent(tools=[...])  # e.g. tools=[python_repl], tools=[graph], …

Full A2AServer + session-manager wiring lives in Concepts — see Stateful prebuilt tools — examples.

  • Graph IDs from the model are auto-prefixed: graph_id="research" becomes "<context_id>:research".
  • Two A2A clients cannot see each other's in-memory graphs even with the same logical ID.

See Stateful tools on A2A and Stateful prebuilt tools — examples.

agent_graph

Persistent agent graphs with shared state.

python
from elsai_tools.agent_graph import agent_graph
ParameterTypeRequiredDescription
actionstrYesGraph action
graph_idstrNoGraph identifier
topologydictNoGraph topology
taskstrNoExecution task
messagestrNoMessage to send

journal

Daily markdown journal files and execution logs stored on disk under ./journal/.

python
from elsai_tools.journal import journal
ParameterTypeRequiredDescription
actionstrYesJournal action
taskstrNoTask entry
logstrNoLog entry
datestrNoDate filter

write_todos

Session task tracking for complex multi-step agent work. Each call replaces the full todo list stored on agent.state["todos"]. Pass an empty list to clear todos.

python
from elsai_tools.write_todos import write_todos
ParameterTypeRequiredDescription
todosList[Todo]YesFull todo list (replaces the previous list)

Todo item

FieldTypeRequiredDescription
contentstrYesTask description (non-empty; leading and trailing whitespace is stripped)
statusstrYespending, in_progress, or completed

Distinct from journal

journal appends markdown notes and checkbox tasks to daily journal files on disk. write_todos stores structured todos in agent state for the current session.

Usage

Register write_todos on Agent(tools=[...]) and send a multi-step prompt — the model calls the tool during the agent loop. Todos are stored on agent.state["todos"]. For programmatic calls without the LLM, use agent.tool.write_todos(todos=[...]).

See Prebuilt Tools — Task tracking (write_todos) for an example.

When a session manager is configured, agent.state["todos"] is saved and restored across process restarts. See Persisting state across sessions.

swarm

Coordinate specialist agents with handoffs.

python
from elsai_tools.swarm import swarm
ParameterTypeRequiredDescription
taskstrYesTask description
agentsList[Dict[str, Any]]YesList of agent configs
max_handoffsintNoMax handoffs
max_iterationsintNoMax iterations
execution_timeoutfloatNoTotal timeout in seconds

handoff_to_user

Pause for human input or full handoff.

python
from elsai_tools.handoff_to_user import handoff_to_user
ParameterTypeRequiredDescription
messagestrYesMessage to show the user
breakout_of_loopboolNoExit agent loop entirely

use_agent

Spawn a nested agent event loop.

python
from elsai_tools.use_agent import use_agent
ParameterTypeRequiredDescription
promptstrYesUser prompt
system_promptstrYesSystem prompt
toolsList[str]NoTool names
model_providerstrNoModel provider
model_settingsDict[str, Any]NoModel settings dict

think

Parallel reasoning branches.

python
from elsai_tools.think import think
ParameterTypeRequiredDescription
thoughtstrYesReasoning prompt
cycle_countintYesNumber of branches
system_promptstrYesSystem prompt
toolsList[str]NoTool names
model_providerstrNoModel provider

use_llm

Nested LLM call with custom prompt.

python
from elsai_tools.use_llm import use_llm
ParameterTypeRequiredDescription
promptstrYesLLM prompt
system_promptAnyNoSystem prompt
model_providerAnyNoModel provider
model_settingsAnyNoModel settings dict

workflow

Sequenced task pipelines with dependencies.

python
from elsai_tools.workflow import workflow
ParameterTypeRequiredDescription
actionstrYesWorkflow action
workflow_idstrNoWorkflow identifier
tasksList[Dict[str, Any]]NoTask definitions with dependencies

A2A isolation

On A2A servers, workflow declares PER_CONTEXT scope. Each context_id gets its own WorkflowTool instance. Workflow definitions are stored under:

$ELSAI_A2A_SESSION_DIR/<context_id>/workflows/

Workflow IDs are prefixed with the context_id.

Using on an A2A server

python
from elsai import Agent

# Register the tool on the template agent; PER_CONTEXT cloning is automatic.
agent = Agent(tools=[...])  # e.g. tools=[python_repl], tools=[graph], …

Full A2AServer + session-manager wiring lives in Concepts — see Stateful prebuilt tools — examples.

  • Workflow files: $ELSAI_A2A_SESSION_DIR/<context_id>/workflows/
  • Workflow IDs are prefixed with context_id the same way as graph.

See Stateful tools on A2A and Stateful prebuilt tools — examples.

batch

Invoke multiple tools in one model turn.

python
from elsai_tools.batch import batch
ParameterTypeRequiredDescription
tool_callslist[dict]YesList of tool invocations

a2a_discover_agent

Discover remote A2A agents. Register via A2AClientToolProvider. Uses A2A Protocol v1.0 internally (a2a-sdk>=1.0.0).

python
from elsai_tools.a2a_client import A2AClientToolProvider

provider = A2AClientToolProvider(known_agent_urls=["http://agent.example.com"])
agent = Agent(tools=provider.tools)

Extra: a2a-client

ParameterTypeRequiredDescription
urlstrYesA2A agent endpoint URL

a2a_list_discovered_agents

List discovered A2A agents.

Extra: a2a-client

No parameters.

a2a_send_message

Send a message to a remote A2A agent.

Extra: a2a-client

ParameterTypeRequiredDescription
message_textstrYesMessage content
target_agent_urlstrYesAgent endpoint URL
message_idstrNoOptional message ID

Copyright © 2026 elsai foundry.