callguard
Guardrails for AI-agent tool / function calls. Framework-agnostic, zero heavy
dependencies (only jsonschema). Makes agent tool calls reliable and
cost-bounded — the two things every agent framework reinvents from
scratch and gets wrong.
Why this exists
In production, agents don't fail with clean exceptions. They fail with:
- JSON that has single quotes, trailing commas, unquoted keys (LLM output)
- Wrong types (
"123"instead of123) - Missing required args (the model "forgot")
- Typo'd tool names (
send_emialvssend_email) - $40 runaway loops because nothing capped spend
- Retry storms against a tool that's 5xx-ing
callguard handles all six in one decorator.
Install
pip install agent-callguard
(PyPI name is agent-callguard; you import it as callguard.)
Quick start
from callguard import Guard
g = Guard(
budget=g.budget(max_cost=1.0, cost_per_call=0.002), # stop the $40 loop
breaker=g.breaker(failure_threshold=5, reset_after=30), # halt retry storms
cache=g.cache(ttl=120), # skip dup idempotent reads
)
@g.tool(schema={
"type": "object",
"properties": {
"to": {"type": "string"},
"subject": {"type": "string"},
"priority": {"type": "string", "enum": ["low", "normal", "high"]},
"retry": {"type": "integer"},
},
"required": ["to", "subject"],
})
def send_email(to, subject, body="", priority="normal", retry=0):
... # your real tool body
return f"sent:{to}"
# The LLM produced this MESSY blob — callguard fixes it automatically:
g.call("send_email", "{'to': 'a@b.com', 'subject': 'Hi', 'retry': '3'}")
# -> single quotes repaired, '3' coerced to int 3, tool executed OK
# Typo'd tool name? Auto-recovered:
g.call("send_emial", {"to": "a@b.com", "subject": "Hi"}) # redirects to send_email
# Missing required arg? Structured, actionable error (not a stack trace):
try:
g.call("send_email", {"to": "a@b.com"})
except ToolCallError as e:
print(e.errors[0].suggestion) # "provide 'subject'"
What it does
| Feature | Module | Behavior |
|---|---|---|
| JSON repair | errors.repair_json |
single quotes, trailing commas, unquoted keys, True/False/None, code fences |
| Type coercion | schema.validate |
"3"→3, "true"→True, "1.5"→1.5 before failing |
| Actionable validation | schema.validate |
errors name the field + show the fix: "field 'x' expected number, got str" |
| Tool-name recovery | errors.suggest_tool |
Levenshtein match redirects send_emial→send_email |
| Error classification | errors.classify |
transient/retryable (timeout, 429, 5xx) vs hard (401, 404, auth) |
| Cost & quota budget | budget.Budget |
raises before a hard cap; soft-warn callback at 80% |
| Circuit breaker | breaker.CircuitBreaker |
opens after N consecutive failures, half-opens to probe recovery |
| Response cache | cache.Cache |
short-TTL dedupe for idempotent reads |
Lower-level pieces
Every component is importable and usable on its own:
from callguard import repair_json, validate, classify, suggest_tool, parse_args
from callguard import Budget, CircuitBreaker, Cache, tool, Guard
repair_json("{'a': 1,}") # '{"a": 1}'
classify("503 Service Unavailable") # CallError(kind='transient', recoverable=True)
suggest_tool("send_emial", ["send_email", "get_weather"]) # 'send_email'
Backtest
The repo ships a regression corpus of real-world malformed agent calls
(callguard/backtest.py) — single-quote JSON, trailing commas, missing
args, enum typos, tool-name typos, transient vs hard errors, budget
enforcement, circuit-breaker trips. Run it:
python -m callguard.backtest
Current status: 18 / 18 cases passing.
License
MIT
Metadata
Release files for agent-callguard 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| agent_callguard-0.1.0.tar.gz | 63.8 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| agent_callguard-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 81.5 kB
Release files / agent_callguard-0.1.0.tar.gz
| Download URL | agent_callguard-0.1.0.tar.gz |
|---|---|
| Size | 63.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6605e67879c22d48a754323575a3a1709451b32447d602f0cae8134df2297a81
|
|
BLAKE2b-256 checksum How to use checksums |
2c4927f1b44bbaf75407e5553c26388ae1883df8ff30ca9521f0876c0981fd86
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / agent_callguard-0.1.0-py3-none-any.whl
| Download URL | agent_callguard-0.1.0-py3-none-any.whl |
|---|---|
| Size | 17.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8626f471f36598e1a1586cfd96b9ddd074c52aad61cd421c030f7eb10c11a2ea
|
|
BLAKE2b-256 checksum How to use checksums |
0d98148a6c74412c18188a0c396a790d363304defa645c98d167308032e48053
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for agent-callguard 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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
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.