Skip to main content

Build an LLM agent with spending limits, a tamper-evident audit trail, PII redaction, and record/replay testing built in from the start — a governed agent in about 10 lines.

Project description

cendor-sdk

A governed agent in 10 lines — cost budgets, tamper-evident audit, and PII redaction built in.

PyPI Python License Ruff types: mypy

provider-agnostic · local-first · offline by default · sync and async

A thin, provider-agnostic agent SDK where cost budgets, tamper-evident audit, PII redaction, context governance, and record/replay testing are the foundation, not a plugin.

cendor-sdk owns the agent loop, so every governance concern that is best-effort beneath a framework becomes first-class here: usage is never lost, budgets enforce before the model call, PII is redacted before send, and the whole run correlates under one trace_id. It's the simple, batteries-included door into the Cendor stack — you don't need to pick a framework or wire the libraries. (Already have a framework? Compose the libraries beneath it: pip install cendor-libs.)

Install

pip install "cendor-sdk[openai,anthropic]"     # provider SDKs are optional extras
pip install "cendor-sdk[all]"                  # every provider + interop, batteries included
# Using uv? Same names, same extras: `uv add` instead of `pip install`.

The install bundles the whole Cendor stack — all seven libraries (cendor-core, tokenguard, guardrails, acttrace, contextkit, squeeze, cassette) — by dependency, so you install once and import only from cendor.sdk. Provider SDKs stay optional extras: [openai], [anthropic], [google], [bedrock], [ollama], [huggingface], [azure], [foundry-local], plus [mcp] and [otel].

Using an AI coding assistant? uvx cendor-init (Python) / npx @cendor/init (TS) wires it up — or point it at cendor.ai/docs/for-ai-assistants.

A governed agent in 10 lines

Auth: OPENAI_API_KEY from your environment (or Agent(api_key=…), or a pre-built client=). The SDK builds the provider client for you — there's no Cendor-specific key. Full table: docs/providers.

from cendor.sdk import Agent, tool, run, budget, guard, Policy, AuditLog

@tool
def get_weather(city: str) -> str:
    """Current weather for a city."""
    return f"Sunny in {city}"

agent = Agent(name="assistant", model="gpt-4o", tools=[get_weather],
              instructions="Answer using tools when helpful.")

log = AuditLog(system="support", risk_tier="limited", path="audit.jsonl")
with budget(usd=0.25, on_exceed="block"), guard(Policy.default(), audit=log):
    result = run(agent, "What's the weather in Paris?", audit=log)

print(result.output)                        # -> "It's sunny in Paris."
print(result.cost, result.usage)            # priced in Decimal, budgeted
print([s.name for s in result.tool_steps])  # -> ["get_weather"]
# audit.jsonl: audit_open -> decision -> llm_call -> tool_call -> llm_call, hash-chained &
# verify()-able, all correlated by one trace_id. Wrap in cassette.using("run.json") to replay it.

Ungoverned still works — on cendor-core alone. Every governance layer is optional and removable; drop the with block and run(agent, ...) runs bare:

from cendor.sdk import Agent, run
result = run(Agent(name="a", model="gpt-4o", instructions="Be brief."), "Hi")
result = await run.aio(agent, "Hi")   # same call, async

run.aio is natively async for OpenAI (Chat + Responses — and the Microsoft Foundry (formerly Azure AI Foundry) / Foundry Local paths that use the same client), Anthropic, Google Gemini (google-genai's aio.models.generate_content), Ollama, and Hugging Face. Bedrock's boto3 converse is blocking, so run.aio offloads it to a worker thread (asyncio.to_thread) — the event loop keeps running, and the run's governance scope still attaches.

Why it's different

Provider lock Cost budgets Tamper-evident audit PII redaction Record/replay tests Local-first
OpenAI Agents SDK OpenAI-centric lib
LangGraph agnostic DIY DIY DIY DIY lib
Anthropic Agent SDK Anthropic-centric lib
CrewAI / Pydantic AI / ADK varies ✗/DIY lib
cendor-sdk agnostic built-in built-in built-in built-in yes

Governance is composed through Cendor's existing bus / interceptor / Sink / Compressor seams, correlated by trace()zero SDK-specific glue. Budgets, audit, redaction, and record/replay all ride the agent loop through those seams, so removing any one is just not entering its context.

Multi-agent, one correlated tree

Handoff, supervisor/router, and sequential/parallel pipelines — with the correlation that was impossible beneath frameworks. A whole multi-agent run is one governed, trace_id-correlated tree, on one verifiable audit chain. Handoff even works across providers:

from cendor.sdk import Agent, run

writer  = Agent(name="writer",  model="claude-opus-4-8", instructions="Write the brief.")
planner = Agent(name="planner", model="gpt-4o", instructions="Plan, then hand off.",
                handoffs=["writer"])

result = run([planner, writer], "Research X and write a brief")   # OpenAI -> Anthropic handoff
print(result.agents)     # ["planner", "writer"]

Every major provider — one canonical loop

The provider is inferred from the model id (override with provider=). History is held in one canonical shape, so a run can hand off between providers without rewriting it.

Provider Models Extra
OpenAI Chat Completions + Responses API [openai]
Anthropic Messages API [anthropic]
Google Gemini google-genai [google]
AWS Bedrock Converse API [bedrock]
Ollama local models [ollama]
Hugging Face Inference / endpoints [huggingface]
Microsoft Foundry deployments via the OpenAI v1 endpoint (Chat + Responses) [azure]
Foundry Local on-device, OpenAI-compatible [foundry-local]

More in the box

Everything a real agent needs — all governed through the same seams:

  • Streamingrun.stream / run.astream yield text deltas + tool events. Incremental token-level deltas on the OpenAI Chat family (including Microsoft Foundry, Foundry Local, and Hugging Face), Anthropic, and Ollama; OpenAI Responses, Gemini, and Bedrock yield the whole response as one delta.
  • Structured output — a dataclass / Pydantic / JSON-schema output_type uses each provider's native schema mode.
  • Reasoning & controlAgent.extra passes tool_choice, reasoning_effort, top_p, stop, …; o-series temperature is handled for you.
  • RAGVectorIndex + Agent(retriever=…) inject governed retrieval, or expose your store as a @tool.
  • MemorySession (conversation), SummarizingSession (rolling summary), SQLiteSessionStore (durable), context_budget (fit the window).
  • Embeddingsembed() / aembed() capture RAG calls on the same cost/audit tree.
  • Cost governance for any modelregister_model_price(...) so budgets bind on custom / deployment-named ids.
  • Interop — MCP tools, A2A server/client, a Foundry/Copilot adapter, and human-in-the-loop approvals on the same audit chain.
  • Production hardening — retry policies, and checkpointed/resumable runs so a crashed run continues where it stopped.
  • Observability, zero telemetry code — configure any OpenTelemetry provider and run() emits an agent.run span tree with usage/cost rollups and governance correlated to the run; CENDOR_TELEMETRY=off switches it off. Cendor has no endpoint or key — it emits into your backend.
  • Agent identityAgent(id="reg-42") rides the semconv gen_ai.agent.id on every span and governance row, so a budget block says which agent it stopped; no id means the attribute is omitted, never fabricated.

Scope & honest limits

  • on_exceed="raise" overshoots by one call — it's post-flight. For a true ceiling use "block".
  • Unpriced models record $0, so a USD cap can't bind on them — register_model_price(...) or use a token cap.
  • guard redacts what its detectors find — regex/pattern detectors plus Presidio NER (an optional extra). See acttrace for coverage.
  • guard / interceptors are process-global — they register on the single in-process bus, so install policy once at startup rather than toggling per request.
  • Evidence, not compliance. The audit chain supports a compliance case; it doesn't make one, and it isn't legal advice.

Docs

Rendered, searchable, with a page-wide Python / TypeScript toggle at cendor.ai/docs/sdk — the same markdown also renders on GitHub.

License

Apache-2.0.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cendor_sdk-1.22.2.tar.gz (429.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cendor_sdk-1.22.2-py3-none-any.whl (117.8 kB view details)

Uploaded Python 3

File details

Details for the file cendor_sdk-1.22.2.tar.gz.

File metadata

  • Download URL: cendor_sdk-1.22.2.tar.gz
  • Upload date:
  • Size: 429.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for cendor_sdk-1.22.2.tar.gz
Algorithm Hash digest
SHA256 549ee5ae48274a24427275405047d12001bf9415d7c6456f470aada5a8d3a7ad
MD5 97d4283123f83f076200b71e55364a71
BLAKE2b-256 bf4057d0770dd59a7f5ab55834363caf08f120d1b550aa2537a6fc5a34cd6a27

See more details on using hashes here.

Provenance

The following attestation bundles were made for cendor_sdk-1.22.2.tar.gz:

Publisher: release.yml on cendorhq/cendor-sdk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file cendor_sdk-1.22.2-py3-none-any.whl.

File metadata

  • Download URL: cendor_sdk-1.22.2-py3-none-any.whl
  • Upload date:
  • Size: 117.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for cendor_sdk-1.22.2-py3-none-any.whl
Algorithm Hash digest
SHA256 16d23e6fba68f2bde137e56c734ff4afe03fef47cf8d18afa3bcaeda50168478
MD5 216e62984e49d092592adb68aaf14a15
BLAKE2b-256 1073f44478b3567498764e9b4423002a462130f8c73473133724fa7e42a10dc8

See more details on using hashes here.

Provenance

The following attestation bundles were made for cendor_sdk-1.22.2-py3-none-any.whl:

Publisher: release.yml on cendorhq/cendor-sdk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page