Async Support
Use acall(), async sessions, and async middleware for non-blocking tool execution.
Overview
Every agentguard GuardedTool supports async execution out of the box. Use acall() for async tool invocations, or use the async with tool.session() context manager for session-scoped tracing.
Async Tool Execution
python
from agentguard import guard
@guard(validate_input=True, max_retries=3)
def search_web(query: str) -> dict:
return requests.get(f"https://api.search.com?q={{query}}").json()
# Sync call
result = search_web("Python tutorials")
# Async call
result = await search_web.acall("Python tutorials")
Session Context Manager
The async with tool.session() context manager groups multiple tool calls into a single session for trace recording:
python
from agentguard import guard
@guard(record=True, detect_hallucination=True)
def search_web(query: str) -> dict:
return requests.get(f"https://api.search.com?q={{query}}").json()
# All calls within the session share a session_id
async with search_web.session() as session:
r1 = await session.acall("Python tutorials")
r2 = await session.acall("FastAPI docs")
# Both calls are recorded under the same session trace
async_record_session()
For programmatic session recording in async contexts:
python
from agentguard import async_record_session
async with async_record_session(storage="./traces", backend="sqlite", session_id="my-session") as recorder:
result = await search_web.acall("test query")
entries = recorder.entries()
# Traces written to ./traces/agentguard_traces.db
Async Middleware
Middleware functions can be async — the pipeline handles both sync and async middleware transparently:
python
from agentguard.middleware import MiddlewareChain
# Async middleware
async def auth_middleware(ctx, next):
if not ctx.metadata.get("api_key"):
raise PermissionError("No API key")
return await next(ctx)
# Sync middleware (automatically wrapped)
def logging_middleware(ctx, next):
print(f"Calling {{ctx.tool_name}}")
return next(ctx) # Returns a coroutine, awaited automatically
chain = MiddlewareChain()
chain.use(auth_middleware)
chain.use(logging_middleware)
@guard(middleware=chain)
async def my_tool(x: str) -> str:
return x.upper()
Mixed sync/async
You can freely mix sync and async middleware in the same chain. Sync middleware is wrapped transparently so that next(ctx) returns a coroutine that the framework awaits.
Async with Integration Wrappers
python
from agentguard.integrations.crewai_integration import GuardedCrewAITool
from agentguard.integrations.autogen_integration import GuardedAutoGenTool
# CrewAI async
guarded = GuardedCrewAITool(search_web, config=config)
result = await guarded.arun(query="test")
# AutoGen async
guarded = GuardedAutoGenTool(search_web, config=config)
result = await guarded.acall(query="test")