PageSourceSearch

https://innovationlab.fetch.ai/resources/assets/js/d3d10450.db85e9f9.js

js fetch.ai collected 2026-09-24 09:38:22 UTC 29,918 bytes, 1 lines download raw bytes

1"use strict";(self.webpackChunkinnovation_labs=self.webpackChunkinnovation_labs||[]).push([[386],{59356:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>i,default:()=>h,frontMatter:()=>r,metadata:()=>s,toc:()=>l});const s=JSON.parse('{"id":"agent-communication/agent-chat-protocol","title":"Agent Chat Protocol","description":"The Agent Chat Protocol is a standardized communication framework that enables agents to exchange messages in a structured and reliable manner. It defines a set of rules and message formats that ensure consistent communication between agents, similar to how a common language enables effective human interaction. This guide demonstrates how to implement and utilize this protocol in your agents.","source":"@site/versioned_docs/version-1.0.5/agent-communication/agent-chat-protocol.mdx","sourceDirName":"agent-communication","slug":"/agent-communication/agent-chat-protocol","permalink":"/resources/docs/agent-communication/agent-chat-protocol","draft":false,"unlisted":false,"tags":[],"version":"1.0.5","frontMatter":{"id":"agent-chat-protocol","title":"Agent Chat Protocol"},"sidebar":"tutorialSidebar","previous":{"title":"uAgent to uAgent Communication","permalink":"/resources/docs/agent-communication/uagent-uagent-communication"},"next":{"title":"Agent Payment Protocol","permalink":"/resources/docs/agent-transaction/agent-payment-protocol"}}');var o=t(74848),a=t(28453);const r={id:"agent-chat-protocol",title:"Agent Chat Protocol"},i="Agent Chat Protocol",c={},l=[{value:"Understanding the Chat Protocol",id:"understanding-the-chat-protocol",level:2},{value:"1. Core Models",id:"1-core-models",level:3},{value:"TextContent",id:"textcontent",level:4},{value:"Resource and ResourceContent",id:"resource-and-resourcecontent",level:4},{value:"Metadata Types",id:"metadata-types",level:4},{value:"2. Session and Stream Management",id:"2-session-and-stream-management",level:3},{value:"Session Control",id:"session-control",level:4},{value:"Stream Control",id:"stream-control",level:4},{value:"3. Agent Content Type",id:"3-agent-content-type",level:3},{value:"4. Message Types",id:"4-message-types",level:3},{value:"ChatMessage",id:"chatmessage",level:4},{value:"ChatAcknowledgement",id:"chatacknowledgement",level:4},{value:"5. Message Handlers",id:"5-message-handlers",level:3},{value:"Using the Chat Protocol",id:"using-the-chat-protocol",level:2},{value:"Prerequisites",id:"prerequisites",level:3},{value:"Basic Message Flow",id:"basic-message-flow",level:2},{value:"Primary path: Agentverse-hosted agents",id:"primary-path-agentverse-hosted-agents",level:3},{value:"Agent1 Script (hosted)",id:"agent1-script-hosted",level:3},{value:"Agent2 Script (hosted)",id:"agent2-script-hosted",level:3},{value:"Running the Agents on Agentverse",id:"running-the-agents-on-agentverse",level:3},{value:"Expected Output",id:"expected-output",level:3},{value:"Troubleshooting",id:"troubleshooting",level:3},{value:"Alternative: running locally",id:"alternative-running-locally",level:3}];function d(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",header:"header",img:"img",input:"input",li:"li",mdxAdmonitionTitle:"mdxAdmonitionTitle",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,a.R)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.header,{children:(0,o.jsx)(n.h1,{id:"agent-chat-protocol",children:"Agent Chat Protocol"})}),"\n",(0,o.jsx)(n.p,{children:"The Agent Chat Protocol is a standardized communication framework that enables agents to exchange messages in a structured and reliable manner. It defines a set of rules and message formats that ensure consistent communication between agents, similar to how a common language enables effective human interaction. This guide demonstrates how to implement and utilize this protocol in your agents."}),"\n",(0,o.jsx)(n.h2,{id:"understanding-the-chat-protocol",children:"Understanding the Chat Protocol"}),"\n",(0,o.jsx)(n.p,{children:"The chat protocol consists of several key components that work together to enable reliable communication between agents. Let's explore each component:"}),"\n",(0,o.jsx)(n.h3,{id:"1-core-models",children:"1. Core Models"}),"\n",(0,o.jsxs)(n.admonition,{title:"Schema excerpts",type:"note",children:[(0,o.jsxs)(n.p,{children:["The blocks below are ",(0,o.jsx)(n.strong,{children:"schema excerpts"})," from ",(0,o.jsx)(n.code,{children:"uagents_core"})," \u2014 not standalone runnable files. Prefer importing symbols instead of redefining them. Canonical import:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-python",children:"from uagents_core.contrib.protocols.chat import (\n    TextContent,\n    Resource,\n    ResourceContent,\n    MetadataContent,\n    StartSessionContent,\n    EndSessionContent,\n    StartStreamContent,\n    EndStreamContent,\n    ChatMessage,\n    ChatAcknowledgement,\n    chat_protocol_spec,\n)\n"})})]}),"\n",(0,o.jsx)(n.h4,{id:"textcontent",children:"TextContent"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-python",children:"class TextContent(Model):\n    type: Literal['text']\n    text: str\n"})}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"Basic content type for text messages"}),"\n",(0,o.jsxs)(n.li,{children:["Uses ",(0,o.jsx)(n.code,{children:"Literal['text']"})," to ensure type safety"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"text"})," field stores the actual message content"]}),"\n"]}),"\n",(0,o.jsx)(n.h4,{id:"resource-and-resourcecontent",children:"Resource and ResourceContent"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-python",children:"class Resource(Model):\n    uri: str\n    metadata: dict[str, str]\n\nclass ResourceContent(Model):\n    type: Literal['resource']\n    resource_id: UUID4\n    resource: Resource | list[Resource]\n"})}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"Resource"}),": Represents external resources (files, images, etc.)","\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"uri"}),": Location of the resource"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"metadata"}),": Additional resource information"]}),"\n"]}),"\n"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"ResourceContent"}),": Wraps resources in messages","\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"resource_id"}),": Unique identifier for tracking"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"resource"}),": Single or multiple resources"]}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,o.jsx)(n.h4,{id:"metadata-types",children:"Metadata Types"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-python",children:"class Metadata(TypedDict):\n    mime_type: str\n    role: str\n\nclass MetadataContent(Model):\n    type: Literal['metadata']\n    metadata: dict[str, str]\n"})}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"Metadata"}),": Documents conventional keys used in resource-related metadata (for example on ",(0,o.jsx)(n.code,{children:"Resource.metadata"}),")","\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"mime_type"}),": Resource type (e.g., ",(0,o.jsx)(n.code,{children:'"text/plain"'}),")"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"role"}),": Resource's purpose in communication"]}),"\n"]}),"\n"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"MetadataContent"}),": For sending metadata-only messages; ",(0,o.jsx)(n.code,{children:"metadata"})," accepts an arbitrary ",(0,o.jsx)(n.code,{children:"dict[str, str]"})," (including the conventional ",(0,o.jsx)(n.code,{children:"mime_type"})," / ",(0,o.jsx)(n.code,{children:"role"})," keys)"]}),"\n"]}),"\n",(0,o.jsx)(n.p,{children:"Example using the conventional keys:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-python",children:'MetadataContent(\n    type="metadata",\n    metadata={"mime_type": "text/plain", "role": "attachment"},\n)\n'})}),"\n",(0,o.jsx)(n.h3,{id:"2-session-and-stream-management",children:"2. Session and Stream Management"}),"\n",(0,o.jsx)(n.admonition,{title:"Advanced content types",type:"note",children:(0,o.jsxs)(n.p,{children:[(0,o.jsx)(n.code,{children:"StartSessionContent"}),", ",(0,o.jsx)(n.code,{children:"EndSessionContent"}),", stream types, and resources are part of the protocol but are ",(0,o.jsx)(n.strong,{children:"not required for this tutorial"}),". The working Agent1/Agent2 scripts below use ",(0,o.jsx)(n.code,{children:"TextContent"})," + acknowledgements only."]})}),"\n",(0,o.jsx)(n.h4,{id:"session-control",children:"Session Control"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-python",children:"class StartSessionContent(Model):\n    type: Literal['start-session']\n\nclass EndSessionContent(Model):\n    type: Literal['end-session']\n"})}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"Manages chat session lifecycle"}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"StartSessionContent"}),": Initiates new sessions"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"EndSessionContent"}),": Properly terminates sessions"]}),"\n"]}),"\n",(0,o.jsx)(n.h4,{id:"stream-control",children:"Stream Control"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-python",children:"class StartStreamContent(Model):\n    type: Literal['start-stream']\n    stream_id: UUID4\n\nclass EndStreamContent(Model):\n    type: Literal['end-stream']\n    stream_id: UUID4\n"})}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"Handles continuous data streams"}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"stream_id"}),": Unique identifier for stream tracking"]}),"\n"]}),"\n",(0,o.jsx)(n.h3,{id:"3-agent-content-type",children:"3. Agent Content Type"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-python",children:"AgentContent = (\n    TextContent\n    | ResourceContent\n    | MetadataContent\n    | StartSessionContent\n    | EndSessionContent\n    | StartStreamContent\n    | EndStreamContent\n)\n"})}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"Combines all possible content types"}),"\n",(0,o.jsx)(n.li,{children:"Ensures type safety in message content"}),"\n"]}),"\n",(0,o.jsx)(n.h3,{id:"4-message-types",children:"4. Message Types"}),"\n",(0,o.jsx)(n.h4,{id:"chatmessage",children:"ChatMessage"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-python",children:"class ChatMessage(Model):\n    timestamp: datetime\n    msg_id: UUID4\n    content: list[AgentContent]\n"})}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"Primary message type for communication"}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"timestamp"}),": When message was sent (UTC)"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"msg_id"}),": Unique message identifier"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"content"}),": List of content elements discussed above."]}),"\n"]}),"\n",(0,o.jsx)(n.h4,{id:"chatacknowledgement",children:"ChatAcknowledgement"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-python",children:"class ChatAcknowledgement(Model):\n    timestamp: datetime\n    acknowledged_msg_id: UUID4\n    metadata: dict[str, str] | None = None\n"})}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"Confirms message receipt"}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"acknowledged_msg_id"}),": References original message"]}),"\n",(0,o.jsx)(n.li,{children:"Optional metadata for additional information"}),"\n"]}),"\n",(0,o.jsx)(n.h3,{id:"5-message-handlers",children:"5. Message Handlers"}),"\n",(0,o.jsx)(n.admonition,{title:"Signature-only example",type:"note",children:(0,o.jsxs)(n.p,{children:["The snippet below is a ",(0,o.jsx)(n.strong,{children:"signature-only"})," reference. ",(0,o.jsx)(n.code,{children:"protocol"})," is created later as ",(0,o.jsx)(n.code,{children:"Protocol(spec=chat_protocol_spec)"}),". See the full Agent1/Agent2 scripts below for runnable code."]})}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-python",children:'@protocol.on_message(ChatMessage)\nasync def handle_message(ctx: Context, sender: str, msg: ChatMessage):\n    ctx.logger.info(f"I got a chat message {sender} {msg}")\n\[email protected]_message(ChatAcknowledgement)\nasync def handle_ack(ctx: Context, sender: str, msg: ChatAcknowledgement):\n    ctx.logger.info(f"I got a chat acknowledgement {sender} {msg}")\n'})}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"Process incoming messages"}),"\n",(0,o.jsx)(n.li,{children:"Handle acknowledgements"}),"\n"]}),"\n",(0,o.jsx)(n.h2,{id:"using-the-chat-protocol",children:"Using the Chat Protocol"}),"\n",(0,o.jsxs)(n.p,{children:["This guide targets ",(0,o.jsx)(n.strong,{children:"Agent Chat Protocol v0.3.0"})," (",(0,o.jsx)(n.code,{children:"chat_protocol_spec.version"}),")."]}),"\n",(0,o.jsx)(n.h3,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,o.jsx)(n.p,{children:(0,o.jsx)(n.strong,{children:"Agentverse-hosted"})}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"uagents"})," and the chat protocol are provided by the platform \u2014 no local ",(0,o.jsx)(n.code,{children:"pip install"})," required."]}),"\n"]}),"\n",(0,o.jsx)(n.p,{children:(0,o.jsx)(n.strong,{children:"Local"})}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:["Python ",(0,o.jsx)(n.strong,{children:"3.10+"})," recommended"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:'pip install "uagents>=0.25.5"'})," (pulls a compatible ",(0,o.jsx)(n.code,{children:"uagents_core"}),"), or ",(0,o.jsx)(n.code,{children:"pip install uagents uagents-core"})," if needed"]}),"\n",(0,o.jsx)(n.li,{children:"Confirm the protocol version:"}),"\n"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:'python -c "from uagents_core.contrib.protocols.chat import 
1chat_protocol_spec; print(chat_protocol_spec.name, chat_protocol_spec.version)"\n'})}),"\n",(0,o.jsxs)(n.p,{children:["Expected: ",(0,o.jsx)(n.code,{children:"AgentChatProtocol 0.3.0"}),"."]}),"\n",(0,o.jsxs)(n.p,{children:["See also ",(0,o.jsx)(n.a,{href:"/docs/agent-creation/uagent-creation",children:"Local Agents"}),"."]}),"\n",(0,o.jsxs)(n.p,{children:["Import the components you need from ",(0,o.jsx)(n.code,{children:"uagents_core"}),":"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-python",children:"from uagents_core.contrib.protocols.chat import (\n    ChatMessage,\n    ChatAcknowledgement,\n    TextContent,\n    chat_protocol_spec,\n)\n"})}),"\n",(0,o.jsxs)(n.p,{children:["Optional helpers: ",(0,o.jsx)(n.code,{children:"ChatMessage"})," includes helpers such as ",(0,o.jsx)(n.code,{children:".text()"})," to collect text blocks from ",(0,o.jsx)(n.code,{children:"content"}),". Richer metadata/card helpers live under ",(0,o.jsx)(n.code,{children:"uagents_core.contrib.protocols.chat"})," as well."]}),"\n",(0,o.jsx)(n.h2,{id:"basic-message-flow",children:"Basic Message Flow"}),"\n",(0,o.jsx)(n.p,{children:"This tutorial uses a one-reply pattern so agents do not loop forever:"}),"\n",(0,o.jsxs)(n.ol,{children:["\n",(0,o.jsxs)(n.li,{children:["Agent1 sends a ",(0,o.jsx)(n.code,{children:"ChatMessage"}),' ("Hello from Agent1!") to Agent2']}),"\n",(0,o.jsxs)(n.li,{children:["Agent2 sends a ",(0,o.jsx)(n.code,{children:"ChatAcknowledgement"})," back to Agent1"]}),"\n",(0,o.jsxs)(n.li,{children:["Agent2 sends one ",(0,o.jsx)(n.code,{children:"ChatMessage"}),' reply ("Hello from Agent2!") to Agent1']}),"\n",(0,o.jsxs)(n.li,{children:["Agent1 sends a ",(0,o.jsx)(n.code,{children:"ChatAcknowledgement"})," back to Agent2 (Agent1 does ",(0,o.jsx)(n.strong,{children:"not"})," send another ",(0,o.jsx)(n.code,{children:"ChatMessage"}),")"]}),"\n"]}),"\n",(0,o.jsx)("div",{style:{textAlign:"center"},children:(0,o.jsx)("img",{src:"/resources/img/chat-protocol/chat-protocol-flow.png",alt:"comparison",style:{width:"85%",maxWidth:"600px"}})}),"\n",(0,o.jsx)(n.h3,{id:"primary-path-agentverse-hosted-agents",children:"Primary path: Agentverse-hosted agents"}),"\n",(0,o.jsxs)(n.p,{children:["This tutorial uses ",(0,o.jsx)(n.strong,{children:"Agentverse-hosted"})," agents as the primary path. Create two agents on ",(0,o.jsx)(n.a,{href:"https://agentverse.ai/",children:"Agentverse"}),", then paste the ",(0,o.jsx)(n.strong,{children:"hosted"})," scripts below into each agent's editor."]}),"\n",(0,o.jsxs)(n.admonition,{type:"caution",children:[(0,o.jsxs)(n.mdxAdmonitionTitle,{children:["Do not include ",(0,o.jsx)(n.code,{children:"agent.run()"})," on Agentverse"]}),(0,o.jsxs)(n.p,{children:["Agentverse runs the agent for you. Omit the ",(0,o.jsx)(n.code,{children:"if __name__ == '__main__': agent.run()"})," block when pasting into a hosted agent. That block belongs only in the ",(0,o.jsx)(n.a,{href:"#alternative-running-locally",children:"local alternative"}),"."]})]}),"\n",(0,o.jsxs)(n.p,{children:["Refer to the ",(0,o.jsx)(n.a,{href:"/docs/agent-creation/uagent-creation#hosted-agents",children:"Hosted Agents"})," section for detailed Agentverse setup steps."]}),"\n",(0,o.jsx)(n.h3,{id:"agent1-script-hosted",children:"Agent1 Script (hosted)"}),"\n",(0,o.jsxs)(n.p,{children:["Paste this into your Agent1 editor on Agentverse (no ",(0,o.jsx)(n.code,{children:"run()"})," block):"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-python",metastring:"title='agent1.py'",children:'from uagents import Agent, Protocol, Context\n\nfrom uagents_core.contrib.protocols.chat import (\n    ChatAcknowledgement,\n    ChatMessage,\n    TextContent,\n    chat_protocol_spec,\n)\n\nagent1 = Agent()\n\n# REQUIRED: paste Agent2\'s address from its startup logs before starting Agent1\nagent2_address = "PASTE_AGENT2_ADDRESS_HERE"\n\nchat_proto = Protocol(spec=chat_protocol_spec)\n\n\[email protected]_event("startup")\nasync def startup_handler(ctx: Context):\n    ctx.logger.info(f"My name is {ctx.agent.name} and my address is {ctx.agent.address}")\n\n    if agent2_address.startswith("PASTE_") or not agent2_address.startswith("agent"):\n        ctx.logger.error("Set agent2_address to Agent2\'s real address before running Agent1")\n        return\n\n    # timestamp/msg_id are optional \u2014 ChatMessage defaults to timezone-aware UTC and a new msg_id\n    initial_message = ChatMessage(\n        content=[TextContent(type="text", text="Hello from Agent1!")]\n    )\n    await ctx.send(agent2_address, initial_message)\n\n\n@chat_proto.on_message(ChatMessage)\nasync def handle_message(ctx: Context, sender: str, msg: ChatMessage):\n    for item in msg.content:\n        if isinstance(item, TextContent):\n            ctx.logger.info(f"Received message from {sender}: {item.text}")\n            # Ack only \u2014 do not reply with another ChatMessage (avoids an unbounded loop)\n            await ctx.send(\n                sender,\n                ChatAcknowledgement(acknowledged_msg_id=m
1sg.msg_id),\n            )\n\n\n@chat_proto.on_message(ChatAcknowledgement)\nasync def handle_acknowledgement(ctx: Context, sender: str, msg: ChatAcknowledgement):\n    ctx.logger.info(\n        f"Received acknowledgement from {sender} for message: {msg.acknowledged_msg_id}"\n    )\n\n\n# publish_manifest=True publishes the protocol manifest so other agents / Agentverse\n# can discover that this agent supports the chat protocol. Use True for tutorials\n# and discoverable agents; use False only if you intentionally want to hide support.\nagent1.include(chat_proto, publish_manifest=True)\n'})}),"\n",(0,o.jsx)(n.h3,{id:"agent2-script-hosted",children:"Agent2 Script (hosted)"}),"\n",(0,o.jsxs)(n.p,{children:["Paste this into your Agent2 editor on Agentverse (no ",(0,o.jsx)(n.code,{children:"run()"})," block):"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-python",metastring:"title='agent2.py'",children:'from uagents import Agent, Protocol, Context\n\nfrom uagents_core.contrib.protocols.chat import (\n    ChatAcknowledgement,\n    ChatMessage,\n    TextContent,\n    chat_protocol_spec,\n)\n\nagent2 = Agent()\n\nchat_proto = Protocol(spec=chat_protocol_spec)\n\n\[email protected]_event("startup")\nasync def startup_handler(ctx: Context):\n    ctx.logger.info(f"My name is {ctx.agent.name} and my address is {ctx.agent.address}")\n\n\n@chat_proto.on_message(ChatMessage)\nasync def handle_message(ctx: Context, sender: str, msg: ChatMessage):\n    for item in msg.content:\n        if isinstance(item, TextContent):\n            ctx.logger.info(f"Received message from {sender}: {item.text}")\n\n            await ctx.send(\n                sender,\n                ChatAcknowledgement(acknowledged_msg_id=msg.msg_id),\n            )\n\n            # Single reply from Agent2 only (Agent1 acks but does not chat-reply)\n            response = ChatMessage(\n                content=[TextContent(type="text", text="Hello from Agent2!")]\n            )\n            await ctx.send(sender, response)\n\n\n@chat_proto.on_message(ChatAcknowledgement)\nasync def handle_acknowledgement(ctx: Context, sender: str, msg: ChatAcknowledgement):\n    ctx.logger.info(\n        f"Received acknowledgement from {sender} for message: {msg.acknowledged_msg_id}"\n    )\n\n\nagent2.include(chat_proto, publish_manifest=True)\n'})}),"\n",(0,o.jsx)(n.h3,{id:"running-the-agents-on-agentverse",children:"Running the Agents on Agentverse"}),"\n",(0,o.jsxs)(n.p,{children:["Hosted agents are started from the Agentverse UI (not with ",(0,o.jsx)(n.code,{children:"python agent2.py"}),"). ",(0,o.jsxs)(n.strong,{children:["Agent1 will not work until ",(0,o.jsx)(n.code,{children:"agent2_address"})," is replaced"]})," with Agent2's real address."]}),"\n",(0,o.jsxs)(n.ol,{children:["\n",(0,o.jsxs)(n.li,{children:["In Agentverse, create ",(0,o.jsx)(n.strong,{children:"two"})," hosted agents (Agent2 and Agent1). See the ",(0,o.jsx)(n.a,{href:"/docs/agent-creation/uagent-creation#hosted-agents",children:"Hosted Agents"})," guide."]}),"\n",(0,o.jsxs)(n.li,{children:["Paste the Agent2 hosted script into the Agent2 editor (",(0,o.jsx)(n.strong,{children:"do not"})," include ",(0,o.jsx)(n.code,{children:"if __name__ == '__main__': agent2.run()"}),")."]}),"\n",(0,o.jsxs)(n.li,{children:["Click ",(0,o.jsx)(n.strong,{children:"Start"})," on Agent2.\n",(0,o.jsx)(n.img,{alt:"Start-Agent-2",src:t(47572).A+"",width:"2574",height:"527"})]}),"\n",(0,o.jsxs)(n.li,{children:["From Agent2 logs, copy the line with ",(0,o.jsx)(n.code,{children:"my address is agent1q..."}),".\n",(0,o.jsx)(n.img,{alt:"Agent-Address",src:t(23132).A+"",width:"2563",height:"1560"})]}),"\n",(0,o.jsxs)(n.li,{children:["Paste that address into Agent1: ",(0,o.jsx)(n.code,{children:'agent2_address = "agent1q..."'}),"."]}),"\n",(0,o.jsxs)(n.li,{children:["Paste the Agent1 hosted script into the Agent1 editor (again without local ",(0,o.jsx)(n.code,{children:"run()"}),"), then click ",(0,o.jsx)(n.strong,{children:"Start"}),".\n",(0,o.jsx)(n.img,{alt:"Start-Agent-1",src:t(66479).A+"",width:"2654",height:"507"})]}),"\n",(0,o.jsxs)(n.li,{children:["Confirm logs match ",(0,o.jsx)(n.a,{href:"#expected-output",children:"Expected Output"}),"."]}),"\n"]}),"\n",(0,o.jsx)(n.h3,{id:"expected-output",children:"Expected Output"}),"\n",(0,o.jsx)(n.p,{children:"When both agents run successfully, you should see logs similar to:"}),"\n",(0,o.jsx)(n.p,{children:(0,o.jsx)(n.strong,{children:"Agent2"})}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-text",children:"INFO: [agent2]: My name is agent2 and my address is agent1q...\nINFO: [agent2]: Received message from agent1q...: Hello from Agent1!\nINFO: [agent2]: Received acknowledgement from agent1q... for message: <uuid>\n"})}),"\n",(0,o.jsx)(n.p,{children:(0,o.jsx)(n.img,{alt:"Agent2-Logs",src:t(76285).A+"",width:"2358",height:"1686"})}),"\n",(0,o.jsx)(n.p,{children:(0,o.jsx)(n.strong,{children:"Agent1"})}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-text",children:"INFO: [agent1]: My name is agent1 and my address is agent1q...\nINFO: [agent1]: Received acknowledgement from agent1q... for message: <uuid>\nINFO: [agent1]: Received message from agent1q...: Hello from Agent2!\n"})}),"\n",(0,o.jsx)(n.p,{children:(0,o.jsx)(n.img,{alt:"Agent1-Logs",src:t(2080).A+"",width:"2429",height:"1706"})}),"\n",(0,o.jsx)(n.p,{children:(0,o.jsx)(n.strong,{children:"Success checklist"})}),"\n",(0,o.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,o.jsxs)(n.li,{className:"task-list-item",children:[(0,o.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Agent2 received \u201cHello from Agent1!\u201d"]}),"\n",(0,o.jsxs)(n.li,{className:"task-list-item",children:[(0,o.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Both sides show acknowledgements"]}),"\n",(0,o.jsxs)(n.li,{className:"task-list-item",children:[(0,o.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Agent1 received Agent2\u2019s reply (\u201cHello from Agent2!\u201d)"]}),"\n"]}),"\n",(0,o.jsx)(n.h3,{id:"troubleshooting",children:"Troubleshooting"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.strong,{children:"Agent1 shows no reply"})," \u2192 Agent2 is not started, or ",(0,o.jsx)(n.code,{children:"agent2_address"})," was not replaced with Agent2\u2019s real address."]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.strong,{children:(0,o.jsx)(n.code,{children:"ImportError: uagents_core"})})," \u2192 Install prerequisites (see above) or use Agentverse-hosted agents."]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.strong,{children:"Repeated / flooding messages"})," \u2192 Both agents are ack+replying on every ",(0,o.jsx)(n.code,{children:"ChatMessage"}),". Use the tutorial pattern: Agent2 replies once; Agent1 acks only."]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.strong,{children:"Hosted agent won\u2019t start / unexpected local server"})," \u2192 Remove the local ",(0,o.jsx)(n.code,{children:"if __name__ == '__main__': agent.run()"})," block from the hosted editor."]}),"\n"]}),"\n",(0,o.jsx)(n.h3,{id:"alternative-running-locally",children:"Alternative: running locally"}),"\n",(0,o.jsx)(n.p,{children:"To run these agents on your local machine instead of Agentverse:"}),"\n",(0,o.jsxs)(n.ol,{children:["\n",(0,o.jsx)(n.li,{children:"Create and activate a virtual environment, then install dependencies:"}),"\n"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:'python -m venv venv\n# Windows PowerShell: .\\venv\\Scripts\\Activate.ps1\n# macOS/Linux: 
1source venv/bin/activate\npip install "uagents>=0.25.5"\n'})}),"\n",(0,o.jsxs)(n.ol,{start:"2",children:["\n",(0,o.jsxs)(n.li,{children:["Use the hosted script bodies above, but initialise each agent with a port and endpoint, and ",(0,o.jsx)(n.strong,{children:"keep"})," the local ",(0,o.jsx)(n.code,{children:"run()"})," block at the bottom of each file:"]}),"\n"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-python",children:'# For agent1\nagent1 = Agent(\n    name="agent1",\n    port=8000,\n    endpoint=["http://localhost:8000/submit"],\n)\n\n# For agent2\nagent2 = Agent(\n    name="agent2",\n    port=8001,\n    endpoint=["http://localhost:8001/submit"],\n)\n\n# At the bottom of each file (local only):\nif __name__ == "__main__":\n    agent1.run()  # or agent2.run()\n'})}),"\n",(0,o.jsxs)(n.ol,{start:"3",children:["\n",(0,o.jsx)(n.li,{children:"Start Agent2 first and keep it running:"}),"\n"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"python agent2.py\n# Windows if needed: py -3.12 agent2.py\n"})}),"\n",(0,o.jsxs)(n.ol,{start:"4",children:["\n",(0,o.jsxs)(n.li,{children:["Copy Agent2\u2019s address into Agent1\u2019s ",(0,o.jsx)(n.code,{children:"agent2_address"}),", then start Agent1 in a second terminal:"]}),"\n"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"python agent1.py\n"})}),"\n",(0,o.jsxs)(n.p,{children:["Reminders: start ",(0,o.jsx)(n.strong,{children:"Agent2 before Agent1"}),"; both must stay running; Agent1 will not work until ",(0,o.jsx)(n.code,{children:"agent2_address"})," is replaced."]}),"\n",(0,o.jsxs)(n.p,{children:["To learn more about setting up and running agents locally, refer to the ",(0,o.jsx)(n.a,{href:"/docs/agent-creation/uagent-creation",children:"Local Agents"})," section of our documentation."]})]})}function h(e={}){const{wrapper:n}={...(0,a.R)(),...e.components};return n?(0,o.jsx)(n,{...e,children:(0,o.jsx)(d,{...e})}):d(e)}},23132:(e,n,t)=>{t.d(n,{A:()=>s});const s=t.p+"assets/images/agent-address-818a598ab43a3a654f043a25b9c77b4a.png"},2080:(e,n,t)=>{t.d(n,{A:()=>s});
1const s=t.p+"assets/images/agent1-logs-78f4efec0b0fa511b4c1fc1f6a101cb7.png"},76285:(e,n,t)=>{t.d(n,{A:()=>s});const s=t.p+"assets/images/agent2-logs-9868daf1d1181c4306253b2ff6b8d103.png"},66479:(e,n,t)=>{t.d(n,{A:()=>s});const s=t.p+"assets/images/start-agent1-37db25e8ef988ae39683cddd1a313a92.png"},47572:(e,n,t)=>{t.d(n,{A:()=>s});const s=t.p+"assets/images/start-agent2-79f04b3dc61d723107a358f98747d914.png"},28453:(e,n,t)=>{t.d(n,{R:()=>r,x:()=>i});var s=t(96540);const o={},a=s.createContext(o);function r(e){const n=s.useContext(a);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function i(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:r(e.components),s.createElement(a.Provider,{value:n},e.children)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.