JSPM

@agent-action-firewall/sdk

1.0.0
  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 191
  • Score
    100M100P100Q76335F
  • License MIT

Official TypeScript SDK for Agent Action Firewall - AI agent security platform

Package Exports

  • @agent-action-firewall/sdk

Readme

Agent Action Firewall TypeScript SDK

Official TypeScript SDK for the Agent Action Firewall - a security layer for AI agents.

Installation

npm install @agent-action-firewall/sdk
# or
pnpm add @agent-action-firewall/sdk
# or
yarn add @agent-action-firewall/sdk

Quick Start

import { AgentFirewallClient } from '@agent-action-firewall/sdk';

const client = new AgentFirewallClient({
  baseUrl: 'https://api.agentactionfirewall.com',
  apiKey: process.env.AGENT_FIREWALL_API_KEY!,
  agentId: 'my-agent',
});

// Submit an action for policy evaluation
const response = await client.submitAction({
  tool: 'http_proxy',
  operation: 'POST',
  params: {
    url: 'https://api.example.com/data',
    body: { key: 'value' },
  },
});

console.log('Action status:', response.status);

Usage

Submit an Action

const response = await client.submitAction({
  tool: 'http_proxy',
  operation: 'POST',
  params: {
    url: 'https://api.example.com/data',
    body: { key: 'value' },
  },
  // Optional: prevent duplicate submissions
  idempotencyKey: 'unique-request-id',
});

switch (response.status) {
  case 'allowed':
    // Action is allowed, execute it
    console.log('Action allowed');
    break;
  case 'denied':
    // Action was denied by policy
    console.log('Denied:', response.decision?.reason);
    break;
  case 'pending_approval':
    // Requires human approval
    console.log('Waiting for approval:', response.approvalId);
    break;
}

Get Action Status

const detail = await client.getAction(actionId);
console.log('Status:', detail.status);
console.log('Decision:', detail.decision);
console.log('Approval:', detail.approval);

Wait for Approval

// Wait up to 5 minutes for approval
const finalStatus = await client.waitForApproval(actionId, {
  timeout: 300000,
  interval: 2000, // Poll every 2 seconds
  onStatusChange: (status) => {
    console.log('Status update:', status.status);
  },
});

console.log('Final status:', finalStatus.status);

Submit and Wait

Convenience method that submits an action and waits for completion:

const result = await client.submitAndWait({
  tool: 'jira',
  operation: 'create_ticket',
  params: {
    project: 'PROJ',
    summary: 'New ticket',
    description: 'Created by AI agent',
  },
});

if (result.status === 'succeeded') {
  console.log('Ticket created:', result.execution?.result);
}

Configuration Options

const client = new AgentFirewallClient({
  // Required
  baseUrl: 'https://api.agentactionfirewall.com',
  apiKey: 'your-api-key',
  agentId: 'your-agent-id',

  // Optional
  timeout: 30000, // Request timeout in ms (default: 30000)
  debug: false, // Enable debug logging
});

Error Handling

import { AgentFirewallError } from '@agent-action-firewall/sdk';

try {
  await client.submitAction({ ... });
} catch (error) {
  if (error instanceof AgentFirewallError) {
    console.error('Code:', error.code);
    console.error('Message:', error.message);
    console.error('Status:', error.statusCode);
    console.error('Details:', error.details);
  }
}

Error Codes

  • CONFIG_ERROR - Invalid configuration
  • NETWORK_ERROR - Network connectivity issue
  • TIMEOUT_ERROR - Request or polling timeout
  • API_ERROR - API returned an error response

Types

The SDK exports TypeScript types for all request and response objects:

import type {
  AgentFirewallConfig,
  ActionRequest,
  ActionResponse,
  ActionDetail,
  ActionDecision,
  ApprovalSummary,
  ExecutionSummary,
  PollOptions,
} from '@agent-action-firewall/sdk';

Integration Examples

OpenAI Function Calling

Wrap OpenAI function calls with firewall governance:

import OpenAI from 'openai';
import { AgentFirewallClient } from '@agent-action-firewall/sdk';

const openai = new OpenAI();
const firewall = new AgentFirewallClient({
  baseUrl: 'https://api.agentactionfirewall.com',
  apiKey: process.env.AGENT_FIREWALL_API_KEY!,
  agentId: 'openai-assistant',
});

// Define a governed function
async function executeFunction(name: string, args: Record<string, unknown>) {
  // Check with firewall before executing
  const response = await firewall.submitAndWait({
    tool: name,
    operation: 'execute',
    params: args,
  });

  if (response.status === 'denied') {
    throw new Error(`Action denied: ${response.decision?.reason}`);
  }

  // Execute the actual function
  return await actualFunctionExecution(name, args);
}

// Use with OpenAI
const completion = await openai.chat.completions.create({
  model: 'gpt-4',
  messages: [{ role: 'user', content: 'Create a Jira ticket for the bug' }],
  tools: [
    {
      type: 'function',
      function: {
        name: 'create_jira_ticket',
        parameters: { /* ... */ },
      },
    },
  ],
});

// When OpenAI wants to call a function
for (const call of completion.choices[0].message.tool_calls || []) {
  const result = await executeFunction(
    call.function.name,
    JSON.parse(call.function.arguments)
  );
}

Anthropic Claude Tool Use

Integrate with Claude's tool use capabilities:

import Anthropic from '@anthropic-ai/sdk';
import { AgentFirewallClient } from '@agent-action-firewall/sdk';

const anthropic = new Anthropic();
const firewall = new AgentFirewallClient({
  baseUrl: 'https://api.agentactionfirewall.com',
  apiKey: process.env.AGENT_FIREWALL_API_KEY!,
  agentId: 'claude-assistant',
});

async function handleToolUse(toolName: string, toolInput: Record<string, unknown>) {
  // Submit to firewall
  const response = await firewall.submitAndWait({
    tool: toolName,
    operation: 'execute',
    params: toolInput,
    metadata: {
      source: 'claude',
      model: 'claude-3-opus',
    },
  });

  if (response.status !== 'succeeded') {
    return { error: `Action ${response.status}: ${response.decision?.reason}` };
  }

  return response.execution?.result;
}

const message = await anthropic.messages.create({
  model: 'claude-3-opus-20240229',
  max_tokens: 1024,
  tools: [
    {
      name: 'send_email',
      description: 'Send an email to a recipient',
      input_schema: {
        type: 'object',
        properties: {
          to: { type: 'string' },
          subject: { type: 'string' },
          body: { type: 'string' },
        },
        required: ['to', 'subject', 'body'],
      },
    },
  ],
  messages: [{ role: 'user', content: 'Send an email to team@example.com' }],
});

// Process tool use blocks
for (const block of message.content) {
  if (block.type === 'tool_use') {
    const result = await handleToolUse(block.name, block.input);
    // Continue conversation with result...
  }
}

Vercel AI SDK

Use with the Vercel AI SDK for streaming responses:

import { openai } from '@ai-sdk/openai';
import { streamText, tool } from 'ai';
import { z } from 'zod';
import { AgentFirewallClient } from '@agent-action-firewall/sdk';

const firewall = new AgentFirewallClient({
  baseUrl: 'https://api.agentactionfirewall.com',
  apiKey: process.env.AGENT_FIREWALL_API_KEY!,
  agentId: 'vercel-ai-agent',
});

const result = await streamText({
  model: openai('gpt-4-turbo'),
  tools: {
    createTicket: tool({
      description: 'Create a support ticket',
      parameters: z.object({
        title: z.string(),
        description: z.string(),
        priority: z.enum(['low', 'medium', 'high']),
      }),
      execute: async ({ title, description, priority }) => {
        // Firewall check
        const response = await firewall.submitAndWait({
          tool: 'ticketing',
          operation: 'create',
          params: { title, description, priority },
        });

        if (response.status === 'denied') {
          return { error: response.decision?.reason };
        }

        return { ticketId: response.execution?.result?.id };
      },
    }),
  },
  messages: [{ role: 'user', content: 'Create a high priority ticket for the outage' }],
});

LangChain.js Integration

Wrap LangChain tools with firewall governance:

import { ChatOpenAI } from '@langchain/openai';
import { DynamicStructuredTool } from '@langchain/core/tools';
import { AgentExecutor, createOpenAIToolsAgent } from 'langchain/agents';
import { AgentFirewallClient } from '@agent-action-firewall/sdk';
import { z } from 'zod';

const firewall = new AgentFirewallClient({
  baseUrl: 'https://api.agentactionfirewall.com',
  apiKey: process.env.AGENT_FIREWALL_API_KEY!,
  agentId: 'langchain-agent',
});

// Create a governed tool
const governedSearchTool = new DynamicStructuredTool({
  name: 'web_search',
  description: 'Search the web for information',
  schema: z.object({
    query: z.string().describe('The search query'),
  }),
  func: async ({ query }) => {
    // Check with firewall first
    const response = await firewall.submitAndWait({
      tool: 'web_search',
      operation: 'search',
      params: { query },
    });

    if (response.status === 'denied') {
      throw new Error(`Search denied: ${response.decision?.reason}`);
    }

    // Execute actual search
    return await performWebSearch(query);
  },
});

const llm = new ChatOpenAI({ model: 'gpt-4' });
const agent = await createOpenAIToolsAgent({
  llm,
  tools: [governedSearchTool],
  prompt: /* your prompt */,
});

Express.js Middleware

Create middleware for API routes that require firewall approval:

import express from 'express';
import { AgentFirewallClient } from '@agent-action-firewall/sdk';

const app = express();
const firewall = new AgentFirewallClient({
  baseUrl: 'https://api.agentactionfirewall.com',
  apiKey: process.env.AGENT_FIREWALL_API_KEY!,
  agentId: 'api-gateway',
});

// Middleware to check firewall for all agent actions
const firewallMiddleware = (toolName: string) => {
  return async (req: express.Request, res: express.Response, next: express.NextFunction) => {
    try {
      const response = await firewall.submitAction({
        tool: toolName,
        operation: req.method,
        params: {
          path: req.path,
          body: req.body,
          query: req.query,
        },
        metadata: {
          ip: req.ip,
          userAgent: req.get('user-agent'),
        },
      });

      if (response.status === 'denied') {
        return res.status(403).json({
          error: 'Action denied by policy',
          reason: response.decision?.reason,
          riskLevel: response.decision?.riskLevel,
        });
      }

      if (response.status === 'pending_approval') {
        return res.status(202).json({
          message: 'Action requires approval',
          approvalId: response.approvalId,
          actionId: response.id,
        });
      }

      // Attach action info to request for logging
      req.firewallAction = response;
      next();
    } catch (error) {
      next(error);
    }
  };
};

// Use on routes
app.post('/api/agents/:agentId/execute',
  firewallMiddleware('agent_execution'),
  async (req, res) => {
    // Action was approved, proceed with execution
    const result = await executeAgentAction(req.body);
    res.json(result);
  }
);

Next.js API Route

Protect Next.js API routes with firewall checks:

// app/api/agent/action/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { AgentFirewallClient } from '@agent-action-firewall/sdk';

const firewall = new AgentFirewallClient({
  baseUrl: 'https://api.agentactionfirewall.com',
  apiKey: process.env.AGENT_FIREWALL_API_KEY!,
  agentId: 'nextjs-agent',
});

export async function POST(request: NextRequest) {
  const body = await request.json();

  // Submit to firewall
  const response = await firewall.submitAndWait({
    tool: body.tool,
    operation: body.operation,
    params: body.params,
  });

  if (response.status === 'denied') {
    return NextResponse.json(
      { error: 'Denied', reason: response.decision?.reason },
      { status: 403 }
    );
  }

  if (response.status === 'succeeded') {
    return NextResponse.json({
      success: true,
      result: response.execution?.result,
    });
  }

  return NextResponse.json(
    { error: 'Action failed', status: response.status },
    { status: 400 }
  );
}

License

MIT