Skip to content

Latest commit

 

History

History
343 lines (255 loc) · 9.14 KB

File metadata and controls

343 lines (255 loc) · 9.14 KB

AgentContainers Proxy

A flexible proxy service that bridges Slack conversations with pluggable agentic systems, providing a seamless interface for users to interact with AI agents through Slack.

Overview

This service acts as a middleware layer between Slack and various AI agent backends (AWS Lambda, Docker containers). It receives Slack webhooks, fetches user configuration from a bootstrap server, forwards messages to the appropriate agent backend, and maintains session continuity across Slack threads.

Features

  • Multi-Backend Support: Run agents via AWS Lambda or Docker containers
  • Session Persistence: Maintains conversation context across Slack threads
  • Dual Deployment Modes: Deploy as HTTP server or AWS Lambda function
  • Async Processing: Non-blocking message handling for responsive Slack interactions
  • User Configuration: Dynamic user config fetching from bootstrap server
  • Error Handling: Graceful error reporting back to Slack users

Architecture

Components

  • Slack Handler: Processes incoming Slack webhooks and events
  • Bootstrap Client: Fetches user-specific agent configurations
  • Agent Clients: Interfaces with different agent backends (Lambda/Docker)
  • Session Manager: PostgreSQL-based thread-to-session mapping
  • Service Layer: Orchestrates the flow between components

Deployment Modes

  1. HTTP Server Mode: Standalone server receiving Slack webhooks
  2. Lambda Function Mode: Serverless deployment with API Gateway integration
  3. Docker Agent Mode: Local Docker container execution for development

Installation

Prerequisites

  • Go 1.24.3 or higher
  • PostgreSQL database
  • Slack App with Events API configured
  • AWS credentials (for Lambda mode)
  • Docker (for Docker agent mode)

Setup

  1. Clone the repository:
git clone https://github.com/pbdeuchler/agentcontainers-proxy
cd agentcontainers-proxy
  1. Install dependencies:
go mod download
  1. Set up the database:
# Run migrations using goose
goose -dir migrations postgres "$DATABASE_URL" up
  1. Configure environment variables (see Configuration section)

Configuration

Environment Variables

Variable Description Required Default
DATABASE_URL PostgreSQL connection string Yes -
BOOTSTRAP_SERVER_URL Bootstrap server endpoint for user configs Yes -
AGENT_LAMBDA_ARN ARN of the Claude Code Lambda function Conditional* -
DOCKER_IMAGE_NAME Docker image for agent execution Conditional* -
SLACK_BOT_TOKEN Slack Bot OAuth token Yes -
SLACK_BOT_USER_ID Slack bot's user ID (to ignore self-messages) No -
SLACK_SIGNING_SECRET Slack app signing secret No -
PORT HTTP server port No 2010
ANTHROPIC_API_KEY API key for Claude (Docker mode) Conditional** -

*Either AGENT_LAMBDA_ARN or DOCKER_IMAGE_NAME must be set **Required when using Docker agent mode

Example Configuration

Copy .env.example to .env and update with your values:

cp .env.example .env
# Edit .env with your configuration

Usage

Running the HTTP Server

# Using go run
go run main.go

# Or build and run
go build -o agentcontainers-proxy
./agentcontainers-proxy

Lambda Deployment

The service automatically detects Lambda environment:

  1. Build for Lambda:
GOOS=linux GOARCH=amd64 go build -o bootstrap main.go
zip function.zip bootstrap
  1. Deploy to AWS Lambda with appropriate environment variables

Docker Agent Mode

To use Docker containers as the agent backend:

export DOCKER_IMAGE_NAME="your-agent-image:tag"
export ANTHROPIC_API_KEY="your-api-key"
go run main.go

API Flow

sequenceDiagram
    participant Slack
    participant Proxy
    participant Bootstrap
    participant Database
    participant Agent

    Slack->>Proxy: POST /slack/webhook
    Proxy->>Bootstrap: GET ?slack_id={user_id}
    Bootstrap-->>Proxy: User config
    Proxy->>Database: Check thread_id mapping
    Database-->>Proxy: session_id (if exists)
    Proxy->>Agent: Invoke with prompt + session
    Agent-->>Proxy: Response + session_id
    Proxy->>Database: Store session mapping
    Proxy->>Slack: Post reply to thread
    Proxy-->>Slack: 200 OK
Loading

Project Structure

agentcontainers-proxy/
├── agentclients/         # Agent backend interfaces
│   ├── docker/          # Docker container client
│   ├── lambda/          # AWS Lambda client
│   └── types.go         # Shared types
├── bootstrap/           # Bootstrap server client
├── cmd/                 # Application entry points
│   ├── common.go       # Shared initialization
│   ├── config.go       # Configuration management
│   ├── lambda.go       # Lambda handler
│   └── server.go       # HTTP server
├── dao/                 # Database access layer
├── migrations/          # Database migrations
├── service/            # Business logic layer
├── slack/              # Slack integration
│   ├── client.go       # Slack API client
│   └── handler.go      # Webhook handler
└── main.go             # Main entry point

Database Schema

The service uses PostgreSQL to maintain session continuity:

CREATE TABLE session_mappings (
    id SERIAL PRIMARY KEY,
    thread_id VARCHAR(255) UNIQUE NOT NULL,
    session_id VARCHAR(255) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_thread_id ON session_mappings(thread_id);

Slack App Configuration

  1. Create a new Slack App at https://api.slack.com/apps
  2. Enable Event Subscriptions
  3. Add Bot Token Scopes:
    • chat:write
    • app_mentions:read
    • messages.channels
    • messages.groups
    • messages.im
    • messages.mpim
  4. Subscribe to bot events:
    • message.channels
    • message.groups
    • message.im
    • message.mpim
  5. Set Request URL to your proxy endpoint:
    • HTTP Server: https://your-domain.com/slack/webhook
    • Lambda: Your API Gateway URL

Bootstrap Server Protocol

The bootstrap server must implement the following endpoint:

GET /bootstrap?slack_id={slack_user_id}

Response format:

{
    "user": {...},
    "prompt": "Initial system prompt",
    "append_system_prompt": "Additional context",
    "allowed_tools": ["tool1", "tool2"],
    "disallowed_tools": ["tool3"],
    "env": {...}
}

Agent Request/Response Format

Request (AgentRequest)

{
    "user": {...},
    "prompt": "User message with context",
    "append_system_prompt": "Additional instructions",
    "allowed_tools": ["Read", "Write"],
    "disallowed_tools": ["Delete"],
    "env": {...},
    "resume_session_id": "previous-session-id"
}

Response (AgentResponse)

{
  "type": "result",
  "subtype": "success",
  "is_error": false,
  "result": "Agent response text",
  "session_id": "new-or-continued-session-id"
}

Development

Running Tests

go test ./...

Building

# Local build
go build -o agentcontainers-proxy

# Linux build for Lambda
GOOS=linux GOARCH=amd64 go build -o bootstrap

Debugging

Enable verbose logging by setting:

export DEBUG=true

Monitoring

The service logs important events including:

  • Incoming Slack messages
  • Bootstrap server calls
  • Agent invocations
  • Database operations
  • Error conditions

Security Considerations

  • Store sensitive environment variables securely
  • Use HTTPS for all external communications
  • Validate Slack requests using signing secret
  • Implement rate limiting for production deployments
  • Regularly rotate API keys and tokens
  • Use least-privilege IAM roles for Lambda execution

Troubleshooting

Common Issues

  1. Database Connection Errors: Verify DATABASE_URL format and network access
  2. Slack Not Responding: Check bot token permissions and webhook URL
  3. Agent Timeout: Increase Lambda timeout or check Docker resource limits
  4. Bootstrap Server Errors: Verify server URL and authentication
  5. Session Continuity Loss: Check database connectivity and migrations

Debug Commands

# Test database connection
psql "$DATABASE_URL" -c "SELECT 1"

# Verify Slack token
curl -H "Authorization: Bearer $SLACK_BOT_TOKEN" https://slack.com/api/auth.test

# Check Lambda function
aws lambda get-function --function-name $AGENT_LAMBDA_ARN

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Commit your changes
  4. Push to the branch
  5. Create a Pull Request

License

This project is licensed under the GNU GPLv3 License with the Commons Clause License Condition v1.0.

Support

For issues and questions, please open an issue on GitHub.