SDK Guide
Installation note
The SDKs are currently distributed as part of the TameFlare monorepo. Install them locally:
# Node.js — from the monorepo root
npm install ./packages/sdk-node
# Python — from the monorepo root
pip install ./packages/sdk-pythonWhen published to npm/PyPI (coming soon), you'll be able to install with npm install @agentfirewall/sdk and pip install agentfirewall.
Node.js
# Install from source (npm package coming soon)
npm install ./packages/sdk-nodeBasic usage
import { AgentFirewall } from "@agentfirewall/sdk";
const TameFlare = new AgentFirewall({
apiKey: process.env.AAF_API_KEY,
baseUrl: process.env.AAF_BASE_URL ?? "http://localhost:3000/api",
});
const result = await TameFlare.requestAction({
type: "github.pr.merge",
resource: {
provider: "github",
account: "my-org",
target: "my-org/my-repo",
environment: "production",
},
parameters: { pull_number: 42 },
});
if (result.status === "allowed") {
await TameFlare.execute(result.action_request_id, result.decision_token);
} else if (result.status === "pending_approval") {
const approved = await TameFlare.waitForApproval(result.action_request_id);
if (approved) await TameFlare.execute(result.action_request_id, approved.decision_token);
}Handling all outcomes
const result = await TameFlare.requestAction({
type: "payment.transfer.initiate",
resource: {
provider: "stripe",
account: "acct_123",
target: "transfers",
environment: "production",
},
parameters: { amount: 25000, currency: "USD" },
risk_hints: {
financial_impact: true,
irreversible: true,
production_target: true,
},
});
switch (result.status) {
case "allowed":
// Action approved immediately — execute it
const execResult = await TameFlare.execute(
result.action_request_id,
result.decision_token
);
console.log("Executed:", execResult);
break;
case "pending_approval":
// Action needs human approval — wait or use webhook
console.log("Waiting for approval from:", result.approval.required_approver_groups);
const approved = await TameFlare.waitForApproval(result.action_request_id, {
timeoutMs: 300_000, // 5 minutes
pollIntervalMs: 5_000, // check every 5s
});
if (approved) {
await TameFlare.execute(result.action_request_id, approved.decision_token);
} else {
console.log("Approval timed out or was rejected");
}
break;
case "denied":
// Action blocked by policy
console.log("Denied:", result.decision.reason);
// Do NOT retry — the policy will deny it again
break;
}Error handling and rate limits
try {
const result = await TameFlare.requestAction({ /* ... */ });
} catch (error) {
if (error.status === 429) {
// Rate limited — the SDK auto-retries by default
// but you can handle it manually if needed
const retryAfter = error.retryAfter; // seconds
console.log(`Rate limited. Retry after ${retryAfter}s`);
} else if (error.status === 401) {
// Invalid API key
console.error("Check your AAF_API_KEY");
} else {
console.error("Unexpected error:", error.message);
}
}429 (rate limit) and 5xx (server error) responses with exponential backoff. You can disable this with autoRetry: false in the client config.Failover mode (circuit breaker)
By default, the SDK throws an error when TameFlare is unreachable (failoverMode: "closed"). You can switch to "open" mode to get a synthetic deny result instead of an exception:
const TameFlare = new AgentFirewall({
apiKey: process.env.AAF_API_KEY,
failoverMode: "open",
onFailover: (error) => {
// Alert your monitoring system
console.error("TameFlare unreachable, failover triggered:", error.message);
},
});
// If TameFlare is down, this returns a deny result instead of throwing
const result = await TameFlare.requestAction({ /* ... */ });
if (result.status === "denied" && result.decision.reason.includes("failover")) {
// Handle gracefully — TameFlare was unreachable
}| Mode | Behavior when TameFlare is down | Use case |
|---|---|---|
| closed (default) | Throws error — agent must handle | Safety-critical: no action without TameFlare |
| open | Returns synthetic deny | Graceful degradation: agent gets a clear signal |
Using webhooks instead of polling
Instead of polling for approval status, you can provide a webhook_url to be notified when a decision is made:
const result = await TameFlare.requestAction({
type: "github.pr.merge",
resource: { /* ... */ },
parameters: { pull_number: 42 },
}, {
webhookUrl: "https://your-server.com/TameFlare-webhook",
});
// Your webhook endpoint receives:
// POST /TameFlare-webhook
// {
// "action_request_id": "act_abc123",
// "status": "approved",
// "decision_token": "eyJhbGci..."
// }Python
# Install from source (PyPI package coming soon)
pip install ./packages/sdk-pythonBasic usage
from agentfirewall import AgentFirewall
import os
TameFlare = AgentFirewall(
api_key=os.environ["AAF_API_KEY"],
base_url=os.environ.get("AAF_BASE_URL", "http://localhost:3000/api"),
)
result = TameFlare.request_action(
action_type="github.issue.create",
provider="github",
account="my-org",
target="my-org/my-repo",
environment="development",
parameters={"title": "Bug fix", "body": "Details..."},
)
if result.status == "allowed":
TameFlare.execute(result.action_request_id, result.decision_token)Handling all outcomes
result = TameFlare.request_action(
action_type="payment.transfer.initiate",
provider="stripe",
account="acct_123",
target="transfers",
environment="production",
parameters={"amount": 25000, "currency": "USD"},
risk_hints={
"financial_impact": True,
"irreversible": True,
"production_target": True,
},
)
if result.status == "allowed":
exec_result = TameFlare.execute(result.action_request_id, result.decision_token)
print(f"Executed: {exec_result}")
elif result.status == "pending_approval":
print(f"Waiting for approval from: {result.approval.required_approver_groups}")
approved = TameFlare.wait_for_approval(
result.action_request_id,
timeout_seconds=300,
poll_interval_seconds=5,
)
if approved:
TameFlare.execute(result.action_request_id, approved.decision_token)
else:
print("Approval timed out or was rejected")
elif result.status == "denied":
print(f"Denied: {result.decision.reason}")Async client
from agentfirewall import AsyncAgentFirewall
import asyncio
async def main():
TameFlare = AsyncAgentFirewall(
api_key=os.environ["AAF_API_KEY"],
)
result = await TameFlare.request_action(
action_type="infra.server.provision",
provider="aws",
account="123456789",
target="ec2",
environment="staging",
parameters={"instance_type": "t3.large", "count": 3},
)
if result.status == "allowed":
await TameFlare.execute(result.action_request_id, result.decision_token)
asyncio.run(main())Error handling
from agentfirewall.exceptions import RateLimitError, AuthError, AAFError
try:
result = TameFlare.request_action(...)
except RateLimitError as e:
print(f"Rate limited. Retry after {e.retry_after}s")
except AuthError:
print("Invalid API key")
except AAFError as e:
print(f"TameFlare error: {e.message}")CLI
The CLI is useful for managing agents and policies from your terminal or CI/CD pipelines.
npx tf init # Set up TameFlare config in current directory
npx tf status # Check control plane connectivity
npx tf agents list # List all registered agents
npx tf policies list # List all policiesAgent management
# Create a new agent
npx tf agents create --name "deploy-bot" --env production
# Revoke an agent's API key
npx tf agents revoke --id agent_abc123
# View agent activity
npx tf agents activity --id agent_abc123 --limit 20Policy management
# Install a policy from a YAML file
npx tf policies install ./policies/payment-controls.yaml
# List all policies with status
npx tf policies list
# Dry-run a policy against a test action
npx tf policies dry-run \
--type payment.transfer.initiate \
--provider stripe \
--env production \
--param amount=25000.TameFlare.yaml in your project root. Run npx tf init to create one with your API key and base URL.Framework integration
LangChain (Python)
Wrap TameFlare checks around LangChain tool calls:
from langchain.tools import tool
from agentfirewall import AgentFirewall
TameFlare = AgentFirewall(api_key=os.environ["AAF_API_KEY"])
@tool
def create_github_issue(title: str, body: str, repo: str) -> str:
"""Create a GitHub issue with TameFlare policy enforcement."""
result = TameFlare.request_action(
action_type="github.issue.create",
provider="github",
account="my-org",
target=repo,
environment="production",
parameters={"title": title, "body": body},
)
if result.status == "denied":
return f"Blocked by policy: {result.decision.reason}"
if result.status == "allowed":
exec_result = TameFlare.execute(result.action_request_id, result.decision_token)
return f"Issue created: {exec_result.result}"
return f"Pending approval from: {result.approval.required_approver_groups}"OpenAI function calling (Node.js)
Gate tool execution behind TameFlare before calling external APIs:
import { AgentFirewall } from "@agentfirewall/sdk";
import OpenAI from "openai";
const TameFlare = new AgentFirewall({ apiKey: process.env.AAF_API_KEY! });
const openai = new OpenAI();
async function handleToolCall(toolCall: OpenAI.ChatCompletionMessageToolCall) {
const { name, arguments: args } = toolCall.function;
const parsed = JSON.parse(args);
// Check with TameFlare before executing
const result = await TameFlare.requestAction({
type: `tool.${name}`,
resource: {
provider: "openai-tools",
account: "my-org",
target: name,
environment: "production",
},
parameters: parsed,
context: { reason: "OpenAI function call" },
risk_hints: {},
});
if (result.status !== "allowed") {
return { error: `Blocked: ${result.decision.reason}` };
}
// Execute the actual tool call
return executeToolFunction(name, parsed);
}CrewAI (Python)
Add TameFlare as a pre-execution hook for CrewAI agents:
from crewai import Agent, Task, Crew
from agentfirewall import AgentFirewall
TameFlare = AgentFirewall(api_key=os.environ["AAF_API_KEY"])
def aaf_guarded_tool(action_type: str, params: dict):
"""Wrapper that checks TameFlare before executing any tool."""
result = TameFlare.request_action(
action_type=action_type,
provider="crewai",
account="my-org",
target=action_type,
environment="production",
parameters=params,
)
if result.status != "allowed":
raise PermissionError(f"TameFlare denied: {result.decision.reason}")
return result
# Use in your CrewAI tools
researcher = Agent(
role="Researcher",
goal="Find information",
tools=[your_aaf_wrapped_tools],
)requestAction() before executing the tool, check the result, and only proceed if allowed. TameFlare is framework-agnostic — it works with any agent that makes API calls.