Skip to content

TypeScript

Install

pnpm add openai
import OpenAI from 'openai'
import { withRunForge } from '../sdk-ts/index'

const openai = withRunForge(new OpenAI({ apiKey: process.env.OPENAI_API_KEY }), {
  projectId: process.env.RUNFORGE_PROJECT_ID, // optional if set in env
})

const res = await openai.chat.completions.create({
  model: 'gpt-4o-mini',
  messages: [{ role: 'user', content: 'Hello!' }]
})

Explicit tracker API

class RunForge {
  constructor(opts: { apiKey: string; endpoint?: string; projectId?: string })
  track<T>(metadataOrFn: Record<string, any> | (() => Promise<T>), maybeFn?: () => Promise<T>): Promise<T>
}
- Wrap any async LLM call: await rf.track({ model, experiment? }, () => client.call(...)). - Auto‑extracts tokens and cost from provider response: - OpenRouter: uses usage.total_cost → exact cost (costSource="provider"). - OpenAI/Anthropic: reads usage tokens; client may estimate via tokencost; server verifies and computes authoritative cost (costSource="catalog"). - Sends only usage metadata to /api/ingest. Do not send prompts/outputs.

Example (explicit tracker)

import OpenAI from 'openai'
import { RunForge, withRunForge } from '../sdk-ts/index'

const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY! })
const rf = new RunForge({ apiKey: process.env.RUNFORGE_API_KEY!, endpoint: process.env.RUNFORGE_ENDPOINT, projectId: process.env.RUNFORGE_PROJECT_ID })

await rf.track({ model: 'gpt-4o-mini', experiment: 'chat-v2' }, () =>
  openai.chat.completions.create({ model: 'gpt-4o-mini', messages: [{ role: 'user', content: 'hi' }] })
)

Streaming

  • For OpenAI, prefer stream_options: { include_usage: true } to receive final usage in the last chunk.
  • If you accumulate streamed text, compute output tokens at the end with countStreamingOutputTokens(model, fullText) and POST once.

Options & metadata

  • metadata object is forwarded as metadata to ingestion; you may include experiment, traceId, or custom fields.
  • Set traceId yourself in metadata to propagate an OTel trace ID (optional).
  • Client marks costSource: 'estimated' and costEstimated: true; server sets authoritative values.

Error & retries

  • If the wrapped call throws, RunForge still emits telemetry with status: 'error' and the error code.
  • Use runId to de‑dupe retries (ingest is idempotent by runId).

Privacy

  • Do not send prompts/outputs; the SDK and route are designed to handle usage metadata only.

See also: 05-apis.md, sdk-auto-extraction-guide.md