Skip to main content
The MeshAgent ChatBot lets you add a conversational (chat/text based) agent to any MeshAgent Room with just a few lines of code! In this guide, you’ll build a working chat agent in four phases, starting with a minimal system prompt and ending with a custom, tool-powered assistant. Phase Overview
  1. Using the MeshAgent CLI: Bring a ready-made ChatBot into a room using a single CLI command.
  2. Creating a Basic ChatBot: Create a simple agent with a system prompt (rules) and connect it to a MeshAgent room. This allows us to see the code behind the CLI chatbot.
  3. Extending a ChatBot with Built-in MeshAgent Tools: Extend our chat agent by adding MeshAgent’s prebuilt tools to interact with the user and write documents to the room.
  4. Adding Custom Tools to a ChatBot: Add additional custom tools to the agent for use-case specific tasks.
You’ll learn how to:
  • Build a chat based agent with MeshAgent
  • Connect the agent to a MeshAgent Room for live testing
  • Define and add custom tools to an agent
  • Decide how you want to run and deploy your agent

Prerequisites

Before you begin be sure you have:
  • Created your MeshAgent account and project
  • Set up and activated a virtual environment, and installed MeshAgent. See the Getting Started Guide for help getting setup.
  • Authenticated to MeshAgent using the CLI by running meshagent setup

Phase 1: Chat with the built-in ChatBot from the CLI

Start by calling the built-in ChatBot into a room directly from the CLI:
meshagent chatbot join --room gettingstarted --agent-name chatagent
This will:
  1. Start a room called gettingstarted inside your project
  2. Call the chatagent into the gettingstarted room
Next, in a web browser, go to studio.meshagent.com and join the gettingstarted room from the Sessions tab. You will see the chatagent appear in the participants tab. Select it and start chatting!

Phase 2: Building a Simple ChatBot

Now that we’ve seen the default chatbot in action, let’s create one from scratch. Create a main.py file and paste the starter code below for the basic ChatBot. To start, we can give the agent one rule / system instruction. We’ll build up this code over the course of this tutorial.
Note: You can optionally set the port parameter on ServiceHost. If you don’t pass a port, it will default to an available port.
import asyncio
from meshagent.otel import otel_config
from meshagent.api.services import ServiceHost
from meshagent.agents.chat import ChatBot
from meshagent.openai import OpenAIResponsesAdapter

# Enable OpenTelemetry logging and tracing for the agent
otel_config(service_name="chatbot")

# Create a service host
service = ServiceHost()  # optional to pass a port, MeshAgent automatically assigns an available one if none provideds

# Register an agent at a specific path
@service.path(path="/chat", identity="chatbot")
class SimpleChatbot(ChatBot):
    def __init__(self):
        super().__init__(
            name="chatbot",
            title="Simple Chatbot",
            description="A helpful chatbot for room participants",
            rules=[
                "Always respond to the user first then include a fun fact at the end of your response."
            ],
            llm_adapter=OpenAIResponsesAdapter(),
        )

# Start the service
asyncio.run(service.run())

Run the ChatBot locally and connect it to a Room. From your terminal run:
meshagent setup # authenticate to meshagent if not already signed in
meshagent service run "main.py" --room=gettingstarted
MeshAgent will start the ServiceHost, discover your ChatBot endpoint automatically, and call it into the specified room. In MeshAgent Studio, open the gettingstarted room from the Sessions tab and chat with your new agent!
Tip: There are two ways to connect an agent to a room:
  • meshagent service run – Starts the ServiceHost, automatically discovers all agents and tools defined in your service, and calls them into the room for you. This is the easiest way to test multi-agent or multi-tool setups.
  • meshagent call agent – Manually calls a single agent into a room by URL. Use this when you want finer control or to test one agent endpoint at a time, for example: meshagent call agent --url=http://localhost:8081/chat --room=gettingstarted --participant-name=chatbot. You will also need to run your file to start the agent locally e.g. python main.py before running the call command.
To see live logs, traces, and metrics as you interact with the agent check out the Developer Console on the bottom pane of the Studio. You can toggle this console on and off by selecting or deselecting it from the menu in the room.

Phase 3: Adding Built-in MeshAgent Tools to our ChatBot

Next, let’s give our agent the ability to interact with the user through the UI, convert documents to markdown, and write documents to the room. We can do this by adding toolkits to our agent. Toolkits represent a group of tools that are used for a particular purpose. We’ll also add a few imports and update the chat agent’s rules so it knows how to interact with the available tools more efficiently.
import asyncio

from meshagent.api import RequiredToolkit, RequiredSchema
from meshagent.agents.chat import ChatBot
from meshagent.openai import OpenAIResponsesAdapter
from meshagent.api.services import ServiceHost
from meshagent.tools.document_tools import (
    DocumentAuthoringToolkit,
    DocumentTypeAuthoringToolkit,
)
from meshagent.agents.schemas.document import document_schema
from meshagent.markitdown.tools import MarkItDownToolkit
from meshagent.otel import otel_config

service = ServiceHost()  # port defaults to an available port if not assigned

otel_config(
    service_name="my-service"
)  # automatically enables telemetry data collection for your agents and tools


@service.path(path="/chat", identity="chatbot")
class SimpleChatbot(ChatBot):
    def __init__(self):
        super().__init__(
            name="chatbot",
            title="chatbot",
            description="a simple chatbot",
            rules=[
                "Always respond to the user and include a fun fact at the end of your response.",
                "use the ask_user tool to pick the name of a document, pick a document name if the tool is not available.",
                "the document names MUST have the extension .document, automatically add the extension if it is not provided",
                "you MUST always write content to a document",
                "first open a document, then use tools to write the document content before closing the document",
                "before closing the document, ask the user if they would like any additional modifications to be made to the document, and if so, make them. continue to ask the user until they are happy with the contents. you are not finished until the user is happy.",
                "blob URLs MUST not be added to documents, they must be saved as files first",
            ],
            llm_adapter=OpenAIResponsesAdapter(),
            requires=[RequiredToolkit(name="ui"), RequiredSchema(name="document")],
            toolkits=[
                MarkItDownToolkit(),
                DocumentAuthoringToolkit(),
                DocumentTypeAuthoringToolkit(
                    schema=document_schema, document_type="document"
                ),
            ],
        )


asyncio.run(service.run())

We can test the agent using the same command as we did with the simple chat agent! (Be sure to cancel the previous command Ctrl+C before rerunning)
meshagent service run "main.py" --room=gettingstarted
Head back to MeshAgentStudio and try giving the agent a document to chat about.

Phase 4: Adding Custom Tools to our ChatBot

Now let’s add a custom tool to our ChatBot! We’ll create a TaskTracker toolkit that allows the agent to write and read tasks using the Room database. To do this we will update the chat agent initialization to create a table for the tasks when the room starts up. We will create a tasks toolkit with two custom tools to WriteTask and GetTasks from the database. This is a simple example of adding tasks, to create a more useful task writer we’d want to add date information and other metadata to better track and filter tasks. This example is mainly to demonstrate writing to room storage and adding custom tools to our chat agent.
import asyncio
import uuid

from meshagent.api import RequiredToolkit, RequiredSchema
from meshagent.agents.chat import ChatBot
from meshagent.openai import OpenAIResponsesAdapter
from meshagent.api.services import ServiceHost
from meshagent.tools.document_tools import (
    DocumentAuthoringToolkit,
    DocumentTypeAuthoringToolkit,
)
from meshagent.markitdown.tools import MarkItDownToolkit
from meshagent.agents.schemas.document import document_schema
from meshagent.api.room_server_client import TextDataType
from meshagent.api.messaging import TextResponse, JsonResponse
from meshagent.tools import Tool, Toolkit
from meshagent.otel import otel_config

service = ServiceHost()  # port defaults to an available port if not assigned

otel_config(
    service_name="my-service"
)  # automatically enables telemetry data collection for your agents and tools


class WriteTask(Tool):
    def __init__(self):
        super().__init__(
            name="WriteTask",
            title="Add a task",
            description="A tool to add tasks to the database",
            input_schema={
                "type": "object",
                "additionalProperties": False,
                "required": ["taskdescription"],
                "properties": {"taskdescription": {"type": "string"}},
            },
        )

    async def execute(self, context, taskdescription: str):
        await context.room.database.insert(
            table="tasks",
            records=[
                {"task_id": str(uuid.uuid4()), "taskdescription": taskdescription}
            ],
        )
        return TextResponse(text="Task added!")


class GetTasks(Tool):
    def __init__(self):
        super().__init__(
            name="GetTasks",
            title="List tasks",
            description="List tasks recorded today or this week",
            input_schema={
                "type": "object",
                "additionalProperties": False,
                "required": [],
                "properties": {},
            },
        )

    async def execute(self, context):
        return JsonResponse(
            json={"values": await context.room.database.search(table="tasks")}
        )


@service.path("/chat")
class SimpleChatbot(ChatBot):
    def __init__(self):
        super().__init__(
            name="mychatbot",
            title="chatbot",
            description="a simple chatbot",
            rules=[
                "Always respond to the user and include a fun fact at the end of your response.",
                "use the ask_user tool to pick the name of a document, pick a document name if the tool is not available.",
                "the document names MUST have the extension .document, automatically add the extension if it is not provided",
                "you MUST always write content to a document",
                "first open a document, then use tools to write the document content before closing the document",
                "before closing the document, ask the user if they would like any additional modifications to be made to the document, and if so, make them. continue to ask the user until they are happy with the contents. you are not finished until the user is happy.",
                "blob URLs MUST not be added to documents, they must be saved as files first",
            ],
            llm_adapter=OpenAIResponsesAdapter(),
            requires=[RequiredToolkit(name="ui"), RequiredSchema(name="document")],
            toolkits=[
                MarkItDownToolkit(),
                DocumentAuthoringToolkit(),
                DocumentTypeAuthoringToolkit(
                    schema=document_schema, document_type="document"
                ),
                Toolkit(
                    name="tasktracker", tools=[WriteTask(), GetTasks()]
                ),  # Add our Custom Tools Here!
            ],
        )

    async def start(self, *, room):
        await super().start(room=room)
        # One tiny table:
        await room.database.create_table_with_schema(
            name="tasks",
            schema={"task_id": TextDataType(), "taskdescription": TextDataType()},
            mode="overwrite",
            data=None,
        )


asyncio.run(service.run())

We can test the agent using the same commands as we did with the simple chat agent! And now when we go to the room we can ask the agent to add a task to our task database.
meshagent service run "main.py" --room=gettingstarted
Once we’re satisfied with how the agent is performing we can deploy and share it.
Note: Building an agent will likely take multiple rounds of iterating through writing different versions of the system prompt and crafting the best tools for the agent.

Agent Deployment Options

Once your ChatBot is working locally, you can run it in different ways depending on your needs and permissions.
ModeDescriptionBest For
Local (Development)Run directly from your machine using meshagent service run.Testing, debugging, iteration
Project ServiceDeploy once to run automatically in every room of a project (admin only).Always-on shared agents
Room ServiceLaunch dynamically in specific rooms via the Containers API.On-demand or user-triggered agents
Each mode uses the same main.py file with our ServiceHost and agent definition. For both project and room services we’ll need to create a Dockerfile for our agent and a meshagent.yaml file that defines the agent configuration. Project Services will use a meshagent.yaml with type Service and Room Services will use a meshagent.yaml with type ServiceTemplate. To learn more about containerizing and managing your ChatBot at scale see Services & Room Containers

Troubleshooting & Tips

  • Use the Developer Console in Studio to view logs, traces, and LLM calls live.
  • Small tweaks to your rules (system prompt) and toolkits can have big quality impacts.
  • Restart the service whenever you modify code; the room will auto-reconnect.

Next Steps

  • ChatBot Overview — Review the lifecycle, context building, and key methods for MeshAgent ChatBots
  • TaskRunner — Learn how to run agents in the background with TaskRunners
  • Worker — Offload background or long-running jobs
  • Services & Containers - Deploy your ChatBot as a managed or on-demand service
  • Secrets & Registries — Learn how to store credentials securely for deployment