Skip to content
AgentEnv Framework

Human agents

A person is an A2A agent too

The framework models a human agent no differently from an LLM agent: both serve an A2A endpoint, take messages and reply. Only run() differs, because a person writes the reply instead of a model. So a task can put a person wherever an agent goes, such as the user in a multi-turn conversation with claudius.

Write a human agent

A human agent is an SDK agent whose run() waits for a person. This one shows each message in a terminal and returns what the person types:

human.py
import asyncio

from agentenv_protocol.a2a_agent import (
    AgentEnvAgent, AgentIdentity, TaskRequest, TaskResult, TextPart, a2a_agent,
)

@a2a_agent(identity=AgentIdentity(
    name="dana", description="Dana, answering from a terminal.", version="1.0.0",
))
class TerminalHuman(AgentEnvAgent):
    async def run(self, request: TaskRequest) -> TaskResult:
        message = "\n".join(part.text for part in request.parts if isinstance(part, TextPart))
        reply = await asyncio.to_thread(input, f"\n{message}\n> ")
        if not reply.strip():
            return TaskResult.failure("ended", "The person ended the conversation.")
        return TaskResult.builder().succeeded().add_text(reply).build()

if __name__ == "__main__":
    TerminalHuman().serve()

serve() gives it the same A2A endpoint and agent card as any agent, and it needs no extensions. Anything a person can answer from works the same way: a web form, a chat app or a review queue.

Talk to it from a task

Run python human.py and point a prompt_agent step at it. max_conversation_turns above 1 makes the step a conversation, and user_a2a_url names who plays the user:

{
  "id": "reply",
  "type": "prompt_agent",
  "agent_name": "claudius",
  "prompt_id": "reply",
  "prompt": "Send the Q3 numbers to Sam Lee.",
  "max_conversation_turns": 3,
  "user_a2a_url": "http://localhost:<port>"
}

Each of claudius's replies goes to the person, and their answer is its next prompt. The conversation ends after max_conversation_turns turns, or earlier when the person's task does not complete, as with the empty line above. A person has user_agent_timeout_seconds, 600 by default, to answer each turn.

Without user_a2a_url, the step uses the endpoint in [conversations] default_human_a2a_url or AGENT_ENV_HUMAN_A2A_URL. The framework ships no human endpoint, so you run one like the agent above.

The conversation record

Every turn, the agent's and the person's, lands in the conversation store. The run records its id under a2a_conversations in the context's metadata, keyed by the step's id, and agent-env up shows it in the run's Conversation tab.

Last updated on

Ask a question · Report an issue

On this page