1"use strict";(self.webpackChunkinnovation_labs=self.webpackChunkinnovation_labs||[]).push([[2565],{87254:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>o,default:()=>h,frontMatter:()=>a,metadata:()=>s,toc:()=>d});const s=JSON.parse('{"id":"examples/singularityNet/medical-agent-metta","title":"Medical Agent with MeTTa","description":"Learn how to build a toy medical knowledge-lookup agent using MeTTa and SingularityNET","source":"@site/docs/examples/singularityNet/medical-agent-metta.md","sourceDirName":"examples/singularityNet","slug":"/examples/singularityNet/medical-agent-metta","permalink":"/resources/docs/next/examples/singularityNet/medical-agent-metta","draft":false,"unlisted":false,"tags":[],"version":"current","frontMatter":{"id":"medical-agent-metta","title":"Medical Agent with MeTTa","sidebar_label":"Medical Agent with MeTTa","description":"Learn how to build a toy medical knowledge-lookup agent using MeTTa and SingularityNET"},"sidebar":"tutorialSidebar","previous":{"title":"Creating a MCP Server on Agentverse","permalink":"/resources/docs/next/examples/mcp-integration/mcp-adapter-example"},"next":{"title":"Financial Advisor Agent","permalink":"/resources/docs/next/examples/singularityNet/financial-advisor-agent-metta"}}');var r=t(74848),i=t(28453);const a={id:"medical-agent-metta",title:"Medical Agent with MeTTa",sidebar_label:"Medical Agent with MeTTa",description:"Learn how to build a toy medical knowledge-lookup agent using MeTTa and SingularityNET"},o=void 0,l={},d=[{value:"<strong>Overview</strong>",id:"overview",level:2},{value:"<strong>What is MeTTa?</strong>",id:"what-is-metta",level:2},{value:"<strong>Installation & Setup</strong>",id:"installation--setup",level:2},{value:"<strong>Prerequisites</strong>",id:"prerequisites",level:3},{value:"<strong>Installation Options</strong>",id:"installation-options",level:3},{value:"<strong>Option 1: Install All Dependencies at Once (Recommended)</strong>",id:"option-1-install-all-dependencies-at-once-recommended",level:3},{value:"<strong>Option 2: Verify Hyperon First</strong>",id:"option-2-verify-hyperon-first",level:3},{value:"<strong>Windows Installation Guide</strong>",id:"windows-installation-guide",level:3},{value:"<strong>Project layout</strong>",id:"project-layout",level:2},{value:"<strong>Architecture Overview</strong>",id:"architecture-overview",level:2},{value:"<strong>Core Integration Concepts</strong>",id:"core-integration-concepts",level:2},{value:"<strong>1. MeTTa Knowledge Graph Structure</strong>",id:"1-metta-knowledge-graph-structure",level:3},{value:"<strong>2. Pattern Matching and Querying</strong>",id:"2-pattern-matching-and-querying",level:3},{value:"<strong>3. uAgent Chat Protocol Integration</strong>",id:"3-uagent-chat-protocol-integration",level:3},{value:"<strong>4. Knowledge lookup (not vector RAG)</strong>",id:"4-knowledge-lookup-not-vector-rag",level:3},{value:"<strong>Core Components</strong>",id:"core-components",level:2},{value:"<strong>Implementation Guide</strong>",id:"implementation-guide",level:2},{value:"<strong>Step 1: Define Your Knowledge Domain</strong>",id:"step-1-define-your-knowledge-domain",level:3},{value:"<strong>Step 2: Implement MeTTa lookup</strong>",id:"step-2-implement-metta-lookup",level:3},{value:"<strong>Step 3: Query processing</strong>",id:"step-3-query-processing",level:3},{value:"<strong>Step 4: Configure Agent</strong>",id:"step-4-configure-agent",level:3},{value:"<strong>Detailed Working (Step-by-Step)</strong>",id:"detailed-working-step-by-step",level:2},{value:"<strong>Testing and Deployment</strong>",id:"testing-and-deployment",level:2},{value:"<strong>Local Testing (mailbox)</strong>",id:"local-testing-mailbox",level:3},{value:"<strong>Sample queries (aligned with one-keyword lookup)</strong>",id:"sample-queries-aligned-with-one-keyword-lookup",level:3},{value:"<strong>Query your agent from ASI</strong>",id:"query-your-agent-from-asi",level:3},{value:"<strong>Expected output</strong>",id:"expected-output",level:3}];function c(e){const n={a:"a",code:"code",em:"em",h2:"h2",h3:"h3",hr:"hr",img:"img",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,i.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.h2,{id:"overview",children:(0,r.jsx)(n.strong,{children:"Overview"})}),"\n",(0,r.jsxs)(n.p,{children:["This guide shows how to integrate ",(0,r.jsx)(n.strong,{children:"SingularityNET's MeTTa (Meta Type Talk)"})," knowledge graph with ",(0,r.jsx)(n.strong,{children:"Fetch.ai's uAgents"})," framework. The sample is a ",(0,r.jsx)(n.strong,{children:"toy demo"}),": it looks up illustrative symptom \u2192 disease \u2192 treatment \u2192 side-effect facts in MeTTa, then uses ",(0,r.jsxs)(n.strong,{children:["ASI",":One"]})," to classify intent and humanize the reply. It is ",(0,r.jsx)(n.strong,{children:"not medical advice"})," and is ",(0,r.jsx)(n.strong,{children:"not a substitute for professional care"}),"."]}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Tested combo:"})," Python ",(0,r.jsx)(n.strong,{children:"3.10\u20133.12"}),", ",(0,r.jsx)(n.code,{children:"uagents>=0.25.5"})," (needs ",(0,r.jsx)(n.code,{children:"uagents-core"})," 0.4.x), ",(0,r.jsx)(n.code,{children:"hyperon>=0.2.6"}),". Chat Protocol samples need this runtime; Python 3.8 is not supported."]}),"\n",(0,r.jsx)(n.h2,{id:"what-is-metta",children:(0,r.jsx)(n.strong,{children:"What is MeTTa?"})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"MeTTa"})," (Meta Type Talk) is SingularityNET's multi-paradigm language for declarative and functional computations over knowledge (meta)graphs. Official docs: ",(0,r.jsx)(n.a,{href:"https://metta-lang.dev/",children:"MeTTa language"})," and ",(0,r.jsx)(n.a,{href:"https://github.com/trueagi-io/hyperon-experimental",children:"Hyperon"}),". It provides:"]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Structured Knowledge Representation"}),": Organize information in logical, queryable formats"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Symbolic Reasoning"}),": Perform complex logical operations and pattern matching"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Knowledge Graph Operations"}),": Build, query, and manipulate knowledge graphs"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Space-based Architecture"}),": Knowledge stored as atoms in logical spaces"]}
1),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"installation--setup",children:(0,r.jsx)(n.strong,{children:"Installation & Setup"})}),"\n",(0,r.jsx)(n.h3,{id:"prerequisites",children:(0,r.jsx)(n.strong,{children:"Prerequisites"})}),"\n",(0,r.jsx)(n.p,{children:"Before you begin, ensure you have:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Python 3.10+"})," (3.10\u20133.12 recommended for ",(0,r.jsx)(n.code,{children:"uagents"})," 0.25.x). On Windows use ",(0,r.jsx)(n.code,{children:"py -3.10"}),"; on WSL/macOS/Linux use ",(0,r.jsx)(n.code,{children:"python3"}),"."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"pip"})," package manager"]}),"\n",(0,r.jsxs)(n.li,{children:["An ",(0,r.jsxs)(n.strong,{children:["ASI",":One"," API key"]})," from the ",(0,r.jsxs)(n.a,{href:"https://asi1.ai/dashboard/api-keys",children:["ASI",":One"," API keys dashboard"]})," (not only the ",(0,r.jsx)(n.a,{href:"https://asi1.ai/",children:"asi1.ai"})," homepage)"]}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"Create a project folder and a virtual environment (do not install into system Python):"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"# macOS / Linux / WSL\npython3 -m venv .venv\nsource .venv/bin/activate\n\n# Windows PowerShell\npy -3.10 -m venv .venv\n.\\.venv\\Scripts\\Activate.ps1\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Create a ",(0,r.jsx)(n.code,{children:".env"})," file (never commit real secrets):"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-text",children:"ASI_ONE_API_KEY=your_key_here\nAGENT_SEED=change-me-to-a-unique-local-seed\n# Optional: set LEARN=1 only if you want the demo to persist LLM guesses into the graph\n# LEARN=1\n"})}),"\n",(0,r.jsx)(n.hr,{}),"\n",(0,r.jsx)(n.h3,{id:"installation-options",children:(0,r.jsx)(n.strong,{children:"Installation Options"})}),"\n",(0,r.jsx)(n.h3,{id:"option-1-install-all-dependencies-at-once-recommended",children:(0,r.jsx)(n.strong,{children:"Option 1: Install All Dependencies at Once (Recommended)"})}),"\n",(0,r.jsxs)(n.p,{children:["Create a ",(0,r.jsx)(n.code,{children:"requirements.txt"})," file with one package per line:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-text",children:"openai>=1.0.0\nhyperon>=0.2.6\nuagents>=0.25.5\nuagents-core>=0.4.9\npython-dotenv>=1.0.0\n"})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"uagents"}
1)," 0.25.x is tested with ",(0,r.jsx)(n.code,{children:"uagents-core"})," 0.4.x (Chat Protocol). Keep ",(0,r.jsx)(n.code,{children:"uagents>=0.25.5"})," and ",(0,r.jsx)(n.code,{children:"uagents-core>=0.4.9"})," unless you intentionally upgrade the whole stack."]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Install all dependencies with one command:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"python3 -m pip install -r requirements.txt\n"})}),"\n",(0,r.jsxs)(n.p,{children:["On Windows: ",(0,r.jsx)(n.code,{children:"py -3.10 -m pip install -r requirements.txt"}),"."]}),"\n",(0,r.jsx)(n.hr,{}),"\n",(0,r.jsx)(n.h3,{id:"option-2-verify-hyperon-first",children:(0,r.jsx)(n.strong,{children:"Option 2: Verify Hyperon First"})}),"\n",(0,r.jsxs)(n.p,{children:["Use this only to confirm Hyperon/MeTTa installs on your machine. You still need Option 1 (",(0,r.jsx)(n.code,{children:"requirements.txt"}),") for ",(0,r.jsx)(n.code,{children:"uagents"}),", ",(0,r.jsx)(n.code,{children:"openai"}),", and ",(0,r.jsx)(n.code,{children:"python-dotenv"}),"."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"python3 -m pip install hyperon\npython3 -c \"from hyperon import MeTTa; print('Hyperon installed successfully!')\"\n"})}),"\n",(0,r.jsx)(n.hr,{}),"\n",(0,r.jsx)(n.h3,{id:"windows-installation-guide",children:(0,r.jsx)(n.strong,{children:"Windows Installation Guide"})}),"\n",(0,r.jsxs)(n.p,{children:["Hyperon on native Windows is often painful. ",(0,r.jsx)(n.strong,{children:"WSL (Ubuntu) is recommended."})," If you stay on native Windows and hit build errors, see this video: ",(0,r.jsx)(n.a,{href:"https://www.youtube.com/watch?v=Hp28F9gL2Cc",children:"Hyperon Installation on Windows"}),"."]}),"\n",(0,r.jsx)(n.p,{children:"Written WSL path:"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:["Install ",(0,r.jsx)(n.a,{href:"https://learn.microsoft.com/en-us/windows/wsl/install",children:"WSL"})," and Ubuntu."]}),"\n",(0,r.jsxs)(n.li,{children:["Inside WSL: install Python 3.10+, create the venv above, then ",(0,r.jsx)(n.code,{children:"pip install -r requirements.txt"}),"."]}),"\n",(0,r.jsxs)(n.li,{children:["Run ",(0,r.jsx)(n.code,{children:"python3 agent.py"})," from the project folder shown below."]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"project-layout",children:(0,r.jsx)(n.strong,{children:"Project layout"})}),"\n",(0,r.jsxs)(n.p,{children:["Imports in ",(0,r.jsx)(n.code,{children:"agent.py"})," use the ",(0,r.jsx)(n.code,{children:"metta"})," package. Create this tree (a flat folder of four ",(0,r.jsx)(n.code,{children:".py"})," files will raise ",(0,r.jsx)(n.code,{children:"ImportError"}),"):"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-text",children:"project/\n agent.py\n metta/\n __init__.py\n knowledge.py\n medicalrag.py\n utils.py\n .env\n requirements.txt\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Create empty ",(0,r.jsx)(n.code,{children:"metta/__init__.py"}),". Run from ",(0,r.jsx)(n.code,{children:"project/"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"python3 agent.py\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Windows: ",(0,r.jsx)(n.code,{children:"py -3.10 agent.py"}),"."]}),"\n",(0,r.jsx)(n.p,{children:"This page is the canonical sample. Copy the files below into that tree."}),"\n",(0,r.jsx)(n.h2,{id:"architecture-overview",children:(0,r.jsx)(n.strong,{children:"Architecture Overview"})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.img,{alt:"Medical Agent \u2014 sequence-style workflow (yellow / green / white)",src:t(36062).A+"",width:"1376",height:"768"})}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.strong,{children:"code"})," pipeline (ASI",":One"," chat does not classify intent for you):"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-mermaid",children:"flowchart LR\n user[User or ASI:One chat]\n handler[Chat Protocol handler]\n llm[Agent LLM: intent plus keyword]\n lookup[MeTTa knowledge lookup]\n humanize[Humanize plus disclaimer]\n user --\x3e handler --\x3e llm --\x3e lookup --\x3e humanize --\x3e user\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Alt text: User or ASI",":One"," sends chat text to the Chat Protocol handler. The agent LLM classifies intent and a keyword, MeTTa looks up the toy graph, then the agent humanizes the answer and sends a disclaimer-prefixed reply."]}),"\n",(0,r.jsxs)(n.p,{children:["Architecture pipeline: ",(0,r.jsxs)(n.strong,{children:["User / ASI",":One"," Chat \u2192 Chat Protocol handler \u2192 agent LLM classifies intent + keyword \u2192 MeTTa knowledge lookup (not vector RAG) \u2192 humanized reply with disclaimer \u2192 User"]}),"."]}),"\n",(0,r.jsx)(n.h2,{id:"core-integration-concepts",children:(0,r.jsx)(n.strong,{children:"Core Integration Concepts"})}),"\n",(0,r.jsx)(n.h3,{id:"1-metta-knowledge-graph-structure",children:(0,r.jsx)(n.strong,{children:"1. MeTTa Knowledge Graph Structure"})}),"\n",(0,r.jsxs)(n.p,{children:["MeTTa organizes knowledge as ",(0,r.jsx)(n.strong,{children:"atoms"})," in logical ",(0,r.jsx)(n.strong,{children:"spaces"}),". Use ",(0,r.jsx)(n.strong,{children:"one convention"}),": diseases, symptoms, and treatment ",(0,r.jsx)(n.em,{children:"keys"})," as ",(0,r.jsx)(n.code,{children:"S(...)"}),"; free-text FAQ answers as ",(0,r.jsx)(n.code,{children:"ValueAtom"}),". Multi-word names use underscores (",(0,r.jsx)(n.code,{children:"stomach_upset"}),"), never raw spaces or parentheses inside query interpolation."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:'from hyperon import MeTTa, E, S, ValueAtom\n\nmetta
1= MeTTa()\n\nmetta.space().add_atom(E(S("symptom"), S("fever"), S("flu")))\nmetta.space().add_atom(E(S("treatment"), S("flu"), S("antiviral_drugs")))\nmetta.space().add_atom(E(S("side_effect"), S("antiviral_drugs"), ValueAtom("nausea, dizziness")))\nmetta.space().add_atom(E(S("faq"), S("hi"), ValueAtom("Hello! How can I assist you today?")))\n'})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Key MeTTa Elements:"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"E (Expression)"}),": Creates logical expressions"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"S (Symbol)"}),": Represents symbolic atoms"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"ValueAtom"}),": Stores string values (FAQ text, side-effect descriptions)"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Space"}),": Container where atoms are stored and queried"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"2-pattern-matching-and-querying",children:(0,r.jsx)(n.strong,{children:"2. Pattern Matching and Querying"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:"# Query syntax: !(match &self (relation subject $variable) $variable)\nquery_str = '!(match &self (symptom fever $disease) $disease)'\nresults = metta.run(query_str)\n# Results include flu for the toy graph\n"})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Query Components:"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:(0,r.jsx)(n.code,{children:"&self"})}),": References the current space"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:(0,r.jsx)(n.code,{children:"$variable"})}),": Pattern matching variables that capture results"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:(0,r.jsx)(n.code,{children:"!(match ...)"})}),": Query syntax for pattern matching"]}),"\n"]}),"\n",(0,r.jsxs)(n.p,{children:["Never interpolate unsanitized user/LLM text into MeTTa. Only simple ",(0,r.jsx)(n.code,{children:"[a-z0-9_]+"})," symbols are allowed."]}),"\n",(0,r.jsx)(n.h3,{id:"3-uagent-chat-protocol-integration",children:(0,r.jsx)(n.strong,{children:"3. uAgent Chat Protocol Integration"})}),"\n",(0,r.jsxs)(n.p,{children:["The following is an ",(0,r.jsx)(n.strong,{children:"excerpt"}),". Full Protocol construction is in ",(0,r.jsx)(n.code,{children:"agent.py"}),". ",(0,r.jsx)(n.code,{children:"process_query"})," returns a dict; send the ",(0,r.jsx)(n.code,{children:"humanized_answer"})," string (plus disclaimer), not the dict."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.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@chat_proto.on_message(ChatMessage)\nasync def handle_message(ctx: Context, sender: str, msg: ChatMessage):\n response = process_query(user_query, rag, llm)\n answer = response.get("humanized_answer", "I could not process that query.")\n await ctx.send(sender, create_text_chat(answer))\n'})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"mailbox=True"})," on ",(0,r.jsx)(n.code,{children:"Agent(...)"})," is the Agentverse mailbox flag (an inbox so a local agent stays reachable). Do ",(0,r.jsx)(n.strong,{children:"not"})," ",(0,r.jsx)(n.code,{children:"import mailbox"})," \u2014 that is Python's stdlib email-mailbox module and is unused here."]}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"publish_agent_details=True"})," publishes the agent's profile/details to Agentverse when the mailbox connects. Use it for discoverable demos; turn it off if you do not want the profile updated automatically."]}),"\n",(0,r.jsx)(n.h3,{id:"4-knowledge-lookup-not-vector-rag",children:(0,r.jsx)(n.strong,{children:"4. Knowledge lookup (not vector RAG)"})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"MedicalRAG"})," in this sample is a ",(0,r.jsx)(n.strong,{children:"MeTTa retriever"}),": pattern-match on the toy graph, then an LLM humanizes the result. It does ",(0,r.jsx)(n.strong,{children:"not"})," use embeddings or document RAG. Dynamic graph writes from LLM guesses are ",(0,r.jsx)(n.strong,{children:"off"})," unless ",(0,r.jsx)(n.code,{children:"LEARN=1"})," is set (unsafe for anything beyond a local experiment)."]}),"\n",(0,r.jsx)(n.h2,{id:"core-components",children:(0,r.jsx)(n.strong,{children:"Core Components"})}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:(0,r.jsx)(n.code,{children:"agent.py"})}),": Main uAgent with Chat Protocol"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:(0,r.jsx)(n.code,{children:"metta/knowledge.py"})}),": Toy MeTTa graph (illustrative only \u2014 not clinical knowledge)"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:(0,r.jsx)(n.code,{children:"metta/medicalrag.py"})}),": MeTTa lookup helpers"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:(0,r.jsx)(n.code,{children:"metta/utils.py"})}),": Intent classification and query processing"]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"implementation-guide",children:(0,r.jsx)(n.strong,{children:"Implementation Guide"})}),"\n",(0,r.jsx)(n.h3,{id:"step-1-define-your-knowledge-domain",children:(0,r.jsx)(n.strong,{children:"Step 1: Define Your Knowledge Domain"})}),"\n",(0,r.jsxs)(n.p,{children:["Create ",(0,r.jsx)(n.code,{children:"metta/knowledge.py"}),". Edges are only ",(0,r.jsx)(n.strong,{children:"symptom \u2192 disease"}),", ",(0,r.jsx)(n.strong,{children:"disease \u2192 treatment"}),", ",(0,r.jsx)(n.strong,{children:"treatment \u2192 side_effect"}),", plus FAQ keys. Treatments are separate atoms so side-effect lookup works (for example ",(0,r.jsx)(n.code,{children:"antiviral_drugs"}),", not one mashed string)."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:'from hyperon import MeTTa, E, S, ValueAtom\n\n\ndef initialize_knowledge_graph(metta: MeTTa):\n """Toy graph for the tutorial. Not clinical knowledge."""\n # Symptoms \u2192 diseases\n metta.space().add_atom(E(S("symptom"), S("fever"), S("flu")))\n metta.space().add_atom(E(S("symptom"), S("cough"), S("flu")))\n metta.space().add_atom(E(S("symptom"), S("nausea"), S("flu")))\n metta.space().add_atom(E(S("symptom"), S("headache"), S("migraine")))\n metta.space().add_atom(E(S("symptom"), S("dizziness"), S("migraine")))\n metta.space().add_atom(E(S("symptom"), S("anxiety"), S("depression")))\n metta.space().add_atom(E(S("symptom"), S("insomnia"), S("depression")))\n\n # Diseases \u2192 treatments (one atom per treatment key)\n metta.space().add_atom(E(S("treatment"), S("flu"), S("rest")))\n metta.space().add_atom(E(S("treatment"), S("flu"), S("fluids")))\n metta.space().add_atom(E(S("treatment"), S("flu"), S("antiviral_drugs")))\n metta.space().add_atom(E(S("treatment"), S("migraine"), S("pain_relievers")))\n metta.space().add_atom(E(S("treatment"), S("migraine"), S("hydration")))\n metta.space().add_atom(E(S("treatment"), S("migraine"), S("dark_room")))\n metta.space().add_atom(E(S("treatment"), S("depression"), S("therapy")))\n metta.space().add_atom(E(S("treatment"), S("depression"), S("antidepressants")))\n\n # Treatments \u2192 side effects\n metta.space().add_atom(\n E(S("side_effect"), S("antiviral_drugs"), ValueAtom("nausea, dizziness"))\n )\n metta.space().add_atom(\n E(S("side_effect"), S("pain_relievers"), ValueAtom("stomach_upset"))\n )\n metta.space().add_atom(\n E(S("side_effect"), S("antidepressants"), ValueAtom("weight_gain, insomnia"))\n )\n\n # FAQ keys must match query_faq (not the raw user sentence)\n metta.space().add_atom(\n E(S("faq"), S("hi"), ValueAtom("Hello! How can I assist you today?"))\n )\n metta.space().add_atom(\n E(\n S("faq"),\n S("not_a_doctor"),\n ValueAtom(\n "I am not a doctor. This is a toy demo, not medical advice. "\n "See a clinician for diagnosis or treatment."\n ),\n )\n )\n metta.space().add_atom(\n E(\n S("faq"),\n S("migraine_treatment"),\n ValueAtom(\n "In this toy graph, migraine treatments include pain_relievers, "\n "hydration, and dark_room."\n ),\n )\n )\n'})}),"\n",(0,r.jsxs)(n.p,{children:["Worked FAQ example: user says ",(0,r.jsx)(n.code,{children:"Hi"})," \u2192 classifier keyword ",(0,r.jsx)(n.code,{children:"hi"})," \u2192 graph key ",(0,r.jsx)(n.code,{children:"hi"})," \u2192 greeting."]}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Limitation:"})," the classifier extracts ",(0,r.jsx)(n.strong,{children:"one"})," keyword. Sample queries below use a single symptom (for example ",(0,r.jsx)(n.code,{children:"fever"}),"), not \u201cfever and cough\u201d."]}),"\n",(0,r.jsx)(n.h3,{id:"step-2-implement-metta-lookup",children:(0,r.jsx)(n.strong,{children:"Step 2: Implement MeTTa lookup"})}),"\n",(0,r.jsxs)(n.p,{children:["Create ",(0,r.jsx)(n.code,{children:"metta/medicalrag.py"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:'import re\nfrom hyperon import MeTTa, E, S, ValueAtom\n\nSYMBOL_PATTERN = re.compile(r"^[a-z0-9_]+$")\n\n\ndef to_symbol(token: str):\n """Encode multi-word names; reject tokens that would break MeTTa."""\n if token is None:\n return None\n symbol = (\n str(token)\n .strip()\n .strip(\'"\')\n .lower()\n .replace("\'", "")\n .replace("\\u2019", "")\n .replace(" ", "_")\n )\n if not SYMBOL_PATTERN.fullmatch(symbol):\n return None\n return symbol\n\n\ndef atom_to_str(atom) -> str:\n """Parse both Symbol and ValueAtom results."""\n try:\n obj = atom.get_object()\n if obj is not None and hasattr(obj, "value"):\n return str(obj.value)\n except Exception:\n pass\n return str(atom).strip(\'"\')\n\n\nclass MedicalRAG:\n """MeTTa knowledge lookup (not embedding RAG)."""\n\n def __init__(self, metta_instance: MeTTa):\n self.metta = metta_instance\n\n def _run_match(self, relation: str, subject: str):\n symbol = to_symbol(subject)\n if not symbol:\n return []\n query_str = f"!(match &self ({relation} {symbol} $x) $x)"\n results = self.metta.run(query_str)\n if not results:\n return []\n values = []\n for row in results:\n if row and len(row) > 0:\n values.append(atom_to_str(row[0]))\n return list(dict.fromkeys(values))\n\n def query_symptom(self, symptom):\n return self._run_match("symptom", symptom)\n\n def get_treatment(self, disease):\n return self._run_match("treatment", disease)\n\n def get_side_effects(self, treatment):\n return self._run_match("side_effect", treatment)\n\n def query_faq(self, question_or_key):\n key = to_symbol(question_or_key)\n if not key:\n return None\n results = self._run_match("faq", key)\n return results[0] if results else None\n\n def add_knowledge(self, relation_type, subject, object_value):\n rel = to_symbol(relation_type)\n subj = to_symbol(subject)\n if not rel or not subj or object_value is None:\n return "Ski
1pped invalid knowledge"\n\n if rel == "symptom":\n obj = to_symbol(object_value)\n if not obj:\n return "Skipped invalid disease symbol"\n atom_obj = S(obj)\n elif rel in ("treatment",):\n obj = to_symbol(object_value)\n if not obj:\n return "Skipped invalid treatment symbol"\n atom_obj = S(obj)\n else:\n atom_obj = ValueAtom(str(object_value))\n\n self.metta.space().add_atom(E(S(rel), S(subj), atom_obj))\n return f"Added {rel}: {subj} -> {object_value}"\n'})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Key Methods:"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:(0,r.jsx)(n.code,{children:"query_symptom()"})}),": Finds diseases for a symbol-safe symptom"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:(0,r.jsx)(n.code,{children:"get_treatment()"})}),": Treatment keys for a disease (then look up each key\u2019s side effects)"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:(0,r.jsx)(n.code,{children:"get_side_effects()"})}),": Side effects for a treatment key such as ",(0,r.jsx)(n.code,{children:"antiviral_drugs"})]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:(0,r.jsx)(n.code,{children:"query_faq()"})}),": FAQ by stable key (",(0,r.jsx)(n.code,{children:"hi"}),", ",(0,r.jsx)(n.code,{children:"migraine_treatment"}),"), not the raw sentence"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:(0,r.jsx)(n.code,{children:"add_knowledge()"})}),": Same atom types as seed data (used only when ",(0,r.jsx)(n.code,{children:"LEARN=1"}),")"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"step-3-query-processing",children:(0,r.jsx)(n.strong,{children:"Step 3: Query processing"})}),"\n",(0,r.jsxs)(n.p,{children:["Create ",(0,r.jsx)(n.code,{children:"metta/utils.py"}),". Fallback ",(0,r.jsx)(n.code,{children:"if not prompt:"})," sits at ",(0,r.jsx)(n.strong,{children:"function scope"})," after all intent branches. Default path does ",(0,r.jsx)(n.strong,{children:"not"})," write LLM output into the graph."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:'import json\nimport os\n\nfrom openai import OpenAI\n\nfrom .medicalrag import MedicalRAG, to_symbol\n\nDISCLAIMER = (\n "Not medical advice. I am not a doctor. This is a toy MeTTa demo, "\n "not a substitute for professional care."\n)\nLEARN = os.getenv("LEARN") == "1"\n\n\nclass LLM:\n def __init__(self, api_key):\n self.client = OpenAI(\n api_key=api_key,\n base_url="https://api.asi1.ai/v1",\n )\n\n def create_completion(self, prompt, max_tokens=800):\n completion = self.client.chat.completions.create(\n messages=[{"role": "user", "content": prompt}],\n model="asi1",\n max_tokens=max_tokens,\n )\n return completion.choices[0].message.content\n\n\ndef get_intent_and_keyword(query, llm):\n """Agent-side ASI:One call: classify intent and extract one keyword."""\n prompt = (\n f"Given the query: \'{query}\'\\n"\n "Classify the intent as one of: \'symptom\', \'treatment\', \'side effect\', \'faq\', or \'unknown\'.\\n"\n "Extract the most relevant single keyword (one symptom, disease, or treatment). "\n "Use snake_case for multi-word names (e.g. antiviral_drugs).\\n"\n "For greetings like Hi/Hello, intent=faq and keyword=hi.\\n"\n "For \'how do I treat a migraine\', intent=faq and keyword=migraine_treatment.\\n"\n "For \'what\'s wrong with me\', intent=faq and keyword=not_a_doctor.\\n"\n "Return *only* JSON:\\n"\n \'{ "intent": "<classified_intent>", "keyword": "<extracted_keyword>" }\'\n )\n response = llm.create_completion(prompt)\n try:\n cleaned = response.strip()\n if cleaned.startswith("```"):\n cleaned = "\\n".join(cleaned.split("\\n")[1:])\n if cleaned.endswith("```"):\n cleaned = "\\n".join(cleaned.split("\\n")[:-1])\n result = json.loads(cleaned.strip())\n return result["intent"], result.get("keyword")\n except (json.JSONDecodeError, KeyError):\n return "unknown", None\n\n\ndef generate_knowledge_response(query, intent, keyword, llm):\n """Optional LLM guess. Do not persist unless LEARN=1."""\n if intent == "symptom":\n prompt = (\n f"Query: \'{query}\'\\n"\n f"The symptom \'{keyword}\' is not in the toy graph. Suggest one plausible disease name "\n f"as a snake_case token. Return only that token."\n )\n elif intent == "treatment":\n prompt = (\n f"Query: \'{query}\'\\n"\n f"No treatments for \'{keyword}\' in the toy graph. Suggest one snake_case treatment key. "\n f"Return only that token."\n )\n elif intent == "side effect":\n prompt = (\n f"Query: \'{query}\'\\n"\n f"No side effects for \'{keyword}\'. Suggest a short description. Return only that text."\n )\n elif intent == "faq":\n prompt = (\n f"Query: \'{query}\'\\n"\n "Provide a concise answer and remind the user this is not medical advice. "\n "Return only the answer."\n )\n else:\n return None\n return llm.create_completion(prompt)\n\n\ndef _side_effects_for_treatments(rag: MedicalRAG, treatments):\n chunks = []\n for t in treatments:\n effects = rag.get_side_effects(t)\n if effects:\n chunks.append(f"{t}: {\', \'.join(effects)}")\n return "; ".join(chunks) if chunks else "none in toy graph"\n\n\ndef process_query(query, rag: MedicalRAG, llm: LLM):\n intent, keyword = get_intent_and_keyword(query, llm)\n
1keyword = to_symbol(keyword) if keyword else None\n prompt = ""\n\n if intent == "faq":\n faq_key = keyword or to_symbol(query)\n faq_answer = rag.query_faq(faq_key) if faq_key else None\n if faq_answer:\n prompt = (\n f"Query: \'{query}\'\\n"\n f"FAQ Answer: \'{faq_answer}\'\\n"\n "Humanize this with a friendly tone. Keep the not-a-doctor meaning."\n )\n else:\n new_answer = generate_knowledge_response(query, intent, keyword, llm)\n if LEARN and faq_key and new_answer:\n rag.add_knowledge("faq", faq_key, new_answer)\n prompt = (\n f"Query: \'{query}\'\\n"\n f"FAQ Answer: \'{new_answer}\'\\n"\n "Humanize this with a friendly tone. This is not medical advice."\n )\n elif intent == "symptom" and keyword:\n diseases = rag.query_symptom(keyword)\n if not diseases:\n disease = generate_knowledge_response(query, intent, keyword, llm)\n if LEARN and disease:\n rag.add_knowledge("symptom", keyword, disease)\n treatments = rag.get_treatment(disease) if disease else []\n prompt = (\n f"Query: \'{query}\'\\n"\n f"Symptom: {keyword}\\n"\n f"Related Disease (unverified LLM suggestion, not a graph fact): {disease}\\n"\n f"Treatments in graph: {\', \'.join(treatments) if treatments else \'none\'}\\n"\n "Be explicit that this is a toy demo, not a diagnosis."\n )\n else:\n disease = diseases[0]\n treatments = rag.get_treatment(disease)\n side_effects = _side_effects_for_treatments(rag, treatments)\n prompt = (\n f"Query: \'{query}\'\\n"\n f"Symptom: {keyword}\\n"\n f"Related Disease (toy graph): {disease}\\n"\n f"Treatments: {\', \'.join(treatments)}\\n"\n f"Side Effects: {side_effects}\\n"\n "Generate a concise, empathetic response. Do not claim to diagnose."\n )\n elif intent == "treatment" and keyword:\n treatments = rag.get_treatment(keyword)\n if treatments:\n prompt = (\n f"Query: \'{query}\'\\n"\n f"Disease: {keyword}\\n"\n f"Treatments: {\', \'.join(treatments)}\\n"\n "Provide a helpful suggestion from the toy graph only."\n )\n else:\n treatment = generate_knowledge_response(query, intent, keyword, llm)\n if LEARN and treatment:\n rag.add_knowledge("treatment", keyword, treatment)\n prompt = (\n f"Query: \'{query}\'\\n"\n f"Disease: {keyword}\\n"\n f"Treatments (unverified LLM suggestion): {treatment}\\n"\n "Say this is not from the verified toy graph."\n )\n elif intent == "side effect" and keyword:\n side_effects = rag.get_side_effects(keyword)\n if side_effects:\n prompt = (\n f"Query: \'{query}\'\\n"\n f"Treatment: {keyword}\\n"\n f"Side Effects: {\', \'.join(side_effects)}\\n"\n "Explain briefly from the toy graph."\n )\n else:\n side_effect = generate_knowledge_response(query, intent, keyword, llm)\n if LEARN and side_effect:\n rag.add_knowledge("side_effect", keyword, side_effect)\n prompt = (\n f"Query: \'{query}\'\\n"\n f"Treatment: {keyword}\\n"\n f"Side Effects (unverified LLM suggestion): {side_effect}\\n"\n "Do not present this as clinical fact."\n )\n\n if not prompt:\n prompt = (\n f"Query: \'{query}\'\\n"\n "No specific info found in the toy graph. Offer general assistance "\n "and remind the user to see a clinician."\n )\n\n prompt += (\n f"\\nAlways start the answer with: {DISCLAIMER}\\n"\n "Then give the helpful content. Do not invent prescriptions."\n )\n response = llm.create_completion(prompt, max_tokens=800)\n text = (response or "").strip()\n if DISCLAIMER.lower() not in text.lower():\n text = f"{DISCLAIMER}\\n\\n{text}"\n return {"selected_question": query, "humanized_answer": text}\n'})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Intent Classification (runs in the agent, after Chat Protocol receives text):"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"symptom"}),": one keyword \u2192 diseases and treatments in the toy graph"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"treatment"}),": treatments for a disease key"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"side effect"}),": side effects for a treatment key (",(0,r.jsx)(n.code,{children:"antiviral_drugs"}),", ",(0,r.jsx)(n.code,{children:"antidepressants"}),")"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"faq"}),": keyed FAQs (",(0,r.jsx)(n.code,{children:"hi"}),", ",(0,r.jsx)(n.code,{children:"not_a_doctor"}),", ",(0,r.jsx)(n.code,{children:"migraine_treatment"}),")"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"step-4-configure-agent",children:(0,r.jsx)(n.strong,{children:"Step 4: Configure Agent"})}),"\n",(0,r.jsxs)(n.p,{children:["Create ",(0,r.jsx)(n.code,{children:"agent.py"})," at the project root (not inside ",(0,r.jsx)(n.code,{children:"metta/"}),"):"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:'from datetime import datetime, timezone\nfrom uuid import uuid4\nimport os\nimport sys\n\nfrom dotenv import load_dotenv\nfrom uagents import Context, Protocol, Agent\nfrom hyperon import MeTTa\n\nfrom uagents_core.contrib.protocols.chat import (\n ChatAcknowledgement,\n ChatMessage,\n EndSessionContent,\n StartSessionContent,\n TextContent,\n chat_protocol_spec,\n)\n\nfrom metta.medicalrag import MedicalRAG\nfrom metta.knowledge import initialize_knowledge_graph\nfrom metta.utils import LLM, process_query, DISCLAIMER\n\nload_dotenv()\n\napi_key = os.getenv("ASI_ONE_API_KEY")\nagent_seed = os.getenv("AGENT_SEED")\n\nif not api_key:\n print("Missing ASI_ONE_API_KEY. Create a key at https://asi1.ai/dashboard/api-keys and put it in .env")\n sys.exit(1)\n\nif not agent_seed:\n print("Missing AGENT_SEED. Set a unique local seed in .env (do not commit secrets).")\n sys.exit(1)\n\nagent = Agent(\n name="Medical MeTTa Agent",\n seed=agent_seed,\n port=8005,\n mailbox=True,\n publish_agent_details=True,\n)\n\n\ndef create_text_chat(text: str, end_session: bool = False) -> ChatMessage:\n content = [TextContent(type="text", text=text)]\n if end_session:\n content.append(EndSessionContent(type="end-session"))\n return ChatMessage(\n timestamp=datetime.now(timezone.utc),\n msg_id=uuid4(),\n content=content,\n )\n\n\nmetta
1= MeTTa()\ninitialize_knowledge_graph(metta)\nrag = MedicalRAG(metta)\nllm = LLM(api_key=api_key)\n\nchat_proto = Protocol(spec=chat_protocol_spec)\n\n\n@chat_proto.on_message(ChatMessage)\nasync def handle_message(ctx: Context, sender: str, msg: ChatMessage):\n ctx.storage.set(str(ctx.session), sender)\n await ctx.send(\n sender,\n ChatAcknowledgement(\n timestamp=datetime.now(timezone.utc),\n acknowledged_msg_id=msg.msg_id,\n ),\n )\n\n for item in msg.content:\n if isinstance(item, StartSessionContent):\n ctx.logger.info(f"Got a start session message from {sender}")\n continue\n elif isinstance(item, TextContent):\n user_query = item.text.strip()\n ctx.logger.info(f"Got a medical query from {sender}: {user_query}")\n try:\n response = process_query(user_query, rag, llm)\n answer_text = response.get(\n "humanized_answer",\n f"{DISCLAIMER}\\n\\nI could not process your query.",\n )\n await ctx.send(sender, create_text_chat(answer_text))\n except Exception as e:\n ctx.logger.error(f"Error processing medical query: {e}")\n await ctx.send(\n sender,\n create_text_chat(\n f"{DISCLAIMER}\\n\\nI hit an error processing that query. Please try again."\n ),\n )\n else:\n ctx.logger.info(f"Got unexpected content from {sender}")\n\n\n@chat_proto.on_message(ChatAcknowledgement)\nasync def handle_ack(ctx: Context, sender: str, msg: ChatAcknowledgement):\n ctx.logger.info(\n f"Got an acknowledgement from {sender} for {msg.acknowledged_msg_id}"\n )\n\n\nagent.include(chat_proto, publish_manifest=True)\n\nif __name__ == "__main__":\n agent.run()\n'})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Agent Features:"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["Toy MeTTa lookup only \u2014 ",(0,r.jsx)(n.strong,{children:"not"})," a clinical system or a substitute for care"]}),"\n",(0,r.jsxs)(n.li,{children:["Every reply includes a ",(0,r.jsx)(n.strong,{children:"not medical advice / not a doctor"})," disclaimer"]}),"\n",(0,r.jsxs)(n.li,{children:["Does ",(0,r.jsx)(n.strong,{children:"not"})," persist unverified LLM output into the graph unless ",(0,r.jsx)(n.code,{children:"LEARN=1"})]}),"\n",(0,r.jsxs)(n.li,{children:["Agent LLM (ASI",":One",") classifies intent after Chat Protocol receives text"]}),"\n",(0,r.jsxs)(n.li,{children:["Compatible with ASI",":One"," via Chat Protocol and Agentverse mailbox (",(0,r.jsx)(n.code,{children:"mailbox=True"}),")"]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"detailed-working-step-by-step",children:(0,r.jsx)(n.strong,{children:"Detailed Working (Step-by-Step)"})}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:["User sends a query through ASI",":One"," chat (or Inspector chat)."]}),"\n",(0,r.jsxs)(n.li,{children:["Chat Protocol handler receives ",(0,r.jsx)(n.code,{children:"TextContent"}),"."]}),"\n",(0,r.jsxs)(n.li,{children:["The ",(0,r.jsx)(n.strong,{children:"agent"})," calls ASI",":One"," (",(0,r.jsx)(n.code,{children:"get_intent_and_keyword"}),") to classify intent and one keyword."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"MedicalRAG"})," runs MeTTa ",(0,r.jsx)(n.code,{children:"match"})," queries on the toy graph."]}),"\n",(0,r.jsxs)(n.li,{children:["Reply is humanized, disclaimer is prepended, and Chat Protocol sends a ",(0,r.jsx)(n.strong,{children:"string"})," (not a dict)."]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"testing-and-deployment",children:(0,r.jsx)(n.strong,{children:"Testing and Deployment"})}),"\n",(0,r.jsx)(n.h3,{id:"local-testing-mailbox",children:(0,r.jsx)(n.strong,{children:"Local Testing (mailbox)"})}),"\n",(0,r.jsxs)(n.p,{children:["Numbered steps matching current uAgents + Agentverse. See also ",(0,r.jsx)(n.a,{href:"/docs/agent-creation/uagent-creation#mailbox-agents",children:"Mailbox agents"})," and ",(0,r.jsx)(n.a,{href:"/docs/agent-creation/uagent-creation",children:"uAgent creation"}),"."]}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:["Log in to ",(0,r.jsx)(n.a,{href:"https://agentverse.ai",children:"Agentverse"}),"."]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:["From ",(0,r.jsx)(n.code,{children:"project/"}),", with venv active and ",(0,r.jsx)(n.code,{children:".env"})," set:"]}
1),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"python3 agent.py\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Windows: ",(0,r.jsx)(n.code,{children:"py -3.10 agent.py"}),"."]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsx)(n.p,{children:"In the console, copy the inspector URL (it includes your agent address). Expected lines look like:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-text",children:"INFO: [Medical MeTTa Agent]: Starting agent with address: agent1q...\nINFO: [Medical MeTTa Agent]: Agent inspector available at https://agentverse.ai/inspect/?uri=http%3A//127.0.0.1%3A8005&address=agent1q...\nINFO: [Medical MeTTa Agent]: Starting mailbox client for https://agentverse.ai\nINFO: [mailbox]: Successfully registered as mailbox agent in Agentverse\n"})}),"\n",(0,r.jsxs)(n.p,{children:["If you see ",(0,r.jsx)(n.code,{children:"Missing ASI_ONE_API_KEY"}),", stop and fix ",(0,r.jsx)(n.code,{children:".env"})," \u2014 the agent exits before ",(0,r.jsx)(n.code,{children:"agent.run()"}),"."]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:["Open the inspector URL while logged in. Choose ",(0,r.jsx)(n.strong,{children:"Connect"})," \u2192 ",(0,r.jsx)(n.strong,{children:"Mailbox"})," (Agentverse issues the mailbox token; you do not paste Python ",(0,r.jsx)(n.code,{children:"import mailbox"}),")."]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:["Use ",(0,r.jsx)(n.strong,{children:"Chat with Agent"})," on the Inspector/profile, or continue to ASI",":One"," below. Keep ",(0,r.jsx)(n.code,{children:"agent.py"})," running."]}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"sample-queries-aligned-with-one-keyword-lookup",children:(0,r.jsx)(n.strong,{children:"Sample queries (aligned with one-keyword lookup)"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"Hi"})," \u2192 FAQ key ",(0,r.jsx)(n.code,{children:"hi"})," (greeting)"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"I have a fever, what could this indicate?"})," \u2192 symptom ",(0,r.jsx)(n.code,{children:"fever"})," \u2192 toy disease ",(0,r.jsx)(n.code,{children:"flu"})," \u2192 ",(0,r.jsx)(n.code,{children:"rest"}),", ",(0,r.jsx)(n.code,{children:"fluids"}),", ",(0,r.jsx)(n.code,{children:"antiviral_drugs"})," (side effects on ",(0,r.jsx)(n.code,{children:"antiviral_drugs"}),")"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"What treatment is commonly used for migraine?"})," \u2192 treatments for ",(0,r.jsx)(n.code,{children:"migraine"})]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"What side effects can antidepressants have?"})," \u2192 side effects for ",(0,r.jsx)(n.code,{children:"antidepressants"})]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"How do I treat a migraine?"})," \u2192 FAQ key ",(0,r.jsx)(n.code,{children:"migraine_treatment"})]}),"\n"]}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.img,{alt:"metta1",src:t(16006).A+"",width:"1804",height:"1416"}),"\n",(0,r.jsx)(n.img,{alt:"metta1",src:t(57245).A+"",width:"2226",height:"1634"}),"\n",(0,r.jsx)(n.img,{alt:"metta1",src:t(19764).A+"",width:"2212",height:"1642"})]}),"\n",(0,r.jsx)(n.h3,{id:"query-your-agent-from-asi",children:(0,r.jsxs)(n.strong,{children:["Query your agent from ASI",":One"]})}),"\n",(0,r.jsxs)(n.p,{children:["ASI",":One"," discovers mailbox agents that are running, registered, and using Chat Protocol. README/handle tips: ",(0,r.jsx)(n.a,{href:"/docs/agentverse/searching-agents",children:"Searching agents"}),". Chat UI: ",(0,r.jsxs)(n.a,{href:"https://chat.asi1.ai/",children:["ASI",":One"," Chat"]}),"."]}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:["Copy the agent address from the console (",(0,r.jsx)(n.code,{children:"agent1q..."}),"). Optionally set a handle on the Agentverse profile."]}),"\n",(0,r.jsxs)(n.li,{children:["Open ",(0,r.jsxs)(n.a,{href:"https://asi1.ai/",children:["ASI",":One"]}),", sign in with Google or the ASI",":One"," wallet, and start a new chat."]}),"\n",(0,r.jsxs)(n.li,{children:["Toggle ",(0,r.jsx)(n.strong,{children:"Agents"})," so ASI",":One"," can call Agentverse agents."]}),"\n",(0,r.jsxs)(n.li,{children:["Paste the address or ",(0,r.jsx)(n.code,{children:"@handle"})," and send a sample query such as ",(0,r.jsx)(n.code,{children:"I have a fever, what could this indicate?"})]}),"\n",(0,r.jsxs)(n.li,{children:["Expect a reply that starts with the not-a-doctor disclaimer and mentions the toy ",(0,r.jsx)(n.strong,{children:"flu"})," graph (not a real diagnosis). The local console should log the incoming chat message."]}),"\n"]}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.img,{alt:"metta1",src:t(82027).A+"",width:"1184",height:"988"}),"\n",(0,r.jsx)(n.img,{alt:"metta1",src:t(44546).A+"",width:"2306",height:"1634"}),"\n",(0,r.jsx)(n.img,{alt:"metta1",src:t(9081).A+"",width:"2296",height:"1668"})]}),"\n",(0,r.jsx)(n.h3,{id:"expected-output",children:(0,r.jsx)(n.strong,{children:"Expected output"})}),"\n",(0,r.jsxs)(n.p,{children:["Startup (shape of logs; address is unique to your ",(0,r.jsx)(n.code,{children:"AGENT_SEED"}),"):"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-text",children:"INFO: [Medical MeTTa Agent]: Starting agent with address: agent1q...\nINFO: [Medical MeTTa Agent]: Agent inspector available at https://agentverse.ai/inspect/?uri=...\nINFO: [mailbox]: Successfully registered as mailbox agent in Agentverse\n"})}),"\n",(0,r.jsx)(n.p,{children:"Example chat:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"You:"})," ",(0,r.jsx)(n.code,{children:"I have a fever, what could this indicate?"})]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Agent:"})," Starts with ",(0,r.jsx)(n.em,{children:"Not medical advice. I am not a doctor..."})," then, from the toy graph, links ",(0,r.jsx)(n.code,{children:"fever"})," \u2192 ",(0,r.jsx)(n.code,{children:"flu"})," and lists ",(0,r.jsx)(n.code,{children:"rest"}),", ",(0,r.jsx)(n.code,{children:"fluids"}),", ",(0,r.jsx)(n.code,{children:"antiviral_drugs"})," (with nausea/dizziness on ",(0,r.jsx)(n.code,{children:"antiviral_drugs"})," if asked)."]}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,i.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(c,{...e})}):c(e)}},16006:(e,n,t)=>{t.d(n,{A:()=>s});const s=t.p+"assets/images/metta1-f9351c12f649d37b548a0085650310f3.png"},57245:(e,n,t)=>{t.d(n,{A:()=>s});const s=t.p+"assets/images/metta2-d248108aa2163053999c5e89d74651f5.png"},19764:(e,n,t)=>{t.d(n,{A:()=>s});const s=t.p+"assets/images/metta3-eb20994e4da916326d2515d6356a18f7.png"},82027:(e,n,t)=>{t.d(n,{A:()=>s});const s=t.p+"assets/images/metta4-c862662013a41a465a113a6c83e41d1d.png"},44546:(e,n,t)=>{t.d(n,{A:()=>s});const s=t.p+"assets/images/metta5-d2ad19624cacff36c4151951132b8b9b.png"},9081:(e,n,t)=>{t.d(n,{A:()=>s});const s=t.p+"assets/images/metta6-f53529c617aa0e0644800fe69f8b1ac4.png"},36062:(e,n,t)=>{t.d(n,{A:()=>s});const s=t.p+"assets/images/medical-agent-workflow-2006faf77231456d5612fb93f5856822.png"},28453:(e,n,t)=>{t.d(n,{R:()=>a,x:()=>o});var s=t(96540);const r={},i=s.createContext(r);function a(e){const n=s.useContext(i);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:a(e.components),s.createElement(i.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.