Search

↑↓ to move↵ to openesc to closetop 6 documentation results

Book a demoTry TokenTriage

In development · Explore the product preview. Join the launch list or book a walkthrough.

Browse docs

TypeScript SDK

The complete TypeScript surface — every export, its signature, the two builds, and where each behaviour is documented.

ReferenceLast updated

On this page

The complete public surface of tokentriage for TypeScript, in one place. Behaviour is documented on the topic pages; this is the list of what exists and what each call takes.

import * as tt from "tokentriage";

Requires Node 18 or newer. Local unreleased version 1.0.0-rc.2, contract version 1, zero runtime dependencies, dual ESM and CommonJS.

Two builds, and which one you get

The package ships an edge-safe default build and a Node build, selected by export condition.

Condition Build Async context
node dist/node/ AsyncLocalStorage; scopes propagate
anything else dist/ a no-op carrier; scopes run but do not propagate

On edge runtimes, use the callback’s explicit handle:

await trace({}, async scope => {
  const requestHeaders = scope.headers();
});

The handle supports nested step(), headers() and recordReceipt(). It preserves identity when passed through your application without ambient storage. Existing callbacks accepting no argument remain valid.

Configured provider client

The unreleased TokenTriage from tokentriage/client accepts baseUrl, apiKey and mode. await connection.openai() creates an official OpenAI client; connection.openaiOptions() returns options for your own constructor and fetch. metadata(response) and errorDetails(error) read response-bound information.

openai(), openaiOptions() and native() also take the saved-mode binding: gatewayId (required), environmentId, baseUrl, credentialSource and providerApiKey. Supplying gatewayId selects saved mode, where apiKey is sent as the Authorization bearer and the gateway and environment selector headers are stamped for you. Send the exported gatewayModel as the model. providerApiKey needs credentialSource: "request_supplied"; without it, and for any apiKey passed to a saved-mode call, the SDK throws ConfigurationError naming provider_key_not_allowed before building a request.

See the first request and streaming examples.

Guardrail refusals

A gateway that refuses a request on a guardrail answers 403 for a policy block and 503 for a guard whose detector could not run, with the typed refusal at the top level of the body and x-tt-guardrail: blocked | unavailable on the response. tokentriage/client rewrites that body into the shape the official client can read, so the thrown PermissionDeniedError or InternalServerError already carries the written reason in its message.

guardrailRefusal(error: unknown): GuardrailRefusal | null

Reads the typed fields back off a thrown provider error. null means the failure was not a guardrail refusal (a wrong key, a spent budget, a broken route) and is yours to handle as before.

try {
  await client.chat.completions.create({ model: gatewayModel, messages });
} catch (thrown) {
  const refusal = guardrailRefusal(thrown);
  if (refusal === null) throw thrown;
  console.log(refusal.type, refusal.binding, refusal.category, refusal.phase, refusal.message);
}

GuardrailRefusal fields, every one nullable because the wire makes it optional:

Field What it says
type "guardrail_blocked" or "guardrail_unavailable"; null mid-stream
binding the guardrail binding that acted
category pii, secrets, injection, … when the refusal reached one
phase input, output or stream
ruleRef the policy rule that fired — a block only
reason which detector was suspended — an unavailable refusal only
status 403 or 503; null mid-stream
disclosure the x-tt-guardrail value, when the response carried it
midStream the refusal was read from stream bytes, not from a response
message the written sentence; it names what acted and never the matched content
requestId x-tt-request-id, to quote

ruleRef and reason are never both set, and neither is ever filled in for the other: a block means “do not retry this content”, an unavailable guard means “retry”. isBlocked(refusal) and isUnavailable(refusal) are the two predicates.

streamGuardrailRefusal(data: string | Uint8Array): GuardrailRefusal | null

A refusal that arrives mid-stream is not an error at all: the stream ends with a terminal delta carrying finish_reason: "content_filter" (exported as STREAM_FINISH_REASON) and no explanation, because a refusal that said why would be an oracle for the detector that fired. Pass relayed SSE bytes, or any prefix of them, to read it; a reader that already parses events can compare the finish reason itself. The full disclosure is on the request’s row, never on the wire.

Configuration

init(options?: InitOptions): void

Installs the process configuration. Resolution is argument, then environment, then default. The one call that throws, with TokenTriageConfigError naming the field.

InitOptions carries baseUrl, adminUrl, log, disabled, emitTraceparent, tierHeader, exporters, and the default dimensions agent, user, tenant, feature and tags.

check(options?: CheckOptions): Promise<CheckReport>

The first-run doctor. Admin plane only, not the data plane.

Scopes

trace<T>(options: TraceOptions, fn: (scope: Trace) => T): T and trace<T>(fn: (scope: Trace) => T): T

step<T>(options: StepOptions, fn: (scope: Step) => T): T and step<T>(fn: (scope: Step) => T): T

Callback-scoped; the callback’s return value, including a promise, passes through. There is no decorator form and no observe — those are Python-only conveniences.

currentStep(): Step | null

The innermost open explicit step. currentTrace is not exported.

Trace exposes traceId, headers() and lastReceipt. Step adds stepId, parentId and receipts.

Behaviour: traces, steps, and context.

Wire

headers(overrides?: CallOverrides): Record<string, string>

receipt(source: ReceiptSource, status?: number): Receipt

lastReceipt(): Receipt | null

receipt accepts a Response, a Headers, or a plain record. It never throws, and returns an all-absent receipt rather than null.

Behaviour: from your call to the wire and reading the receipt.

Transport

fetch is a drop-in for globalThis.fetch that injects headers, opens an implicit per-request step, and pairs the receipt.

wrapFetch(base?: FetchFn, options?: WrapFetchOptions): FetchFn builds an origin-scoped wrapper around a fetch you supply. options.origins takes an explicit allowlist instead of deriving one from baseUrl.

bridge() from tokentriage/adapters/otel adopts the active OpenTelemetry span’s ids. The OpenTelemetry API is an optional peer.

Behaviour: adapters.

Ledger

import { ledger } from "tokentriage";

All async. All use the credential-containment protocol and read the token from TOKENTRIAGE_ADMIN_TOKEN only.

ledger.fetch(receiptOrReqId, options?): Promise<RowView> — options { adminUrl?, waitS? }

ledger.fetchTrace(receiptOrTraceId, options?): Promise<TraceView>

ledger.feedback(receiptOrReqId, { ok, note?, adminUrl? }): Promise<FeedbackAck>

ledger.outcomes(receiptOrReqId, options: OutcomeOptions): Promise<OutcomeAck> — options carry metrics, source, evaluator, evalVer, and optionally labels and adminUrl.

Errors: PlaneCollision, AdminAuthRequired, NotFound, LedgerError. feedback is the one call that is not shielded and rejects on failure.

Behaviour: fetching a costed row and outcomes and feedback.

Types and helpers

The whole type surface is exported from the package root: Mode, StepClass, CacheStatus, CacheControl, RefusalType, Cost, Rewrite, CacheInfo, RefusalKind, Refusal, Receipt, ReceiptSource, InitOptions, Dims, TraceOptions, StepOptions, CallOverrides, Trace, Step, WrapFetchOptions, StepRecord, StepStatus, Exporter, CheckFinding, CheckReport and CheckOptions.

renderCost(cost): string produces the pinned money string for any cost state.

version: string is the package version.

Cost is a discriminated union: usd is a decimal string, reachable only after narrowing on state === "priced". Several closed vocabularies are literal unions here that are plain strings in Python; see parity.

Exporter

registerExporter(exporter) and DebugExporter, matching Python:

[tt] step trace=af1ee2db0e477e5b3511fefb3b291231 step=20bdde57899eb179 parent=null agent=null class=null status=error dur_us=1119.5 receipts=0

Testing and management

const { recordingFetch, assertTtHeaders } = tt.testing;
import { Client } from "tokentriage/management";

testing is built in, needing no extra. management is a separate generated client on its own contract version. See testing instrumented code and the management client.

Subpaths and packaging

Three import paths: tokentriage, tokentriage/adapters/otel and tokentriage/management.

The package is dual ESM and CommonJS with types nested per condition, so a CommonJS consumer gets CommonJS declarations rather than ESM declarations served under a CommonJS build. The type shape is identical across conditions; only the runtime differs.

sideEffects lists the Node entry alone, because installing the async-context carrier is an import-time effect a bundler must not remove. The rest of the package is side-effect free and tree-shakeable.