Day 6 14 min read

Advanced Configuration

Master custom tool creation, prompt engineering techniques, resource management, plugin extensions, and environment variable configuration.

Custom Tools

Tools are the hands of your agents β€” they allow agents to interact with the outside world. ThePopeBot comes with built-in tools, but you can create custom tools for any purpose.

Creating a Custom Tool

Every tool implements the Tool interface:

import { defineTool, ToolResult } from '../engine/tools';

export const databaseTool = defineTool({
  name: 'database',
  description: 'Query and manipulate the application database',
  parameters: {
    action: {
      type: 'string',
      enum: ['query', 'insert', 'update'],
      description: 'The database operation to perform',
    },
    table: {
      type: 'string',
      description: 'The target table name',
    },
    data: {
      type: 'object',
      description: 'The query parameters or data payload',
    },
  },
  required: ['action', 'table'],

  async execute(params): Promise<ToolResult> {
    const { action, table, data } = params;

    switch (action) {
      case 'query':
        const results = await db.select(table, data);
        return { success: true, data: results };

      case 'insert':
        const id = await db.insert(table, data);
        return { success: true, data: { id } };

      case 'update':
        const count = await db.update(table, data);
        return { success: true, data: { updatedRows: count } };

      default:
        return { success: false, error: `Unknown action: ${action}` };
    }
  },
});

Registering the Tool

Add it to config/tools.yaml:

tools:
  database:
    module: "./tools/database"
    enabled: true
    permissions:
      - query
      - insert
      - update
    rateLimit:
      maxCalls: 100
      windowMs: 60000

Tool Safety

Always implement safety measures in your custom tools:

async execute(params): Promise<ToolResult> {
  // Validate inputs
  if (!allowedTables.includes(params.table)) {
    return { success: false, error: 'Access denied to this table' };
  }

  // Sanitize data
  const sanitized = sanitize(params.data);

  // Log the operation
  logger.info('Tool execution', { tool: 'database', params: sanitized });

  // Execute with timeout
  return withTimeout(5000, () => db.query(sanitized));
}

Prompt Engineering Techniques

The quality of your agent depends heavily on its system prompt. Here are advanced techniques for crafting effective prompts.

Chain of Thought (CoT)

Instruct the agent to think step by step before acting:

When solving a problem:
1. First, restate the problem in your own words
2. List the key constraints and requirements
3. Consider 2-3 possible approaches
4. Evaluate each approach against the constraints
5. Choose the best approach and explain why
6. Implement the solution
7. Verify the solution meets all requirements

Few-Shot Examples

Provide examples of expected input-output pairs:

Example 1:
Input: "Add a password reset endpoint"
Plan:
  - Create POST /api/auth/reset-password
  - Generate a time-limited reset token
  - Send reset email with token link
  - Create PUT /api/auth/reset-password/:token to set new password
Output: [implementation files]

Example 2:
Input: "Fix the login timeout issue"
Plan:
  - Investigate current timeout settings
  - Check session middleware configuration
  - Identify the root cause
  - Apply fix with proper error handling
Output: [fix details]

Structured Output Format

Define the exact format you want the agent to produce:

Always respond with this structure:

## Analysis
[Brief analysis of the task]

## Plan
1. [Step 1]
2. [Step 2]
...

## Implementation
[Code or actions taken]

## Verification
[How you verified the solution works]

## Next Steps
[Suggestions for follow-up work]

Persona Layering

Combine multiple perspectives into a single prompt:

You are a senior developer with three areas of expertise:
- As an architect, you consider system-wide impacts
- As a security engineer, you identify vulnerabilities
- As a performance engineer, you optimize for speed

When reviewing code, apply all three perspectives and
clearly label which perspective each finding comes from.

Resource Limits

Production agents need resource constraints to prevent runaway costs and ensure fair usage.

Configuring Limits

Set limits in config/resources.yaml:

resources:
  global:
    maxConcurrentAgents: 10
    maxTokensPerMinute: 100000
    maxToolCallsPerRequest: 50

  perAgent:
    default:
      maxTokensPerRequest: 4096
      maxToolCalls: 20
      timeoutMs: 120000  # 2 minutes
      maxRetries: 3

    coder:
      maxTokensPerRequest: 8192
      maxToolCalls: 50
      timeoutMs: 300000  # 5 minutes

  perUser:
    maxRequestsPerHour: 60
    maxTokensPerDay: 500000

Implementing Graceful Degradation

When limits are reached, agents should degrade gracefully:

const resourcePolicy = {
  onTokenLimit: 'summarize',    // Summarize instead of truncating
  onToolLimit: 'prioritize',    // Execute only high-priority tools
  onTimeout: 'partial-result',  // Return what's done so far
  onRateLimit: 'queue',         // Queue the request for later
};

Plugin Extensions

ThePopeBot supports a plugin system for extending functionality without modifying core code.

Plugin Structure

plugins/
β”œβ”€β”€ my-plugin/
β”‚   β”œβ”€β”€ index.ts        # Plugin entry point
β”‚   β”œβ”€β”€ tools/          # Custom tools
β”‚   β”œβ”€β”€ agents/         # Custom agents
β”‚   β”œβ”€β”€ hooks/          # Lifecycle hooks
β”‚   └── plugin.yaml     # Plugin configuration

Creating a Plugin

import { definePlugin } from '../engine/plugins';

export default definePlugin({
  name: 'github-integration',
  version: '1.0.0',
  description: 'Deep GitHub integration with issue tracking and CI/CD',

  tools: [
    githubIssueTool,
    githubActionsTool,
    githubProjectsTool,
  ],

  hooks: {
    onEvent: async (event) => {
      // Pre-process events before they reach agents
      if (event.source === 'webhook:github') {
        event.metadata.enriched = await enrichGitHubData(event);
      }
    },

    onResponse: async (response) => {
      // Post-process agent responses
      if (response.metadata.createIssue) {
        await createGitHubIssue(response);
      }
    },
  },
});

Plugin Configuration

# plugin.yaml
name: github-integration
enabled: true
config:
  githubToken: "${GITHUB_TOKEN}"
  defaultOrg: "my-org"
  features:
    autoLabel: true
    ciIntegration: true
    projectBoard: true

Environment Variables

ThePopeBot uses environment variables for sensitive configuration. Here is a comprehensive reference:

Core Variables

# LLM Provider
OPENAI_API_KEY=sk-...
OPENAI_ORG_ID=org-...
ANTHROPIC_API_KEY=sk-ant-...
LLM_PROVIDER=openai          # openai, anthropic, or custom

# Server
PORT=3000
HOST=0.0.0.0
NODE_ENV=development          # development, staging, production

# Logging
LOG_LEVEL=info                # debug, info, warn, error
LOG_FORMAT=json               # json or pretty

Channel Variables

# Telegram
TELEGRAM_BOT_TOKEN=...
TELEGRAM_ALLOWED_USERS=...

# Webhooks
GITHUB_WEBHOOK_SECRET=...
WEBHOOK_BASE_URL=https://your-domain.com

Security Variables

# Authentication
JWT_SECRET=your-secret-key
SESSION_TIMEOUT=3600
CORS_ORIGINS=https://your-domain.com

# Encryption
ENCRYPTION_KEY=...
ENCRYPTION_ALGORITHM=aes-256-gcm

Best Practices for Environment Variables

  1. Never commit .env files to version control
  2. Use .env.example as a template with placeholder values
  3. Validate on startup β€” fail fast if required variables are missing
  4. Use different values for development, staging, and production
  5. Rotate secrets regularly, especially API keys and JWT secrets
// Startup validation example
const required = ['OPENAI_API_KEY', 'JWT_SECRET', 'LLM_PROVIDER'];
for (const key of required) {
  if (!process.env[key]) {
    throw new Error(`Missing required environment variable: ${key}`);
  }
}