DEV Community

pranav-afk
pranav-afk

Posted on

How to Add Traces, Hard Budgets, and Scoped Memory to AI Agents in Python

If you ship multi-step AI agents with tools and LLMs, you eventually need more than print statements: traces, cost ceilings, tool permissions, and memory that does not leak across users.

This guide shows a practical Python integration pattern for AI agent observability and governance using the open Cartha platform and the cartha-sdk package.

Official product and dashboard: https://cartha.in
Docs: https://cartha.in/documentation
Pricing / trial: https://cartha.in/pricing
Login / API keys: https://cartha.in/login


What is an AI agent control plane?

An AI agent control plane sits beside your agents (CrewAI, LangGraph, OpenAI, custom code). You keep building agents as usual. The control plane:

  • Records execution traces (tools, LLM calls, errors)
  • Enforces hard budget breakers (stop runaway spend)
  • Applies tool allow-lists (block unauthorized tools before they run)
  • Stores scoped memory (user / agent / team / org) with server-side isolation
  • Exposes an ops dashboard for agents, traces, memory, and costs

Cartha is built as that control plane for production agent systems—not a replacement for your agent framework.


Why Python AI agents need observability and budgets

Search traffic and real teams ask the same questions:

Problem What breaks without a control plane
Debugging “Which tool failed?” needs step-level traces
Cost Agent loops can burn API spend overnight
Safety Support bots must not call wire-transfer tools
Multi-tenant apps Customer A memory must never appear for Customer B
Audit Compliance needs “what did the agent know?”

Logging alone is not enough. You want server-enforced budgets, policies, and scopes—visible at cartha.in.


Prerequisites

  1. Python 3.10+
  2. Free workspace + API key from Cartha login
  3. Optional: OpenAI key if you use wrap_openai()

Step 1 — Install Cartha SDK

pip install cartha-sdk
# optional
pip install openai

export CARTHA_API_KEY="cartha_..."           # from https://cartha.in → Settings / Keys
export CARTHA_API_BASE="https://cartha.in"   # same host as the product

Full install notes and examples live in the Cartha documentation (https://cartha.in/documentation).

───
Enter fullscreen mode Exit fullscreen mode

Step 2 — Minimal Python integration (copy-paste)

This is the core AI agent instrumentation pattern: init → tool → trace → optional memory + OpenAI wrap.

```import os
import cartha

Connect to your Cartha workspace (https://cartha.in)

cartha.init(
api_key=os.environ["CARTHA_API_KEY"],
api_base=os.environ.get("CARTHA_API_BASE", "https://cartha.in"),
)

Auto LLM + cost steps for OpenAI chat completions

client = cartha.wrap_openai()

@cartha.tool()
def crm_lookup(user_id: str) -> dict:
"""Recorded as a tool step; blocked if not on allowed_tools."""
return {"user_id": user_id, "plan": "pro"}

@cartha.trace(
id="support_agent",
team="support",
budget_usd=0.50, # hard agent-run budget
allowed_tools=["crm_lookup"], # tool allow-list (authority)
)
async def handle_ticket(user_id: str, ticket: str) -> str:
# Scoped memory — user scope is isolated per customer
await cartha.remember(
user_id=user_id,
content=f"Ticket: {ticket}",
scope="user",
confidence=0.9,
)
hits = await cartha.recall(
user_id=user_id,
context=ticket,
scope=["user", "team"],
top_k=5,
)

data = crm_lookup(user_id)

r = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{
        "role": "user",
        "content": f"{ticket}\nCRM: {data}\nMemory: {hits}",
    }],
)
return r.choices[0].message.content or ""
Enter fullscreen mode Exit fullscreen mode

Run the function once, then open the Cartha dashboard (https://cartha.in):

• Agents — registration / heartbeats
• Traces — step-by-step run replay
• Memory — scoped store/recall
• Costs — spend feeding budget breakers

───



### Step 3 — Hard agent budgets (stop runaway spend)



```from cartha import BudgetExceeded

@cartha.trace(id="support_agent", team="support", budget_usd=0.01)
async def risky_run(user_id: str) -> str:
    # ... LLM / cost events ...
    return "ok"

try:
    await risky_run("user_123")
except BudgetExceeded as e:
    print("Cartha stopped the run:", e)

This is an agent-run budget (per @cartha.trace), not “hope the model stops.” Details: cartha.in/documentation (https://cartha.in/documentation).

───
Enter fullscreen mode Exit fullscreen mode

Step 4 — Tool allow-lists (authority before execution)

@cartha.trace(
    id="support_agent",
    team="support",
    allowed_tools=["crm_lookup"],  # wire tools NOT listed
)
async def support_only(user_id: str):
    return crm_lookup(user_id)
    # calling a non-listed @cartha.tool → ToolNotAuthorized (before body runs)

Support can help customers; it cannot accidentally call privileged tools if those tools are outside the allow-list. Thats AI agent governance, not a prompt suggestion.

───
Enter fullscreen mode Exit fullscreen mode

Step 5 — Scoped memory (multi-tenant isolation)

┌───────┬───────────────────────────────┐
│ Scope │ Who can use it │
├───────┼───────────────────────────────┤
│ user │ Memories for that user_id │
├───────┼───────────────────────────────┤
│ agent │ Bound to agent identity │
├───────┼───────────────────────────────┤
│ team │ Shared within a team │
├───────┼───────────────────────────────┤
│ org │ Org-wide (when policy allows) │
└───────┴───────────────────────────────┘

Isolation is enforced on the Cartha API, not only in client code. Product overview: https://cartha.in (https://cartha.in).

Top comments (0)