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);
}