Xpander is a powerful platform for building and deploying AI agents with sophisticated workflow management capabilities. AgentOps provides seamless integration with the Xpander SDK, automatically instrumenting all agent activities, tool executions, and LLM interactions without any manual setup.

Installation

Install AgentOps and the Xpander SDK, along with the required dependencies:
pip install agentops xpander-sdk xpander-utils openai python-dotenv loguru

Setting Up API Keys

Youโ€™ll need API keys for AgentOps, Xpander, and OpenAI: Set these as environment variables or in a .env file:
export AGENTOPS_API_KEY="your_agentops_api_key_here"
export XPANDER_API_KEY="your_xpander_api_key_here"
export XPANDER_AGENT_ID="your_xpander_agent_id_here"
export OPENAI_API_KEY="your_openai_api_key_here"
You can also store your configuration in a xpander_config.json file:
{
  "api_key": "your_xpander_api_key_here",
  "agent_id": "your_xpander_agent_id_here"
}

Quick Start

The key to AgentOps + Xpander integration is initialization order: Initialize AgentOps before importing the Xpander SDK to enable automatic instrumentation.
The following example shows the callback-based integration pattern. For a complete working example, see our Xpander example.
# ruff: noqa: E402
import os
import json
import asyncio
from pathlib import Path
from dotenv import load_dotenv

# Load environment variables first
load_dotenv()

# 1. Initialize AgentOps FIRST (this enables auto-instrumentation)
import agentops
agentops.init(
    api_key=os.getenv("AGENTOPS_API_KEY"),
    trace_name="my-xpander-coding-agent-callbacks",
    default_tags=["xpander", "coding-agent", "callbacks"],
)

# 2. Now import Xpander SDK (instrumentation will automatically activate)
from xpander_sdk import XpanderClient, LLMProvider, LLMTokens, Tokens, Agent, ExecutionStatus
from xpander_utils.events import XpanderEventListener, AgentExecutionResult, AgentExecution
from openai import AsyncOpenAI

class MyAgent:
    def __init__(self):
        # Load config
        config_path = Path(__file__).parent / "xpander_config.json"
        config = json.loads(config_path.read_text())
        
        # Get API keys
        xpander_key = config.get("api_key") or os.getenv("XPANDER_API_KEY")
        agent_id = config.get("agent_id") or os.getenv("XPANDER_AGENT_ID")
        openai_key = os.getenv("OPENAI_API_KEY")
        
        # Initialize clients
        self.openai = AsyncOpenAI(api_key=openai_key)
        xpander_client = XpanderClient(api_key=xpander_key)
        self.agent_backend: Agent = xpander_client.agents.get(agent_id=agent_id)
        self.agent_backend.select_llm_provider(LLMProvider.OPEN_AI)

    async def run(self, user_input: str) -> dict:
        tokens = Tokens(worker=LLMTokens(0, 0, 0))
        
        while not self.agent_backend.is_finished():
            # Call LLM
            response = await self.openai.chat.completions.create(
                model="gpt-4",
                messages=self.agent_backend.messages,
                tools=self.agent_backend.get_tools(),
                tool_choice=self.agent_backend.tool_choice,
                temperature=0,
            )
            
            # Track tokens
            if hasattr(response, "usage"):
                tokens.worker.prompt_tokens += response.usage.prompt_tokens
                tokens.worker.completion_tokens += response.usage.completion_tokens
                tokens.worker.total_tokens += response.usage.total_tokens
            
            # Add response to agent context
            self.agent_backend.add_messages(response.model_dump())
            self.agent_backend.report_execution_metrics(llm_tokens=tokens, ai_model="gpt-4")
            
            # Execute any tool calls
            tool_calls = self.agent_backend.extract_tool_calls(response.model_dump())
            if tool_calls:
                tool_results = await asyncio.to_thread(self.agent_backend.run_tools, tool_calls)
        
        result = self.agent_backend.retrieve_execution_result()
        return {"result": result.result, "thread_id": result.memory_thread_id}

# Set up event listener with callback handlers
listener = XpanderEventListener(
    api_key=os.getenv("XPANDER_API_KEY"),
    agent_id=os.getenv("XPANDER_AGENT_ID")
)

async def on_execution_request(execution_task: AgentExecution) -> AgentExecutionResult:
    agent = MyAgent()
    agent.agent_backend.init_task(execution=execution_task.model_dump())
    
    try:
        await agent.run(execution_task.input.text)
        execution_result = agent.agent_backend.retrieve_execution_result()
        return AgentExecutionResult(
            result=execution_result.result,
            is_success=execution_result.status == ExecutionStatus.COMPLETED,
        )
    except Exception as e:
        print(f"Error: {e}")
        raise

# Register the callback
listener.register(on_execution_request=on_execution_request)

Whatโ€™s Automatically Tracked

AgentOps automatically captures comprehensive telemetry from your Xpander agents:

๐Ÿค– Agent Activities

  • Agent initialization and configuration
  • Task lifecycle (start, execution steps, completion)
  • Workflow phase transitions (planning โ†’ executing โ†’ finished)
  • Session management and context persistence

๐Ÿง  LLM Interactions

  • All OpenAI API calls with full request/response data
  • Token usage and cost tracking across models
  • Conversation history and context management
  • Model parameters and settings

๐Ÿ› ๏ธ Tool Executions

  • Tool call detection with parameters and arguments
  • Tool execution results and success/failure status
  • Tool performance metrics and timing
  • Tool call hierarchies and dependencies

๐Ÿ“Š Performance Metrics

  • End-to-end execution duration and timing
  • Step-by-step workflow progression
  • Resource utilization and efficiency metrics
  • Error handling and exception tracking

Key Features

โœ… Zero-Configuration Setup

No manual trace creation or span management required. Simply initialize AgentOps before importing Xpander SDK.

โœ… Complete Workflow Visibility

Track the entire agent execution flow from task initiation to completion, including all intermediate steps.

โœ… Real-time Monitoring

View your agent activities in real-time on the AgentOps dashboard as they execute.

โœ… Tool Execution Insights

Monitor which tools are being called, their parameters, execution time, and results.

โœ… Cost Tracking

Automatic token usage tracking for all LLM interactions with cost analysis.

Callback Handler Pattern

The Xpander integration supports two main patterns:
  1. Direct Integration: Directly instrument your agent code (shown above)
  2. Callback Handler: Use XpanderEventListener for webhook-style integration
The callback handler pattern is particularly useful for:
  • Production deployments with centralized monitoring
  • Multi-agent orchestration systems
  • Event-driven architectures

Runtime-Specific Instrumentation

Xpander SDK uses JSII to create methods at runtime, which requires specialized instrumentation. AgentOps handles this automatically by:
  • Method Wrapping: Dynamically wrapping agent methods as theyโ€™re created
  • Context Persistence: Maintaining session context across runtime object lifecycle
  • Agent Detection: Automatically detecting and instrumenting new agent instances
  • Tool Result Extraction: Properly extracting results from JSII object references

Troubleshooting

Import Order Issues

If youโ€™re not seeing traces, ensure AgentOps is initialized before importing Xpander SDK:
# โœ… Correct order
import agentops
agentops.init()
from xpander_sdk import XpanderClient

# โŒ Incorrect order
from xpander_sdk import XpanderClient
import agentops
agentops.init()  # Too late - instrumentation won't activate

Missing Tool Results

If tool results show {"__jsii_ref__": "..."} instead of actual content, ensure youโ€™re using the latest version of AgentOps, which includes improved JSII object handling.

Import Errors (E402)

If you see linting errors about imports not being at the top of the file, this is expected for Xpander integration. Add # ruff: noqa: E402 at the top of your file to suppress these warnings, as the import order is required for proper instrumentation.

Examples