Skip to content

Build custom agents

Build an agent around your workflow. Combine TabulaFlow's reusable tools with your own queries and actions, without adopting ChatSession.

Example: Build a customer support agent

A customer's USB-C dock won't charge their laptop, and they cannot find the order number. Build an agent that finds the order, consults product guides, and opens a support ticket.

custom_agents.py
import asyncio
from importlib.resources import files
from pathlib import Path
from tempfile import TemporaryDirectory

import pandas as pd

from tabulaflow.agents.llm import make_agent
from tabulaflow.agents.tools import RunQueryTool, ViewTool
from tabulaflow.data import SQLConnector


async def prepare_example(orders: SQLConnector, support_dir: Path) -> None:
    await orders.write_dataframe_async(
        pd.DataFrame(
            [
                (1001, 7, "USB-C dock", "2026-08-18", "delivered"),
                (1002, 8, "Monitor", "2026-08-20", "shipped"),
                (1003, 7, "Laptop stand", "2026-08-22", "shipped"),
                (1004, 7, "USB-C dock", "2025-11-05", "delivered"),
            ],
            columns=["order_id", "customer_id", "product", "purchased_on", "status"],
        ),
        "orders",
    )
    bundled = files("tabulaflow.examples.support")
    for name in ("faq.txt", "dock-guide.pdf"):
        (support_dir / name).write_bytes(bundled.joinpath(name).read_bytes())


async def run_support_agent(orders: SQLConnector, support_dir: Path) -> None:
    query = RunQueryTool(orders)
    tickets: list[dict[str, str | int]] = []

    async def get_orders() -> str:
        """List the signed-in customer's orders, newest first."""
        result = await query.execute(
            "SELECT order_id, product, purchased_on, status FROM orders "
            "WHERE customer_id = 7 ORDER BY purchased_on DESC"
        )
        return result.output

    async def open_support_ticket(order_id: int, issue: str) -> str:
        """Open a support ticket and return its ID."""
        ticket_id = f"SUP-{len(tickets) + 1}"
        tickets.append({"ticket_id": ticket_id, "order_id": order_id, "issue": issue})
        return ticket_id

    agent = make_agent(
        "openai:gpt-5.6-sol",
        instructions=(
            "You are a customer support agent. Follow faq.txt, consult product guides, "
            "look up the customer's order, and cite the files you use."
        ),
        tools=[
            ViewTool(working_dir=str(support_dir)).as_pydantic_ai_tool(),
            get_orders,
            open_support_ticket,
        ],
    )
    result = await agent.run(
        "My newest USB-C dock still won't charge my laptop. I already enabled Laptop charging "
        "and reconnected the USB-C cable. Please open a support ticket."
    )
    print(result.output)
    print("Tickets:", tickets)


async def main() -> None:
    with TemporaryDirectory() as directory:
        orders = await SQLConnector.from_url_async("sqlite+aiosqlite:///:memory:", read_only=False)
        async with orders:
            await prepare_example(orders, Path(directory))
            await run_support_agent(orders, Path(directory))


if __name__ == "__main__":
    asyncio.run(main())
Sample output
Thanks — I opened a technical-support ticket for your newest USB-C dock (order 1001).

Summary (from your report and our checks)
- Product/order: USB-C dock — order 1001 (purchased 2026-08-18). I looked this up in your orders list (orders table).
- Reported issue: Dock will not charge the laptop.
- Troubleshooting already tried (per your message): You enabled Laptop charging in Dock settings and reconnected the host USB-C cable (matches steps 1–2 in the dock guide).
- Guide consulted: dock-guide.pdf (USB-C dock: charging help).
- FAQ consulted: faq.txt (USB-C dock not charging a laptop).

Support ticket
- Ticket ID: SUP-1
- Included in ticket: product, order number, reported issue, and steps already tried.

Next steps
- Our support team will follow up on ticket SUP-1. If you can, please reply with:
  - The laptop make/model and operating system,
  - Whether the dock’s external power adapter is connected and showing any LEDs,
  - Any error messages or indicators on the dock or laptop.
These details speed diagnosis.

Files I used
- faq.txt (customer-support FAQ, troubleshooting instructions)
- dock-guide.pdf (USB-C dock: charging help)

Anything else you’d like me to add to the ticket before I hand it over?
Tickets: [{'ticket_id': 'SUP-1', 'order_id': 1001, 'issue': "USB-C dock not charging laptop. Customer reports they enabled 'Laptop charging' in Dock settings > Power and disconnected/reconnected the host USB-C cable, but laptop still will not charge. Requested a technical-support ticket for order 1001 (USB-C dock)."}]

Set OPENAI_API_KEY, then run the complete example:

tabulaflow examples run custom-agents

The example intentionally keeps application concerns lightweight: the signed-in customer is fixed, and tickets are stored in memory. In a real application, derive customer identity from authentication and persist tickets in your support system. Use a model with PDF input support.