7  Agent template

Author

Sam Parmar

Web applications are a great way to implement trusted mini-agents because the developer has complete control of both the frontend and backend. We can optimize the human user experience of reviewing AI-generated tool inputs, control all the tools, and cleanly separate trusted results from untrusted chat output. This chapter proposes a template for a trusted mini-agent as a Shiny for Python app. Users can begin with this template and add their own chatlas tools to create a trusted mini-agent that fits their needs. The next chapter covers tools.

This chapter mirrors the R template, substituting Python equivalents of the same packages.

7.1 Prerequisites

At minimum, we use these Python packages to implement Shiny-based trusted mini-agents.

Package Role
chatlas AI model chat client with tool registration and streaming.
shinychat Drop-in chat UI for Shiny that binds to a chatlas chat client.
shiny Web application framework. Bundles Bootstrap-based UI components (page_sidebar, cards, layouts) by default, so no separate theming package like bslib is required.
python-dotenv Loads credentials such as ANTHROPIC_API_KEY from a local .env file into the environment, so API keys never appear in source code.

7.2 Implementation

We separately consider the chatlas chat client, Shiny UI, and Shiny server function.

7.2.1 Shiny UI

In a trusted mini-agent, the user interface should have clear and separate regions for the untrusted AI model output, human oversight, and trusted results. That way, the users know how to get trustworthy insights from the app: they understand where to go to review tool inputs, and they do not mistake untrusted AI model output for trusted results.

There are multiple ways to establish separate regions of trust and skepticism. The tool calling UI in shinychat, which embeds tool calls as obvious boxes inside the chat window, is the most popular, pragmatic, and versatile approach (c.f. commons and clinical-trials-agent).

However, to underscore the principles of trusted mini-agents, this guide chooses an alternative custom layout. We relegate the chat to a sidebar, and we reserve permanent first-class real estate for human oversight and trusted results. That way, users pay less attention to the untrusted AI model output and more attention to trustworthy output and vital review tasks. Not every UI can implement such diligent guardrails, especially if the harness has multiple remote tools with different output format types, but they are helpful when feasible.

Screenshot of the trusted mini-agent template Shiny app. The left sidebar shows an AI chat interface labeled “do not trust any AI output here!” with a simple ping/pong exchange. The main area has two empty placeholder cards: one labeled “Humans review AI-generated tool inputs here” and another labeled “Trusted results go here,” illustrating the three-region layout of trust zones.
from shiny import ui
from shinychat import chat_ui

app_ui = ui.page_sidebar(
    ui.sidebar(
        chat_ui("chat"),
        title="AI chat (do not trust any AI output here!)",
    ),
    ui.layout_columns(
        ui.card("Humans review AI-generated tool inputs here."),
        ui.card("Trusted results go here."),
    ),
    title="Trusted mini-agent template",
)

7.2.2 Chat client

In chatlas, the chat client brokers communication with the AI model, and it facilitates the registration of tools. Crucially for trusted mini-agents, a chat client supports no tools by default, so each tool must be explicitly registered (see the next chapter).

For convenience, we create a separate constructor function for the chatlas chat client. This compartmentalization will be useful when we add tools and complicated system prompts.

We use ChatAnthropic() in this example, but any chat client will do.

ChatAnthropic() reads the ANTHROPIC_API_KEY environment variable automatically, so the API key never needs to appear in source code. Following chatlas’s recommended pattern, we keep the key in a local .env file (excluded from version control) and load it with python-dotenv:

.env
ANTHROPIC_API_KEY=...
from chatlas import ChatAnthropic
from dotenv import load_dotenv

load_dotenv()


def new_chat():
    return ChatAnthropic(
        system_prompt="You are a friendly, concise assistant."
    )

7.2.3 Shiny server function

In the Shiny server, we register a handler that watches for user prompts from the shinychat interface and streams the AI model’s reply back into the UI token-by-token.

from shinychat import Chat


def server(input, output, session):
    client = new_chat()
    chat = Chat("chat")

    @chat.on_user_submit
    async def handle_user_input(user_input: str):
        response = await client.stream_async(user_input)
        await chat.append_message_stream(response)

7.2.4 Full app code

This app.py script is a blank template to help you begin implementing your own trusted mini-agent.

app.py
from chatlas import ChatAnthropic
from dotenv import load_dotenv
from shiny import App, ui
from shinychat import Chat, chat_ui

load_dotenv()


def new_chat():
    return ChatAnthropic(
        system_prompt="You are a friendly, concise assistant."
    )


app_ui = ui.page_sidebar(
    ui.sidebar(
        chat_ui("chat"),
        title="AI chat (do not trust any AI output here!)",
    ),
    ui.layout_columns(
        ui.card("Humans review AI-generated tool inputs here."),
        ui.card("Trusted results go here."),
    ),
    title="Trusted mini-agent template",
)


def server(input, output, session):
    client = new_chat()
    chat = Chat("chat")

    @chat.on_user_submit
    async def handle_user_input(user_input: str):
        response = await client.stream_async(user_input)
        await chat.append_message_stream(response)


app = App(app_ui, server)