BrowserStack AI Evals
PlatformEvaluationTools

Decorators & Annotations

Instrument TypeScript functions with OpenTelemetry spans using tool, agent, task, and workflow decorators.

Decorators & Annotations

Decorators are a TypeScript-only feature. They are not available in the Python or Java SDKs.

Decorators instrument functions with OpenTelemetry spans, automatically capturing inputs, outputs, and errors. Four span types are supported — tool, agent, task, and workflow — each with a function wrapper variant and a method decorator variant.

import { withTool, withAgent, withTask, withWorkflow } from '@browserstack/ai-sdk';
// or method decorator variants:
import { tool, agent, task, workflow } from '@browserstack/ai-sdk';
DecoratorSpan Kindgen_ai.operation.name
@tool / withTooltoolexecute_tool
@agent / withAgentagentinvoke_agent
@task / withTasktasktask_call
@workflow / withWorkflowworkflowworkflow_call

All decorators capture function arguments as span input, capture return value as span output, and record exceptions on error.

withTool — Function Wrapper

import { withTool } from '@browserstack/ai-sdk';

async function searchWeb(query: string): Promise<string[]> {
  return ['result1', 'result2'];
}

const tracedSearch = withTool({ name: 'search_web' }, searchWeb);

const results = await tracedSearch('AI news today');
// Creates a span with gen_ai.operation.name=execute_tool

@tool — Method Decorator

import { tool } from '@browserstack/ai-sdk';

class SearchService {
  @tool({ name: 'search_web' })
  async search(query: string): Promise<string[]> {
    return ['result1', 'result2'];
  }
}

const service = new SearchService();
await service.search('latest news'); // automatically traced

withAgent, withTask, withWorkflow

import { withAgent, withTask, withWorkflow } from '@browserstack/ai-sdk';

const tracedAgent = withAgent({ name: 'research-agent' }, async (task: string) => {
  return 'Agent result';
});

const tracedTask = withTask({ name: 'document-processing' }, async (doc: string) => {
  return 'processed';
});

const tracedPipeline = withWorkflow({ name: 'rag-pipeline' }, async (input: string) => {
  return 'pipeline output';
});

Complete Agent Example

import '@browserstack/ai-sdk/instrument';
import { AISDK, withAgent, withTool } from '@browserstack/ai-sdk';
import OpenAI from 'openai';

const testOps = new AISDK({
  publicKey: process.env.AISDK_PUBLIC_KEY,
  secretKey: process.env.AISDK_SECRET_KEY,
});
const openai = new OpenAI();

const searchWeb = withTool({ name: 'search_web' }, async (query: string) => {
  return [`Result for: ${query}`];
});

const researchAgent = withAgent(
  { name: 'research-agent' },
  async (userRequest: string): Promise<string> => {
    const response = await openai.chat.completions.create({
      model: 'gpt-4o',
      messages: [{ role: 'user', content: userRequest }],
      tools: [
        {
          type: 'function',
          function: {
            name: 'search_web',
            description: 'Search the web',
            parameters: {
              type: 'object',
              properties: { query: { type: 'string' } },
              required: ['query'],
            },
          },
        },
      ],
      tool_choice: 'auto',
    });

    const choice = response.choices[0];
    if (choice.finish_reason === 'tool_calls') {
      for (const toolCall of choice.message.tool_calls ?? []) {
        if (toolCall.function.name === 'search_web') {
          const args = JSON.parse(toolCall.function.arguments);
          const results = await searchWeb(args.query);
          return results.join('\n');
        }
      }
    }

    return choice.message.content ?? '';
  }
);

const result = await researchAgent('Find the latest news about AI safety.');
console.log(result);
await testOps.shutdown();