DEV Community

João André Gomes Marques
João André Gomes Marques

Posted on • Originally published at asqav.com

SDK v0.2.9: Output Verification, Attestations, Preflight and Budgets

v0.2.9 is out on PyPI. Four new things, all driven by what people asked for after shipping agents to production: prove the output wasn't swapped, hand a customer a document they can verify themselves, check everything before you run, and stop agents burning through a budget.

Install or upgrade:

pip install --upgrade asqav
Enter fullscreen mode Exit fullscreen mode

Output verification

Signing that an action happened is one thing. Proving the output you see now is the same output the agent produced is another. sign_output binds a hash of the result to a hash of the input, then verify_output checks both later.

import asqav

agent = asqav.Agent.create("research-bot")

query = {"question": "latest NIST PQC guidance"}
result = {"answer": "FIPS 203, 204, 205 finalized in 2024"}

sig = agent.sign_output(
    action_type="tool:search",
    input_hash=asqav._hash_value(query),
    output=result,
)

# Later, or on another machine:
check = asqav.verify_output(sig.signature_id, result)
assert check["verified"]  # signature valid AND output matches
Enter fullscreen mode Exit fullscreen mode

If anyone changes a character in result before verification, output_matches comes back false. If the signature itself was tampered with, signature_valid comes back false. You get both signals separately so you can tell what went wrong.

Portable attestations

You often need to show someone outside your team that an agent did what it was supposed to, without giving them access to your Asqav account. generate_attestation builds a self-contained document with the agent's public key, a session summary, and a signature over the whole thing. verify_attestation checks it.

agent = asqav.Agent.create("contract-reviewer")
session = agent.start_session()
# ... run the agent, sign actions ...
agent.end_session()

doc = asqav.generate_attestation(
    agent.agent_id,
    session_id=session.session_id,
)

# Hand doc.json to an auditor. They run:
result = asqav.verify_attestation(doc)
print(result["valid"], result["all_valid"], result["signatures_checked"])
Enter fullscreen mode Exit fullscreen mode

The attestation carries its own hash and signature, plus every signature ID from the session. The auditor doesn't need your keys. They just need the SDK and the document.

Pre-flight checks

Before v0.2.9 you had to call three things to know if an agent was cleared: status, policy list, and sometimes certificate. preflight does it in one call and tells you why if it says no.

agent = asqav.Agent.get("agt_abc123")

check = agent.preflight("api:transfer")
if not check.cleared:
    print("blocked:", check.reasons)
    return

# Agent is active and policy allows the action. Proceed.
Enter fullscreen mode Exit fullscreen mode

It returns cleared, agent_active, policy_allowed, and a list of reasons. If a sub-check errors, the reason is noted but the agent isn't blocked on infrastructure hiccups. Run it at the top of any sensitive action and you catch revoked agents and policy blocks before you waste an LLM call.

Budget tracking

Agents that call paid APIs need a ceiling. BudgetTracker enforces the limit client-side and signs every spend entry so the trail is tamper-evident.

agent = asqav.Agent.create("data-enricher")
budget = asqav.BudgetTracker(agent, limit=10.0, currency="USD")

decision = budget.check(estimated_cost=0.25)
if not decision.allowed:
    raise RuntimeError(decision.reason)  # "budget_exhausted"

# ... call OpenAI, measure actual cost ...
budget.record("api:openai", actual_cost=0.23, context={"model": "gpt-4"})

print(budget.status())
# {'limit': 10.0, 'currency': 'USD', 'spend': 0.23, 'remaining': 9.77, 'records': 1}
Enter fullscreen mode Exit fullscreen mode

Every record call writes a signed entry through the agent's key. You can replay the trail against the verification endpoint at any point and prove exactly where the money went. Negative, NaN, and infinite costs all get rejected. The check fails closed.

Why these four

These are the gaps people kept hitting. Signing the call isn't enough if the output can be swapped. Signatures aren't useful if you can't hand one to an external reviewer. Status and policy checks want to be one call. Budget caps need to be real, not a comment in a README.

Full changelog and source on GitHub. Docs at asqav.com/docs. If something doesn't work the way you expect, open an issue.

Top comments (0)