Skip to main content

VegaDūta Agent SDK for Python

Governance for AI agents in Python, as a dependency. Tool risk classification, human approval, budgets, idempotent effects, content guardrails, policy hooks, audit and telemetry, wired around the tools you already have — plus the guarantees a security review, a compliance officer or an incident post-mortem asks for: a kill switch, tiered autonomy, delegation mandates that can only narrow, a tamper-evident (hash-chained, signable) audit trail, durable SQLite stores, tool-shape pinning, governed memory, cost attribution and policy replay. Framework-free — works on plain and async functions — with adapters for LangChain, OpenAI-style tool calling and an OpenTelemetry observer.

This is the Python sibling of the Java Agent SDK (sdk/java, io.github.cd-lc:vegaduta-agent-*): same contracts, same vocabulary, same audit format. It is a different thing from sdk/python (vegaduta_sdk), which is the generated REST client that calls the VegaDūta platform API — this library runs inside your own application. Apache-2.0. Python 3.10+.

Status: 0.1.0, not yet on PyPI. Install from source: pip install ./sdk/python-agent (or pip install -e ./sdk/python-agent for development).

Why this exists

LangChain, Pydantic AI, LlamaIndex, the OpenAI Agents SDK and a hand-rolled tool loop all give you model calls and tool dispatch. None of them answers what a security review, a compliance officer or an incident post-mortem asks:

  • which tools can this agent reach, and what can each one do to the world?
  • who approved that refund, and what exactly was approved?
  • how much did this run spend, and what stopped it?
  • if the turn is retried, does the payment happen twice?
  • did a web page the agent read try to re-program it?
  • one audit record across every tool call, tagged with the OWASP agentic risk (ASI01–ASI10) it relates to.

The SDK answers those with one dependency-free package and one decorator, and does not require a server, a UI or a database to start (though it supports durable storage and pluggable sinks for all three).

60-second start

from vegaduta_agent import Governance, governed, RiskLabel, AsiRisk

@governed(risk=RiskLabel.HIGH, requires_approval=True, idempotent=True,
          risks={AsiRisk.ASI02})
def refund(order_id: str, cents: int) -> str:
    ...

@governed(risk=RiskLabel.LOW, side_effecting=False, idempotent=True)
def order_status(order_id: str) -> str:
    ...

governance = Governance()
tools = governance.scan(__import__(__name__))   # or governance.wrap(refund)

Now, when the model calls refund:

  1. The dispatch gate and hooks evaluate the call; CRITICAL risk and requires_approval=True record an approval request instead of running — the tool returns {"approvalRequired": true, "approvalId": ...} for the model to relay to the user.
  2. order_status runs immediately; a repeat of the same call in the same run is served from the effect journal (the payment never happens twice).
  3. A per-run budget (default: 50 tool calls) stops loops before they spend.
  4. Tool output is redacted for credential-looking text, and flagged when a fetched page reads like a prompt-injection attempt.
  5. Every outcome lands as one key=value audit line on the vegaduta.agent.audit logger and can drive metrics/OTel execute_tool spans via observers.

Decide the approval from your own UI, a chat command or a ticket:

gate = governance.approval_gate
req = gate.pending(tenant_id="acme")[0]
gate.approve(req.id, "reviewer@corp")   # runs refund(), journals the result
gate.reject(other.id, "cfo", "not this quarter")

The pieces

Piece Type Default
@governed decorator → ToolClassification MEDIUM, side-effecting
Dispatch gate ToolDispatchGate protocol allow-all; policy lives in the decorator
Approval ApprovalGate + ApprovalStore in-memory, 24 h TTL
Effect journal EffectJournal in-memory; SqliteEffectJournal is stdlib-durable
Budget BudgetProvider → Budget 50 tool calls per run
Guardrails ContentGuardrail at 4 stages secret redaction + injection flagging
Hooks Hook at 9 HookPoints none; fail mode CLOSED
Audit AuditSink key=value lines to vegaduta.agent.audit; SqliteAuditSink for durability
Observers ToolCallObserver none; OtelToolCallObserver with [otel]
Mode GovernanceMode ENFORCE; OBSERVE audits without stopping
Report governance_report(run_id, events, approvals) Markdown/JSON: per-tool risk, outcomes, approval decisions, OWASP ASI coverage
Kill switch HaltSwitch + HaltGate engages a halt on a tool, an agent or everything; halt_drill proves it works
Autonomy AutonomyGate + AutonomyRegistry L1 observe → L4 act; L2 recommends, L3 needs approval on HIGH, CRITICAL always gated
Mandates Mandate.derive, verify_mandate_chain, MandateGate delegation that can only narrow, digest-chained across hops
Evidence HashChainedAuditSink, HmacSha256, verify_audit_chain, evidence_bundle tamper-evident audit with optional signature; JSON/Markdown export
Provenance ProvenanceGate on Governance(provenance=...) pins each tool's promised surface; ENFORCE refuses a drifted description or schema
Memory GovernedMemoryStore writes pass guardrails, carry provenance; tool-output text is poison-probed
Cost CostLedger + CostObserver, showback per-run/agent/principal/tool attribution and a markdown report
Replay policy_replay, ShadowGate, TraceRecorder, replay_trace measure a stricter policy before enforcing it; record and re-run tool traces
Risk map risk_map(module) the scan-before-you-integrate report: unclassified tools, approval coverage, lethal-trifecta, ASI exposure, 0-100 score
Notify slack_message(req), teams_message(req) approval payloads for chat review; the HTTP transport is your port
Reconcile interrupted_keys(journal) effects that began but never recorded — the "did the payment run?" check
Approvals+ FourEyesAuthorizer, allowed_deciders, sign_receipt/verify_receipt two-person rule and signed decision receipts
Async Governance.wrap_async / tool.acall(...) same pipeline around async def tools

LangChain

from vegaduta_agent.adapters.langchain import to_langchain_tools

lc_tools = to_langchain_tools(governance.scan(my_tools_module), context=ctx)
# pass to create_react_agent / bind_tools as usual

Install the extra with pip install './sdk/python-agent[langchain]' (quote it: zsh expands the brackets; the name vegaduta-agent[langchain] works once the package is on PyPI). The pipeline is unchanged — the adapter only translates the call surface, so governance behaves identically across frameworks.

OpenAI-style tool calling

from vegaduta_agent.adapters.openai import openai_tools, dispatch_tool_call

tools = governance.scan(my_tools_module)
resp = client.chat.completions.create(model=..., tools=openai_tools(tools.values()))
for call in resp.choices[0].message.tool_calls or []:
    messages.append({"role": "tool", "tool_call_id": call.id,
                     "content": dispatch_tool_call(call.model_dump(), tools, ctx)})

Dependency-free — it works with the OpenAI SDK, LiteLLM, Azure OpenAI, Ollama's OpenAI mode or a hand-rolled loop. The governed result (including approvalRequired JSON) is the tool message the model sees.

Durability and evidence

Everything is in-memory by default so the SDK starts with zero infrastructure; the stdlib sqlite3 stores make approvals, audit and the effect journal durable with one file:

from vegaduta_agent import (Governance, SqliteApprovalStore, SqliteAuditSink,
                            SqliteEffectJournal, HashChainedAuditSink, HmacSha256,
                            verify_audit_chain, evidence_bundle)

sink = SqliteAuditSink("agent.db")
chain = HashChainedAuditSink(sink, HmacSha256(key))   # tamper-evident + signed
g = Governance(approval_gate=ApprovalGate(SqliteApprovalStore("agent.db")),
               journal=SqliteEffectJournal("agent.db"), audit_sink=chain)
...
report = verify_audit_chain(sink.events())           # intact or the break point
bundle = evidence_bundle(sink.events(run_id), run_id).to_markdown()

sign_receipt/verify_receipt do the same for an approval decision: a signed record of who approved what, verifiable later. HMAC is in the box; plug in Ed25519 from your crypto library when the audit consumer is untrusted.

Webhooks and other hooks

WebhookHook posts each chosen HookPoint to your endpoint — but the transport is a port you supply (the SDK imports no HTTP client; the contract test test_sdk_makes_no_http_call_to_core enforces it). Three lines of urllib.request or your existing client is the adapter; a response of {"block": "reason"} turns the endpoint into a policy service.

Observability

pip install './sdk/python-agent[otel]' (once on PyPI: vegaduta-agent[otel]) adds OtelToolCallObserver, emitting one execute_tool span per call with gen_ai.* attributes — the same convention the platform's core/chat module uses, so platform and embedded agents land in one trace view.

Rules that are easy to miss

  • Share the RunContext across a run's calls. Budgets and the effect journal are keyed by run_id; a fresh context per call defeats both. tool(args, context=ctx), or bind one with the LangChain adapter.
  • Approval resumptions are in-memory by default. An approval that outlives the process is recorded but cannot execute; SqliteApprovalStore makes the request durable (the resumption still must be re-issued — a callable cannot persist).
  • Undeclared tools are classified MEDIUM + side-effecting, never silently trusted. Declare honestly: idempotent=True on a tool that isn't is the one dangerous combination.
  • Failures raise, not return. ToolDeniedException, BudgetExceededException, GuardrailViolationException propagate to break the tool loop; adapters translate them into model-readable errors.
  • GovernanceMode.OBSERVE is the rollout path: full evaluation and audit, nothing blocked. Measure, then enforce.

Development

cd sdk/python-agent
python -m venv .venv && .venv/bin/pip install -e '.[dev]'
.venv/bin/python -m pytest tests/ -q
.venv/bin/ruff check vegaduta_agent tests
.venv/bin/ruff format --check vegaduta_agent tests   # `ruff format vegaduta_agent tests` fixes it

Metadata

Release files for vegaduta-agent 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for vegaduta-agent 0.1.0
File Size Uploaded Provenance Actions
vegaduta_agent-0.1.0.tar.gz 80.0 kB With provenance Details for vegaduta_agent-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for vegaduta-agent 0.1.0
File Interpreter ABI Platform Actions
vegaduta_agent-0.1.0-py3-none-any.whl Python 3 none any Details for vegaduta_agent-0.1.0-py3-none-any.whl

Total release size: 155.9 kB

Release files / vegaduta_agent-0.1.0.tar.gz

Download URL vegaduta_agent-0.1.0.tar.gz
Size 80.0 kB
Tags Source
SHA-256 checksum
How to use checksums
61e763675dc05bf3f4d364f8a19d0f3f1fe7458233883f89622d81a7d84438b6
BLAKE2b-256 checksum
How to use checksums
cd3dc5c0f447c28d5a65e4193b7b91afd79a18819352ac6d3475659437259454
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.

Transparency log

Release files / vegaduta_agent-0.1.0-py3-none-any.whl

Download URL vegaduta_agent-0.1.0-py3-none-any.whl
Size 75.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4b11c6e842700068c385fedac744caf82687bad5d36d38d636fc8964632cd5e6
BLAKE2b-256 checksum
How to use checksums
0d32312e8ffa7cd4a38cd418e8c09c236fb745501874f6405f5049abef83829d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.

Transparency log

Security for vegaduta-agent 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for vegaduta_agent-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page