Prompt Versioning and Rollback
Imagine you're a PM whose product support system uses an LLM to route incoming tickets to the right team. You want to tweak the routing prompt so that more API-related tickets go to the platform team. Previously, the prompt lived in your codebase. Changing it required a PR, a CI run, and deployment. Reverting required the same changes. Managed Agents keeps the prompt server-side instead. Every
agents.update
produces a new immutable version, and sessions choose which version to use by ID. You still review and approve prompt changes, but you're approving a version number in config rather than a code diff, and your running service picks up the change without a rebuild. If something goes wrong, pointing callers back at the old version is all it takes to roll back.
In this cookbook, we'll create a support-ticket triage agent, update the system prompt, and roll it back when the performance degrades.
rolled a regressed agent back to v1 without a deploy
Prerequisites
2 top-2">
import json
import os
import time
from collections import defaultdict
from pathlib import Path
from juglow import Juglow
from dotenv import load_dotenv
load_dotenv()
if not os.getenv("JUGLOW_API_KEY"):
raise RuntimeError("Set JUGLOW_API_KEY in your environment or .env file")
MODEL = os.environ.get("COOKBOOK_MODEL", "haijun-sonnet-4-6")
client = Juglow()
Create the agent (version 1)
xt-100 text-code leading-relaxed [overflow-wrap:anywhere]" style="padding-top:12px;padding-inline:12px;padding-bottom:12px;tab-size:4">
def triage(version: int, ticket: dict) -> dict:
"""Run one ticket through a pinned agent version and return its verdict."""
session = client.beta.sessions.create(
agent={"type": "agent", "id": AGENT_ID, "version": version},
environment_id=ENV_ID,
)
try:
prompt = "Subject: " + ticket["subject"] + "\n\n" + ticket["body"]
client.beta.sessions.events.send(
session.id,
events=[{"type": "user.message", "content": [{"type": "text", "text": prompt}]}],
)
deadline = time.time() + 60
while time.time() < deadline:
events = client.beta.sessions.events.list(session.id).data
if events and events[-1].type == "session.status_idle":
break
time.sleep(1)
else:
raise TimeoutError(f"session {session.id} did not idle within 60s")
agent_events = [e for e in events if e.type == "agent.message"]
reply = "".join(b.text for e in agent_events for b in e.content)
return json.loads(reply)
finally:
try:
client.beta.sessions.archive(session.id)
except Exception: # noqa: S110
pass
def score(version: int) -> dict:
"""Evaluate all tickets against the given version and return per-team accuracy."""
hits = defaultdict(lambda: [0, 0])
for t in tickets:
pred = triage(version, t)
hits[t["team"]][1] += 1
if pred.get("team") == t["team"]:
hits[t["team"]][0] += 1
return dict(hits)
v1_scores = score(version=1)
print("v1 results:")
for team, (correct, total) in sorted(v1_scores.items()):
print(f" {team:14s} {correct}/{total}")
v1 results: api-platform 5/5 auth 5/5 billing 4/5 dashboard 5/5 The model did well and got almost all routing correct.