Introduction

Functions transform your StateSet agents from conversationalists into action-takers. By connecting to external APIs and services, your agents can perform real tasks—from canceling orders to updating inventory, processing refunds to scheduling appointments. This guide will show you how to create, manage, and optimize functions for maximum impact.

What are Agent Functions?

Agent Functions are the bridge between conversation and action. When a customer asks your agent to do something, functions enable the agent to:

  • Understand Intent: Recognize what action needs to be taken
  • Extract Parameters: Gather necessary information from the conversation
  • Execute Actions: Call external APIs to perform the task
  • Handle Results: Process responses and communicate outcomes

How Agent Functions Work

Why Functions Matter

Automation at Scale

Handle thousands of requests simultaneously without human intervention

Instant Resolution

Complete actions in seconds that would take humans minutes or hours

Error Reduction

Eliminate manual errors with validated, tested automation

Getting Started

Prerequisites

  1. StateSet account with API access
  2. Agent created and configured
  3. External API endpoints ready to integrate
  4. API authentication credentials

Installation

npm install stateset-node

Creating Functions

Basic Function Structure

Every function needs:

  • Name: Unique identifier for the function
  • Description: Clear explanation for the agent to understand usage
  • Endpoint: The API URL to call
  • Parameters: Information to extract from conversations
  • Authentication: How to authenticate with the external API

Example: Order Cancellation Function

Let’s create a comprehensive order cancellation function:

import { StateSetClient } from 'stateset-node';

const client = new StateSetClient({
  apiKey: process.env.STATESET_API_KEY
});

async function createOrderCancellationFunction(agentId) {
  try {
    const cancelOrderFunction = await client.functions.create({
      agent_id: agentId,
      name: 'cancel_order',
      description: 'Cancels a customer order and processes any necessary refunds',
      endpoint: 'https://api.yourstore.com/v1/orders/{order_id}/cancel',
      method: 'POST',
      parameters: [
        {
          name: 'order_id',
          type: 'string',
          description: 'The unique order identifier',
          required: true,
          validation: {
            pattern: '^ORD-[0-9]{6,}$',
            example: 'ORD-123456'
          }
        },
        {
          name: 'reason',
          type: 'string',
          description: 'Reason for cancellation',
          required: true,
          enum: [
            'customer_request',
            'out_of_stock',
            'pricing_error',
            'duplicate_order',
            'other'
          ]
        },
        {
          name: 'refund_amount',
          type: 'number',
          description: 'Amount to refund (if different from order total)',
          required: false
        }
      ],
      authentication: {
        type: 'bearer',
        token_env_var: 'STORE_API_TOKEN'
      },
      headers: {
        'Content-Type': 'application/json',
        'X-API-Version': '2024-01'
      },
      request_transform: {
        body: {
          order_id: '{{order_id}}',
          cancellation_reason: '{{reason}}',
          refund: {
            amount: '{{refund_amount || order_total}}',
            method: 'original_payment_method'
          },
          notify_customer: true
        }
      },
      response_handling: {
        success_condition: 'status_code == 200',
        error_message_path: 'error.message',
        result_mapping: {
          success: 'data.cancelled',
          order_status: 'data.status',
          refund_id: 'data.refund.id',
          estimated_refund_date: 'data.refund.estimated_date'
        }
      },
      retry_config: {
        max_attempts: 3,
        backoff: 'exponential',
        retry_on: [502, 503, 504]
      },
      timeout: 30000, // 30 seconds
      rate_limit: {
        requests_per_minute: 60
      }
    });

    console.log('Order cancellation function created:', cancelOrderFunction.id);
    return cancelOrderFunction;
  } catch (error) {
    console.error('Failed to create function:', error);
    throw error;
  }
}

Advanced Example: Multi-Step Function

Some operations require multiple API calls. Here’s a function that handles complex return processing:

async function createReturnProcessingFunction(agentId) {
  const returnFunction = await client.functions.create({
    agent_id: agentId,
    name: 'process_return',
    description: 'Processes a product return including validation, label generation, and refund initiation',
    type: 'workflow', // Indicates multi-step function
    steps: [
      {
        name: 'validate_order',
        endpoint: 'https://api.yourstore.com/v1/orders/{order_id}',
        method: 'GET',
        output: 'order_data'
      },
      {
        name: 'check_return_eligibility',
        endpoint: 'https://api.yourstore.com/v1/returns/check-eligibility',
        method: 'POST',
        condition: 'order_data.status == "delivered"',
        body: {
          order_id: '{{order_id}}',
          items: '{{return_items}}',
          order_date: '{{order_data.created_at}}'
        },
        output: 'eligibility'
      },
      {
        name: 'create_return_label',
        endpoint: 'https://api.shipping.com/v2/labels',
        method: 'POST',
        condition: 'eligibility.eligible == true',
        body: {
          from_address: '{{order_data.shipping_address}}',
          to_address: '{{warehouse_address}}',
          weight: '{{calculated_weight}}',
          service: 'ground'
        },
        output: 'shipping_label'
      },
      {
        name: 'create_return_record',
        endpoint: 'https://api.yourstore.com/v1/returns',
        method: 'POST',
        body: {
          order_id: '{{order_id}}',
          items: '{{return_items}}',
          reason: '{{return_reason}}',
          shipping_label: '{{shipping_label.tracking_number}}',
          expected_refund: '{{eligibility.refund_amount}}'
        },
        output: 'return_record'
      }
    ],
    final_response: {
      success: '{{return_record.id != null}}',
      return_id: '{{return_record.id}}',
      tracking_number: '{{shipping_label.tracking_number}}',
      label_url: '{{shipping_label.url}}',
      estimated_refund: '{{eligibility.refund_amount}}',
      instructions: 'Please print the label and drop off the package at any {{shipping_label.carrier}} location.'
    }
  });
  
  return returnFunction;
}

Function Parameters

Parameter Types and Validation

StateSet supports comprehensive parameter validation:

const advancedFunction = await client.functions.create({
  agent_id: agentId,
  name: 'update_subscription',
  parameters: [
    {
      name: 'customer_email',
      type: 'string',
      required: true,
      validation: {
        format: 'email',
        example: 'customer@example.com'
      }
    },
    {
      name: 'subscription_plan',
      type: 'string',
      required: true,
      enum: ['starter', 'pro', 'enterprise'],
      description: 'The plan to switch to'
    },
    {
      name: 'billing_period',
      type: 'string',
      required: false,
      default: 'monthly',
      enum: ['monthly', 'yearly']
    },
    {
      name: 'apply_credit',
      type: 'number',
      required: false,
      validation: {
        min: 0,
        max: 1000,
        precision: 2
      }
    },
    {
      name: 'effective_date',
      type: 'date',
      required: false,
      validation: {
        format: 'YYYY-MM-DD',
        min: 'today',
        max: 'today+90d'
      }
    },
    {
      name: 'addons',
      type: 'array',
      required: false,
      items: {
        type: 'string',
        enum: ['extra_users', 'priority_support', 'api_access']
      }
    }
  ]
});

Dynamic Parameter Extraction

Configure how your agent extracts parameters from conversations:

const smartFunction = await client.functions.create({
  agent_id: agentId,
  name: 'smart_order_lookup',
  parameters: [
    {
      name: 'identifier',
      type: 'string',
      required: true,
      extraction_hints: [
        'order number',
        'order ID', 
        'confirmation number',
        'reference number'
      ],
      extraction_patterns: [
        'ORD-[0-9]{6,}',
        '#[0-9]{8}',
        '[A-Z]{2}-[0-9]{8}'
      ]
    }
  ],
  parameter_resolution: {
    strategy: 'interactive', // or 'automatic'
    missing_parameter_prompt: 'I need your order number to look that up. It usually starts with ORD- or # followed by numbers.',
    confirmation_required: true,
    confirmation_prompt: 'I found order {{identifier}}. Is this the one you\'re asking about?'
  }
});

Authentication Methods

API Key Authentication

const apiKeyFunction = await client.functions.create({
  agent_id: agentId,
  name: 'inventory_check',
  endpoint: 'https://api.inventory.com/v1/products/{sku}/availability',
  authentication: {
    type: 'api_key',
    key_env_var: 'INVENTORY_API_KEY',
    header_name: 'X-API-Key'
  }
});

OAuth 2.0 Authentication

const oauthFunction = await client.functions.create({
  agent_id: agentId,
  name: 'calendar_booking',
  endpoint: 'https://api.calendar.com/v2/events',
  authentication: {
    type: 'oauth2',
    client_id_env_var: 'CALENDAR_CLIENT_ID',
    client_secret_env_var: 'CALENDAR_CLIENT_SECRET',
    token_url: 'https://api.calendar.com/oauth/token',
    scope: 'events.write',
    refresh_token_env_var: 'CALENDAR_REFRESH_TOKEN'
  }
});

Custom Authentication

const customAuthFunction = await client.functions.create({
  agent_id: agentId,
  name: 'legacy_system_query',
  endpoint: 'https://legacy.company.com/api/query',
  authentication: {
    type: 'custom',
    headers: {
      'X-Company-ID': '{{COMPANY_ID}}',
      'X-Timestamp': '{{CURRENT_TIMESTAMP}}',
      'X-Signature': '{{HMAC_SHA256(COMPANY_SECRET, COMPANY_ID + CURRENT_TIMESTAMP)}}'
    }
  }
});

Error Handling

Comprehensive Error Configuration

const robustFunction = await client.functions.create({
  agent_id: agentId,
  name: 'payment_processing',
  endpoint: 'https://api.payments.com/v1/charge',
  error_handling: {
    strategies: {
      'insufficient_funds': {
        retry: false,
        message: 'The payment was declined due to insufficient funds. Would you like to try a different payment method?',
        suggest_actions: ['use_different_card', 'split_payment']
      },
      'card_expired': {
        retry: false,
        message: 'This card has expired. Please provide a valid payment method.',
        suggest_actions: ['update_card']
      },
      'network_error': {
        retry: true,
        max_retries: 3,
        message: 'I\'m having trouble processing your payment right now. Let me try again...'
      },
      'rate_limit': {
        retry: true,
        backoff: 'exponential',
        message: 'Our payment system is busy. I\'ll try again in a moment.'
      }
    },
    default_strategy: {
      retry: true,
      max_retries: 2,
      message: 'I encountered an issue processing your request. Let me try once more.'
    },
    fallback_action: 'escalate_to_human'
  }
});

Error Recovery Workflows

const recoveryFunction = await client.functions.create({
  agent_id: agentId,
  name: 'order_with_recovery',
  endpoint: 'https://api.store.com/v1/orders',
  error_recovery: {
    on_timeout: {
      action: 'check_status',
      endpoint: 'https://api.store.com/v1/orders/status/{request_id}',
      message: 'This is taking longer than expected. Let me check the status...'
    },
    on_partial_success: {
      action: 'complete_remaining',
      message: 'I\'ve partially processed your order. Working on the remaining items...'
    },
    on_failure: {
      actions: [
        {
          condition: 'status_code == 500',
          action: 'create_support_ticket',
          message: 'I\'ve encountered a system issue and created a support ticket for you.'
        },
        {
          condition: 'status_code == 400',
          action: 'request_clarification',
          message: 'I need to clarify some information to complete your request.'
        }
      ]
    }
  }
});

Testing Functions

Test Mode Configuration

const testableFunction = await client.functions.create({
  agent_id: agentId,
  name: 'refund_processor',
  endpoint: 'https://api.payments.com/v1/refunds',
  test_mode: {
    enabled: true,
    test_endpoint: 'https://sandbox.payments.com/v1/refunds',
    test_credentials_env_var: 'PAYMENTS_SANDBOX_KEY',
    test_scenarios: [
      {
        name: 'successful_refund',
        input: { amount: 100, order_id: 'TEST-001' },
        expected_output: { success: true, refund_id: 'REF-TEST-001' }
      },
      {
        name: 'partial_refund',
        input: { amount: 50, order_id: 'TEST-002' },
        expected_output: { success: true, refund_id: 'REF-TEST-002', type: 'partial' }
      },
      {
        name: 'failed_refund',
        input: { amount: 100, order_id: 'TEST-FAIL' },
        expected_output: { success: false, error: 'insufficient_funds' }
      }
    ]
  }
});

// Run tests
const testResults = await client.functions.test(testableFunction.id);
console.log('Test results:', testResults);

Monitoring & Analytics

Function Performance Tracking

// Get function analytics
const analytics = await client.functions.getAnalytics(functionId, {
  timeframe: '7d',
  metrics: ['execution_count', 'success_rate', 'avg_duration', 'error_breakdown']
});

console.log(`Function performance:
  - Executions: ${analytics.execution_count}
  - Success Rate: ${analytics.success_rate}%
  - Avg Duration: ${analytics.avg_duration}ms
  - Most Common Error: ${analytics.error_breakdown[0]?.type}
`);

// Set up alerts
await client.functions.createAlert({
  function_id: functionId,
  conditions: [
    {
      metric: 'success_rate',
      operator: 'less_than',
      threshold: 95,
      window: '5m'
    },
    {
      metric: 'avg_duration',
      operator: 'greater_than',
      threshold: 5000, // 5 seconds
      window: '15m'
    }
  ],
  notification_channels: ['email', 'slack']
});

Best Practices

1. Design for Conversation

// Good: Natural parameter extraction
const goodFunction = await client.functions.create({
  name: 'track_package',
  description: 'Tracks a package using various identifier types',
  parameters: [{
    name: 'tracking_info',
    extraction_hints: [
      'tracking number',
      'order number',
      'reference code'
    ]
  }]
});

// Bad: Rigid parameter requirements
const badFunction = await client.functions.create({
  name: 'track_package',
  description: 'Enter the 18-digit UPS tracking number',
  parameters: [{
    name: 'ups_tracking_number',
    validation: { pattern: '^1Z[0-9]{16}$' }
  }]
});

2. Implement Graceful Degradation

const resilientFunction = await client.functions.create({
  name: 'product_recommendations',
  endpoint: 'https://api.recommendations.com/v1/suggest',
  fallback_behavior: {
    on_error: 'use_static_recommendations',
    static_response: {
      recommendations: [
        { id: 'BESTSELLER-001', name: 'Our Most Popular Item' },
        { id: 'BESTSELLER-002', name: 'Customer Favorite' }
      ],
      message: 'Here are some of our popular items you might like:'
    }
  }
});

3. Security First

const secureFunction = await client.functions.create({
  name: 'user_data_update',
  endpoint: 'https://api.secure.com/v1/users/{user_id}',
  security: {
    require_authentication: true,
    allowed_roles: ['admin', 'user_self'],
    rate_limit: {
      per_user: 10,
      window: '1h'
    },
    input_sanitization: true,
    pii_handling: {
      mask_in_logs: ['ssn', 'credit_card'],
      encrypt_in_transit: true
    }
  }
});

Advanced Patterns

Conditional Execution

const conditionalFunction = await client.functions.create({
  name: 'smart_discount_application',
  execution_conditions: [
    {
      condition: 'customer.lifetime_value > 1000',
      endpoint: 'https://api.store.com/v1/vip-discount'
    },
    {
      condition: 'cart.total > 100 && customer.first_purchase',
      endpoint: 'https://api.store.com/v1/welcome-discount'
    },
    {
      condition: 'cart.abandoned_duration > 3600',
      endpoint: 'https://api.store.com/v1/recovery-discount'
    }
  ],
  default_endpoint: 'https://api.store.com/v1/standard-pricing'
});

Function Chaining

// Define a chain of functions
await client.functions.createChain({
  agent_id: agentId,
  name: 'complete_purchase_flow',
  description: 'Handles the entire purchase process from cart to confirmation',
  steps: [
    {
      function: 'validate_cart',
      on_success: 'apply_discounts',
      on_failure: 'request_cart_update'
    },
    {
      function: 'apply_discounts',
      on_success: 'calculate_shipping',
      pass_output: true
    },
    {
      function: 'calculate_shipping',
      on_success: 'process_payment',
      pass_output: true
    },
    {
      function: 'process_payment',
      on_success: 'create_order',
      on_failure: 'handle_payment_failure'
    },
    {
      function: 'create_order',
      on_success: 'send_confirmation',
      store_result: 'order_details'
    }
  ]
});

Troubleshooting

Common Issues and Solutions

  1. Function Not Executing

    • Verify agent has permission to use the function
    • Check parameter extraction rules
    • Review execution conditions
  2. Authentication Failures

    • Confirm environment variables are set
    • Validate token expiration
    • Check API credential permissions
  3. Timeout Errors

    • Increase timeout configuration
    • Implement async processing for long operations
    • Add status checking endpoints
  4. Parameter Extraction Issues

    • Add more extraction hints
    • Provide parameter examples
    • Enable confirmation prompts

Next Steps


Pro Tip: Start with simple functions and gradually add complexity. Monitor performance metrics to identify optimization opportunities.

For more examples and support, visit our GitHub repository or contact support@stateset.com.