SuperBryn SDK — sync your voice-agent configuration to SuperBryn for review, versioning, and monitoring
Project description
SuperBryn Agent Sync
Sync your voice-agent configuration to SuperBryn for review, versioning, and monitoring — from any framework (Pipecat, LiveKit) or provider (Vapi, Retell, ElevenLabs, Bland, Bolna, …), or straight from your source code.
A pushed manifest never changes your live agent directly. It lands as a pending draft that you review, diff, and approve in the SuperBryn dashboard. On approval (once verification passes), SuperBryn promotes the draft to a new agent version.
Features
- Zero runtime dependencies — the blocking client uses stdlib
urllib; addaiohttponly if you want the async client. - Draft-first sync — every push lands as a pending draft for human review; nothing goes live without approval.
- Client-side content hashing — same RFC 8785 (JCS) + SHA-256 hashing as the server, so you can pre-check and skip no-op pushes.
- Manifest builder — fluent, typed builder for identity, behavior, LLM / STT / TTS / voice, tools, language, telephony, guardrails, and concurrency.
- Framework adapters — build a manifest directly from a Pipecat pipeline or a LiveKit agent; public attributes only, never API keys.
- Provider translators — turn Vapi / Retell / ElevenLabs / Bland / Bolna agent JSON into a manifest, best-effort and never erroring on unknown fields.
- Source-code extraction —
codescanstatically scans your agent's code (Pythonast, conservative JS/TS regexes) to fill prompt, models, voice, and phone number when no API can. - Typed errors — auth, scope, validation, business-rule, and rate-limit failures each raise a distinct exception with details.
- Bundled JSON Schema — the canonical manifest schema ships inside the package.
Prerequisites
- Python 3.10+
- An agent-scoped API key created in the SuperBryn dashboard (Developers → API Keys, scope: Single agent). Org-wide keys are rejected by the sync endpoints.
Install
pip install superbryn-agent-sync # zero runtime dependencies
pip install "superbryn-agent-sync[async]" # + aiohttp for the async client
The import name is superbryn:
from superbryn import Superbryn, Manifest
Quick Start
-
Set your agent-scoped API key in the environment:
export SUPERBRYN_API_KEY="sk_agent_..."
-
Build a manifest and sync it:
from superbryn import Superbryn, Manifest manifest = ( Manifest.builder(source="custom") .set_identity(name="Support Agent", type="inbound", agent_modality="voice") .set_behavior(prompt=open("system_prompt.txt").read()) .set_llm(provider="openai", model="gpt-4o", temperature=0.7, max_tokens=1024) .set_stt(provider="deepgram", model="nova-2", language="en-US") .set_tts(provider="cartesia", model="sonic-2") .set_voice(provider="cartesia", voice_id="a0e99841-...") .add_tool( name="lookup_order", description="Look up an order by ID", schema={"type": "object", "properties": {}}, server={"type": "http", "url": "https://api.example.com/orders"}, ) .set_language(primary_language="en-US", additional_languages=[{"code": "es-US", "priority": 1}]) .set_telephony(phone_number="+15551234567") .set_policy_guardrails(open("guardrails.md").read()) .set_concurrency_calls(10) .build() ) client = Superbryn() # or Superbryn(api_key="sk_agent_...") result = client.sync(manifest) # {"agent_row_id": "...", "approval_status": "pending", "verification_status": "...", # "hash": "...", "change_types": [...]}
-
Open the SuperBryn dashboard, review the pending draft, and approve it to promote a new agent version.
Every manifest field is optional — send only what your integration knows. An empty manifest is valid.
Client Surface
client.sync(manifest) # push; lands as pending draft (or no-op)
The async client mirrors the same surface (pip install "superbryn-agent-sync[async]"):
from superbryn import AsyncSuperbryn
result = await AsyncSuperbryn(api_key="sk_agent_...").sync(manifest)
Content Hashing
The SDK implements the same RFC 8785 (JCS) + SHA-256 content hashing as the server, so a client-side hash always agrees with the server's:
from superbryn import compute_manifest_hash
local_hash = compute_manifest_hash(manifest) # == manifest.hash
Framework Adapters
Lazy submodules — the base package depends on neither framework.
Pipecat
from superbryn import Superbryn
from superbryn.pipecat import build_manifest_from_pipeline
manifest = build_manifest_from_pipeline(
pipeline,
identity={"name": "Support Agent", "type": "inbound", "agent_modality": "voice"},
behavior={"prompt": open("prompt.txt").read()},
policy_guardrails=open("guardrails.md").read(),
)
Superbryn(api_key="sk_agent_...").sync(manifest)
Walks pipeline._processors and fills llm / stt / tts / voice automatically. Extractors read public attributes only — never API keys.
LiveKit
from superbryn import Superbryn
from superbryn.livekit import build_manifest_from_agent
manifest = build_manifest_from_agent(
agent,
identity={"name": "Support Agent", "type": "inbound", "agent_modality": "voice"},
policy_guardrails=open("guardrails.md").read(),
)
Superbryn(api_key="sk_agent_...").sync(manifest)
Reads agent.llm / agent.stt / agent.tts and uses agent.instructions as the behavior prompt.
Provider Translators
For SaaS platforms the agent config lives in their cloud, not in your process. Fetch the agent JSON from the provider's API, then translate it to a manifest:
import requests
from superbryn import Superbryn
from superbryn.translators import vapi
raw = requests.get(
"https://api.vapi.ai/assistant/ASSISTANT_ID",
headers={"Authorization": "Bearer VAPI_KEY"},
).json()
manifest = vapi.manifest_from_assistant(raw)
Superbryn(api_key="sk_agent_...").sync(manifest)
| Provider | Translator | Input |
|---|---|---|
| Vapi | translators.vapi.manifest_from_assistant(raw) |
GET /assistant/:id |
| Retell | translators.retell.manifest_from_agent(agent, llm) |
GET /get-agent/:id + GET /get-retell-llm/:llm_id |
| ElevenLabs | translators.elevenlabs.manifest_from_agent(raw) |
GET /v1/convai/agents/:id |
| Bland | translators.bland.manifest_from_agent(raw) |
GET /v1/agents/:id |
| Bolna | translators.bolna.manifest_from_agent(raw) |
GET /v2/agent/:id |
| Hooman Labs / Shunya Labs / custom | translators.generic.manifest_from_prompt(prompt, source=...) or codescan.build_manifest_from_source(...) (see below) |
your own prompt + known pipeline facts (no public agent-read API yet) |
All translators are best-effort — unknown or missing fields degrade to a sparser manifest, never an error.
Source-Code Extraction (works for every provider)
You never know in advance what a provider's public API returns — some give back the full agent config, others little more than an id, and some (Hooman Labs, Shunya Labs, in-house stacks) have no agent-read API at all. Whatever the API does or doesn't return, the customer's own code — the place that instantiates the provider's package/SDK — is always available. superbryn.codescan statically scans that code and extracts the prompt, model, voice, language, temperature and phone number.
As the sole source (no API, or the API returned nothing useful):
from superbryn import Superbryn
from superbryn.codescan import build_manifest_from_source
manifest = build_manifest_from_source(
"path/to/agent-project", # directory or single file
source="hooman-labs",
identity={"name": "Support Agent", "type": "inbound"}, # anything the scan can't see
)
Superbryn(api_key="sk_agent_...").sync(manifest)
As a gap filler after ANY translator — the scan adds only the fields the provider's API didn't provide, and API-provided values always win:
from superbryn import codescan, translators
manifest = translators.vapi.manifest_from_assistant(raw) # may be sparse
manifest = codescan.fill_manifest_gaps(manifest, "path/to/agent-project")
How it works:
- Python files are parsed with
ast: keyword arguments on any call (prompt=,instructions=,model=,voice_id=, ...) are collected, and simple variable references (prompt=SYSTEM_PROMPT) resolve to their assigned string constants. - JS/TS files are scanned with conservative regexes for the same keys in object-literal form (
systemPrompt: "...",voiceId: '...'). - Called class names classify hits per pipeline stage (
DeepgramSTTService→ stt/deepgram,CartesiaTTSService→ tts/cartesia), so an STT model never lands in thellmblock. - The longest prompt-key string wins as
behavior.prompt;node_modules, virtualenvs and build output are skipped.
Extraction is best-effort and read-only. Run it in CI next to the agent code and every deploy syncs the latest config. Use scan_source(path) to inspect the raw findings before building a manifest.
Manifest Fields
Override sections accept exactly the fields of the canonical manifest schema (unknown keys raise ValueError locally — the endpoint rejects them anyway):
| Section | Fields |
|---|---|
identity |
name, type (inbound/outbound), agent_modality (voice/chat), description, pain_point, gender, age, dob |
behavior |
prompt, flow |
llm / stt / tts / voice |
provider, model / voice_id, plus per-block extras (temperature, max_tokens, language, fallback, extra) |
tools |
list of {name, description, schema, server: {type, url}} |
language |
primary_language, additional_languages: [{code, priority}] |
telephony |
phone_number, ivr_config |
Plus top-level strings/ints: policy_guardrails, additional_details, concurrency_calls.
The canonical JSON Schema is bundled with the package:
from superbryn import load_manifest_schema
schema = load_manifest_schema()
Typed Errors
from superbryn import (
AuthenticationError, # 401 — bad/revoked key
ScopeError, # 403 — key is not agent-scoped
NotFoundError, # 404 — resource not found
ManifestValidationError, # 400 — schema failure (has .details)
BusinessRuleError, # 422 — semantic rule failure (has .details)
RateLimitError, # 429 — back off and retry
)
Troubleshooting
Enable debug logs
import logging
logging.basicConfig(level=logging.DEBUG)
logging.getLogger("superbryn").setLevel(logging.DEBUG)
Common errors
| Error | Cause | Fix |
|---|---|---|
ConfigurationError: no API key |
Missing API key | Pass api_key= or set SUPERBRYN_API_KEY |
AuthenticationError (401) |
Invalid or revoked key | Verify the key in SuperBryn → Developers → API Keys |
ScopeError (403) |
Org-wide key used | Create an agent-scoped key (scope: Single agent) |
NotFoundError (404) |
Resource not found | Verify the key belongs to the intended agent |
ManifestValidationError (400) |
Manifest fails schema validation | Inspect .details for the offending fields |
BusinessRuleError (422) |
Semantic rule failure | Inspect .details and adjust the manifest |
RateLimitError (429) |
Too many requests | Back off and retry |
Environment Variables
| Variable | Meaning |
|---|---|
SUPERBRYN_API_KEY |
Agent-scoped API key (fallback for api_key=) |
SUPERBRYN_BASE_URL |
API base URL (default https://api.superbryn.com) |
Links
Support
- Email: support@superbryn.com
- GitHub issues: Report a bug
License
This project is licensed under the MIT License — see the LICENSE file for details.
Made with ❤️ by SuperBryn
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file superbryn_agent_sync-0.1.4.tar.gz.
File metadata
- Download URL: superbryn_agent_sync-0.1.4.tar.gz
- Upload date:
- Size: 36.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6d5246f38a0825136bb8883bafb02ab3d927a02aca9c39ce1f9b87317588dc77
|
|
| MD5 |
b0975ea07b016b2630e6ba3c2ef7037a
|
|
| BLAKE2b-256 |
5285406cf21fec2c7879ba3278f10af28c00fac472d4c5849953aeae7af37dba
|
File details
Details for the file superbryn_agent_sync-0.1.4-py3-none-any.whl.
File metadata
- Download URL: superbryn_agent_sync-0.1.4-py3-none-any.whl
- Upload date:
- Size: 35.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
14cf6105e095d5206b4ab18e065326b48818593f8ed072e4a9ee4587fefbfb8c
|
|
| MD5 |
8e71eb87de51722f5946bc142833e46f
|
|
| BLAKE2b-256 |
4c103ae78b29c5007b60c6cd18ee82366c9b3728a3c65cc7bc4398c53c4ef06c
|