TypeScript and JavaScript SDK

Updated on Jun 16, 2026

Package: @progress/observability

Overview

The TypeScript/JavaScript SDK instruments AI agents and LLM applications running on Node.js. It supports both ESM and CommonJS module systems.

Use this SDK when your agent is built with TypeScript or JavaScript and uses frameworks like LangChain.js, Vercel AI SDK, OpenAI Node, Anthropic, or any of the other supported providers.

Core capabilities:

  • Automatic instrumentation of LLM providers and agent frameworks
  • Manual instrumentation with @task, @workflow, @agent, @tool decorators and wrapFunctionWithSpan()
  • Tag propagation with propagateAttributes()
  • ESM loader hooks for transparent module patching
  • Content tracing control

Installation

bash
npm install @progress/observability

Initialization

Initialization depends on your module system.

Create a separate bootstrap file that initializes instrumentation before your app loads:

typescript
// bootstrap.ts — ESM instrumentation bootstrap
import '@progress/observability/register/hooks';
import dotenv from 'dotenv';
dotenv.config();

import { Observability } from '@progress/observability';

await Observability.instrument({
    appName: 'my-ai-agent',
    apiKey: process.env.OBSERVABILITY_API_KEY
});

// Load your main app after instrumentation is ready
await import('./src/app.ts');

Run with: tsx bootstrap.ts

ESM / TypeScript — Inline (No Bootstrap File)

Initialize with dynamic imports at the top of your main entry point:

typescript
// src/app.ts — ESM without bootstrap file
import '@progress/observability/register/hooks';
const { Observability } = await import('@progress/observability');
import dotenv from 'dotenv';
dotenv.config();

await Observability.instrument({
    appName: 'my-ai-agent',
    apiKey: process.env.OBSERVABILITY_API_KEY
});

// Your application code here

CommonJS / Synchronous CommonJS

typescript
// CommonJS / Synchronous initialization
import { Observability } from '@progress/observability';
import dotenv from 'dotenv';
dotenv.config();

await Observability.instrument({
    appName: 'my-ai-agent',
    apiKey: process.env.OBSERVABILITY_API_KEY,
    debug: true
});

// Your application code here

When using ESM with LangChain, use dynamic imports for LangChain modules after calling instrument().

Configuration

Full configuration example with all options:

typescript
import { Observability, ObservabilityInstruments } from '@progress/observability';

await Observability.instrument({
    appName: 'my-ai-agent',
    apiKey: process.env.OBSERVABILITY_API_KEY,
    endpoint: 'https://collector.observability.progress.com:443',  // default
    debug: false,
    traceContent: true,           // set false to exclude prompts/responses
    disableBatch: true,           // send traces immediately (default)
    instruments: new Set([        // only enable specific instruments
        ObservabilityInstruments.OPENAI,
        ObservabilityInstruments.LANGCHAIN
    ]),
    additionalTags: ['production', 'release:2.4.1']
});

Parameters

ParameterRequiredDefaultDescription
appNameNoprocess.argv[1]Application name shown in platform
apiKeyYes*undefinedYour API key (* or set env var)
endpointNohttps://collector.observability.progress.com:443Collector endpoint URL
debugNofalseEnable debug logging
traceContentNotrueInclude prompts and completions in traces
disableBatchNotrueSend traces immediately (no batching)
instrumentsNoundefined (all)Set of instruments to enable
blockInstrumentsNoundefinedSet of instruments to disable
additionalTagsNoundefinedGlobal tags applied to all spans
resourceAttributesNoundefinedCustom resource attributes
headersNoundefinedCustom headers for exporter

Environment Variables

bash
# Set these environment variables instead of passing them to instrument()
export OBSERVABILITY_APP_NAME="my-ai-agent"
export OBSERVABILITY_API_KEY="<your-api-key>"
export OBSERVABILITY_ENDPOINT="https://collector.observability.progress.com:443"
export OBSERVABILITY_TRACE_CONTENT="true"
VariableOverrides
OBSERVABILITY_APP_NAMEappName
OBSERVABILITY_API_KEYapiKey
OBSERVABILITY_ENDPOINTendpoint
OBSERVABILITY_TRACE_CONTENTtraceContent (true or false)

Decorators

The TypeScript SDK provides the same four decorators as the Python SDK. In TypeScript, decorators are applied to class methods:

DecoratorSpan KindUse For
@tasktaskA discrete unit of work
@workflowworkflowA multi-step orchestration
@agentagentAn AI agent entry point
@tooltoolA tool or function the agent can invoke

Examples

@agent

typescript
import { agent } from '@progress/observability';

class SupportAgent {
    @agent({ name: 'support-agent' })
    async handleRequest(message: string) {
        // Agent logic with LLM calls, tool usage, and so on
        return response;
    }
}

@workflow

typescript
import { workflow } from '@progress/observability';

class OnboardingService {
    @workflow({ name: 'onboarding-flow', version: 2 })
    async onboardCustomer(customerId: string) {
        await this.verifyIdentity(customerId);
        await this.createAccount(customerId);
        await this.sendWelcomeEmail(customerId);
    }
}

@tool

typescript
import { tool } from '@progress/observability';

class SearchTools {
    @tool({ name: 'web-search' })
    async searchWeb(query: string): Promise<string> {
        // Tool implementation
        return results;
    }
}

Wrapping Standalone Functions

For functions that are not class methods, use wrapFunctionWithSpan():

typescript
import { wrapFunctionWithSpan, ObservabilitySpanKind } from '@progress/observability';

// Wrap a standalone function (not a class method)
const instrumentedFetch = wrapFunctionWithSpan(
    fetchData,
    'fetch-data',
    { spanKind: ObservabilitySpanKind.TOOL, tags: ['api-call'] }
);

// Call the wrapped function — a span is created automatically
const result = await instrumentedFetch(url);

Tags

Tags work the same way as in the Python SDK. Three levels:

1. Global Tags

typescript
await Observability.instrument({
    appName: 'my-ai-agent',
    apiKey: process.env.OBSERVABILITY_API_KEY,
    additionalTags: ['production', 'release:2.4.1']
});

2. Scoped Tags

typescript
import { propagateAttributes } from '@progress/observability';

propagateAttributes(['tenant:acme', 'experiment-v2'], () => {
    // All spans created here inherit these tags
    myAgentFunction();
});

// Nesting is supported — tags accumulate
propagateAttributes(['outer-tag'], () => {
    propagateAttributes(['inner-tag'], () => {
        doWork(); // span gets both "outer-tag" and "inner-tag"
    });
});

3. Decorator Tags

typescript
import { task } from '@progress/observability';

class MyService {
    @task({ tags: ['cohort-a'] })
    async myTask() {
        // ...
    }
}

Supported Instruments

Currently Instrumented

CategoryInstruments
LLM ProvidersOPENAI, ANTHROPIC, COHERE, BEDROCK, AZURE_OPENAI
Agent FrameworksLANGCHAIN, LLAMA_INDEX
Vector DatabasesPINECONE, CHROMA

Controlling Instruments

typescript
import { Observability, ObservabilityInstruments } from '@progress/observability';

// Enable everything except Redis
await Observability.instrument({
    appName: 'my-ai-agent',
    apiKey: process.env.OBSERVABILITY_API_KEY,
    blockInstruments: new Set([ObservabilityInstruments.REDIS])
});

Shutdown

Call shutdown() before your process exits to flush any pending telemetry:

typescript
// Call shutdown before your process exits
try {
    await runAgent();
} finally {
    await Observability.shutdown();
}

Observability.shutdown() accepts an optional timeoutMs parameter. The default is 30000.

See Also