JavaScript
Get started with Spect tracking in your AI application.
Installation
npm install @spect-tools/track
# or
pnpm add @spect-tools/trackPeer Dependencies
# For Vercel AI SDK
npm install ai
# For OpenTelemetry export
npm install @opentelemetry/core @opentelemetry/sdk-trace-base
# For Claude Agent SDK
npm install @anthropic-ai/claude-agent-sdkAPI key
You can get your API key from the Spect settings page.
AI SDK integration
Wrap your language model to enable automatic trace collection:
import { wrap } from '@spect-tools/track/ai-sdk-middleware';
import { openai } from '@ai-sdk/openai';
import { generateText } from 'ai';
const wrappedModel = wrap(openai('gpt-4o'), {
organizationId: 'your-org-id',
apiKey: 'your-spect-api-key',
});
const result = await generateText({
model: wrappedModel,
prompt: 'Hello!',
});Claude Agent SDK integration
Track Claude Agent sessions:
import { query } from '@anthropic-ai/claude-agent-sdk';
import { wrapQuery } from '@spect-tools/track';
const spectQuery = wrapQuery(query, {
organizationId: 'your-org-id',
apiKey: 'your-spect-api-key',
});
const session = spectQuery({
prompt: 'Build a hello world app',
options: {
model: 'claude-sonnet-4-6',
},
});
for await (const message of session) {
console.log(message);
}Customizing Spect
Operation names
Set the trace operation name with providerOptions.spect.name:
await generateText({
model: wrappedModel,
prompt: 'Hello!',
providerOptions: {
spect: {
name: 'my-operation',
},
},
});Spect generates trace IDs automatically so multi-step calls from the same wrapped model stay correlated.
Manual observer API
Use the generic observer when you are building your own SDK adapter. Record transcript items on spans with messages; use the tool overlay for tool-call/tool-result correlation.
import { createObserver } from '@spect-tools/track';
const observer = createObserver({
organizationId: 'your-org-id',
apiKey: 'your-spect-api-key',
});
const session = observer.startSession({
name: 'custom.agent',
model: { modelId: 'my-model', provider: 'custom' },
});
session.startSpan({
name: 'user',
kind: 'user',
status: 'ok',
messages: [{ id: crypto.randomUUID(), role: 'user', content: 'Find acute asthma protocols.' }],
});
session.startSpan({
name: 'evidence_search',
kind: 'tool-call',
status: 'ok',
tool: {
toolCallId: 'call_1',
toolName: 'evidence_search',
parameters: { query: 'acute asthma protocols' },
},
messages: [
{
id: crypto.randomUUID(),
role: 'assistant',
content: [
{
type: 'tool-call',
toolCallId: 'call_1',
toolName: 'evidence_search',
input: { query: 'acute asthma protocols' },
},
],
},
],
});
session.startSpan({
name: 'evidence_search.result',
kind: 'tool-result',
status: 'ok',
tool: {
toolCallId: 'call_1',
toolName: 'evidence_search',
result: { matches: 3 },
},
messages: [
{
id: crypto.randomUUID(),
role: 'tool',
content: [
{
type: 'tool-result',
toolCallId: 'call_1',
toolName: 'evidence_search',
output: { type: 'json', value: { matches: 3 } },
},
],
},
],
});
await session.send();Configuration Options
These top-level options are accepted by wrap(), wrapQuery(), and createObserver().
| Option | Type | Required | Description |
|---|---|---|---|
organizationId | string | Yes | Your organization identifier |
apiKey | string | Yes, unless local: true | Spect API key |
All other options have sensible defaults and are typically not needed:
| Option | Type | Default | Description |
|---|---|---|---|
collectorUrl | string | https://collect.spect.tools | Collector endpoint |
provider | string | auto-detected | Fallback provider name when the wrapped model or session model does not supply one |
operationName | string | — | Override trace name for all calls; takes precedence over per-call name. Falls back to generate / stream / custom when unset |
local | boolean | false | Local-only mode — skip sending to collector |
conversationId | string | — | Stable ID that groups a conversation's traces into one session |
sampling | SamplingOptions | — | Sticky rate sampling, promotion rules, and rule-based overrides |
onTrace | (payload) => void | — | Callback when a trace is collected |
sendFailuresToConsole | boolean | true | Log collector send failures |
headers | HeadersInit | — | Additional collector request headers |
fetchImpl | typeof fetch | globalThis.fetch | Custom fetch implementation |
AI SDK calls also accept per-call providerOptions.spect values:
| Option | Type | Description |
|---|---|---|
name | string | Operation name for that call; ignored when top-level operationName is set |
conversationId | string | Groups this call's trace into a session; overrides the top-level value |
metadata | Record<string, unknown> | Metadata attached to the trace request |
sampling | SamplingOptions | Per-call sampling override |