Migrating to SDK 0.6
SDK 0.6 is a surgical break — no back-compat with 0.5.x callers or pre-0.6.0 servers. Upgrade both.
1. Minimum server version
Section titled “1. Minimum server version”The SDK requires tappass server ≥ 0.6.0. Older servers are refused at client construction.
# 0.5: works against any serverAgent("http://tappass", api_key="tp_x")
# 0.6: probes /health; raises TapPassConfigError if server < 0.6.0Agent("http://tappass", api_key="tp_x")Upgrade the server first.
2. Correlation IDs on responses
Section titled “2. Correlation IDs on responses”ChatResponse now has five required fields populated by the server.
# 0.5: response only has content, pipeline, usager = agent.chat("...")
# 0.6: correlation IDs always presentr = agent.chat("...")r.session_id, r.task_id, r.agent_uuid, r.pipeline_uuid, r.audit_urlIf you were defensively accessing these via .get(), simplify — they’re guaranteed.
3. Framework guards are context managers
Section titled “3. Framework guards are context managers”CrewAI
Section titled “CrewAI”# 0.5: mutated crew in placefrom tappass.integrations.crewai import guard_crewguarded = guard_crew(crew, constraints={...}, tappass_url=..., api_key="tp_x")result = guarded.kickoff() # caller drives the crew
# 0.6: context manager; session open/close is explicitfrom tappass.integrations.crewai import guard_crewwith guard_crew(crew, tappass_url=..., api_key="tp_x", constraints={...}) as session: result = session.kickoff() print(session.id, session.audit_url)Calling guard_crew(crew, ...) without with now raises TypeError. No shim.
LangChain
Section titled “LangChain”# 0.5: guard_tools onlytools = guard_tools(tools, tappass_url=..., api_key="tp_x")
# 0.6: high-level guard_agent for whole executor; guard_tools still# available for the low-level case.with guard_agent(executor, tappass_url=..., api_key="tp_x") as session: result = session.invoke({"input": "..."})OpenAI, Google ADK, MCP, Temporal, A2A, FastAPI
Section titled “OpenAI, Google ADK, MCP, Temporal, A2A, FastAPI”Each follows the same pattern. See the runtime-governance reference for the full matrix.
4. Typed GovernanceDecision exceptions
Section titled “4. Typed GovernanceDecision exceptions”PolicyBlockError stayed, but it’s now part of a richer tree. The server can return six different decisions:
from tappass import ( GovernanceDecision, PolicyBlockError, RedactionApplied, ApprovalRequired, TrustTierDenied, BreakGlassActive, ToolIntegrityViolation,)
try: r = agent.chat(prompt)except PolicyBlockError as e: ... # hard block — treat as failureexcept ApprovalRequired as e: print(e.approval_url) # pause, resume via dashboardexcept TrustTierDenied as e: ... # agent clearance too lowexcept GovernanceDecision as e: ... # any other decisionIf you previously caught Exception or relied on HTTP response codes, rewire to these subclasses.
5. TapPass admin class stripped
Section titled “5. TapPass admin class stripped”The TapPass client no longer has pipelines, create_pipeline, assign, audit, etc. Those moved to the dashboard.
tp.create_pipeline("strict", steps={...})tp.assign("my-agent", "strict")events = tp.audit(agent_id="my-agent")
# 0.6 — removed. Use the web dashboard.tp.health() # still heretp.agent(agent_uuid) # still here (lookup)tp.register_agent("svc", ...) # still here (self-registration on startup)6. Reporter emits structured AuditEvent
Section titled “6. Reporter emits structured AuditEvent”Callers building custom integrations against the reporter need to enqueue AuditEvent instances instead of raw dicts.
get_reporter().enqueue(url, key, {"tool": "search", "duration_ms": 12})
# 0.6from tappass.types import AuditEventfrom datetime import datetime, timezone
get_reporter().enqueue(url, key, AuditEvent( event_type="tool_call", session_id="", task_id=None, agent_uuid="", pipeline_uuid=None, timestamp=datetime.now(tz=timezone.utc), payload={"tool": "search", "duration_ms": 12, "outcome": "ok"},))Empty session_id/agent_uuid are filled from the active session.