Framework Recipes
Drop-in patterns for the four most common agent frameworks. Wire CloudVera once at startup, then existing agent code keeps working — the gateway enforces policy without changes to your business logic.
Features
Thin-client by design
Your framework keeps owning the plan→act→observe loop. CloudVera observes, enforces, and audits. Switching frameworks doesn't require re-implementing security.
Approval-aware
Every recipe routes tool calls through recordToolCallAndWait so framework-native tools transparently honor policy=approval_required.
Code Examples
LangChain
import { DynamicStructuredTool } from '@langchain/core/tools';
import { CloudVera, AgentClient, SessionClient, previewToolInput } from '@cloudvera/agent-sdk';
import { z } from 'zod';
const cv = new CloudVera({ apiKey: process.env.CLOUDVERA_KEY! });
const agents = new AgentClient(cv);
const sessions = new SessionClient(cv);
const agent = await agents.create({
name: 'security-triage',
framework: 'langchain',
toolCallPolicy: 'approval_required',
allowedTools: ['deploy_rule'],
});
const { session } = await sessions.start(agent.id);
const deployRule = new DynamicStructuredTool({
name: 'deploy_rule',
schema: z.object({ ruleId: z.string() }),
description: 'Push a detection rule to prod (requires approval).',
func: async (input) => {
await sessions.recordToolCallAndWait(agent.id, session.id, {
toolName: 'deploy_rule',
inputPreview: previewToolInput(input),
});
return await deployRuleToProd(input.ruleId);
},
});
// Hand deployRule to your LangChain agent as usual. Policy enforcement
// happens at recordToolCallAndWait — no agent-loop changes needed.
CrewAI
# CloudVera doesn't yet ship a Python SDK — call the REST surface
# directly via httpx. Same shape as the TS SDK.
from crewai_tools import BaseTool
import httpx, json, time
API = "https://api.cloudvera.io/api/ai-gateway/agents"
H = {"Authorization": f"Bearer {os.environ['CLOUDVERA_KEY']}",
"Content-Type": "application/json"}
class DeployRuleTool(BaseTool):
name = "deploy_rule"
description = "Push detection rule to prod (requires approval)"
def _run(self, rule_id: str) -> str:
r = httpx.post(
f"{API}/{AGENT_ID}/sessions/{SESSION_ID}/tool-calls",
headers=H, json={"toolName": "deploy_rule",
"inputPreview": json.dumps({"ruleId": rule_id})})
if r.status_code == 202:
approval_id = r.json()["approvalId"]
# Poll the approval until decided (or local timeout)
for _ in range(60):
time.sleep(2)
a = httpx.get(f"{API}/approvals/{approval_id}", headers=H).json()["approval"]
if a["status"] == "approved":
return deploy_rule_to_prod(rule_id)
if a["status"] in ("denied", "expired"):
raise RuntimeError(f"Tool call {a['status']}")
raise TimeoutError("Reviewer SLA exceeded")
return deploy_rule_to_prod(rule_id)
AutoGen
from autogen import register_function
import httpx, json
API = "https://api.cloudvera.io/api/ai-gateway/agents"
H = {"Authorization": f"Bearer {os.environ['CLOUDVERA_KEY']}",
"Content-Type": "application/json"}
def deploy_rule(rule_id: str) -> str:
"""Push detection rule. Routes through CloudVera approval queue."""
r = httpx.post(f"{API}/{AGENT_ID}/sessions/{SESSION_ID}/tool-calls",
headers=H,
json={"toolName": "deploy_rule",
"inputPreview": json.dumps({"ruleId": rule_id})})
# ... same poll loop as the CrewAI recipe above ...
return _wait_and_deploy(r, rule_id)
register_function(
deploy_rule,
caller=autogen_assistant,
executor=autogen_user_proxy,
name="deploy_rule",
description="Push rule with human approval gate",
)
OpenAI Assistants
import OpenAI from 'openai';
import { CloudVera, AgentClient, SessionClient, previewToolInput } from '@cloudvera/agent-sdk';
const openai = new OpenAI();
const cv = new CloudVera({ apiKey: process.env.CLOUDVERA_KEY! });
const cvAgents = new AgentClient(cv);
const cvSessions = new SessionClient(cv);
// Register the CloudVera agent that mirrors your Assistant
const cvAgent = await cvAgents.create({
name: 'support-bot',
framework: 'openai-assistants',
toolCallPolicy: 'approval_required',
allowedTools: ['refund_order'],
});
const { session } = await cvSessions.start(cvAgent.id);
// In your tool-call handler for the Assistant run loop:
async function handleRefundOrder(args: { orderId: string }) {
const call = await cvSessions.recordToolCallAndWait(
cvAgent.id, session.id,
{ toolName: 'refund_order', inputPreview: previewToolInput(args) },
{ timeoutMs: 5 * 60_000 },
);
// call.status === 'executed' — reviewer approved
return await processRefund(args.orderId);
}