Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.output.ai/llms.txt

Use this file to discover all available pages before exploring further.

This guide covers the @outputai/http and @outputai/llm cost tracking changes in v0.5.0.

What changed

  • addRequestCost now accepts a numeric total instead of a RequestCost object.
  • The RequestCost type is removed.
  • The cost:http:request event now receives an HTTP request cost attribute instead of { requestId, url, cost }.
  • LLM response .cost is now an LLM usage attribute instead of { total, components }.
  • LLM usage entries only include available, finite dimensions; missing dimensions are omitted.
  • Missing LLM costs are returned as null, not as cost objects with total: null and message.
  • The cost:llm:request event now receives the LLM usage attribute instead of { modelId, cost, usage }.

Migration steps

Update addRequestCost

Pass the total request cost directly.

Before

import { addRequestCost } from '@outputai/http';

addRequestCost( response, {
  total: inputCost + outputCost,
  components: [
    { name: 'input', value: inputCost },
    { name: 'output', value: outputCost }
  ]
} );

After

import { addRequestCost } from '@outputai/http';

addRequestCost( response, inputCost + outputCost );

Remove RequestCost imports

The RequestCost object shape is no longer part of the public API.

Before

import { addRequestCost, type RequestCost } from '@outputai/http';

const cost: RequestCost = {
  total: 0.42
};

addRequestCost( response, cost );

After

import { addRequestCost } from '@outputai/http';

const cost = 0.42;

addRequestCost( response, cost );

Update cost:http:request hooks

The event payload is now the HTTP request cost attribute.

Before

import { on } from '@outputai/core/hooks';

on( 'cost:http:request', async ( { requestId, url, cost } ) => {
  console.log( requestId, url, cost.total );
} );

After

import { on } from '@outputai/core/hooks';

on( 'cost:http:request', async ( { workflowId, requestId, url, total, activityId, activityName } ) => {
  console.log( workflowId, requestId, url, total, activityId, activityName );
} );

Update LLM response cost handling

The .cost property on generateText() responses and streamText() onFinish responses is now an LLM usage attribute.

Before

const response = await generateText( { prompt: 'summarize@v1' } );

console.log( response.cost.total );
for ( const component of response.cost.components ) {
  console.log( component.name, component.value );
}

After

const response = await generateText( { prompt: 'summarize@v1' } );

console.log( response.cost?.total );
console.log( response.cost?.tokensUsed );
for ( const usage of response.cost?.usage ?? [] ) {
  console.log( usage.type, usage.amount, usage.total );
}
When pricing cannot be computed, response.cost is null.

Handle missing LLM costs

When LLM pricing cannot be loaded or the model is missing from the pricing table, Output no longer returns a cost object with total: null and message.

Before

const response = await generateText( { prompt: 'summarize@v1' } );

if ( response.cost.total === null ) {
  console.warn( response.cost.message );
}

After

const response = await generateText( { prompt: 'summarize@v1' } );

if ( response.cost === null ) {
  console.warn( 'LLM cost was not available for this response.' );
}
No cost:llm:request event or LLM usage trace attribute is emitted when cost is missing.

Handle omitted LLM usage fields

Cost usage entries now include only the dimensions that are available and priced.

Before

const cached = response.cost.components.find( c => c.name === 'input_cached_tokens' );
console.log( cached?.value ?? 0 );

After

const cached = response.cost?.usage.find( u => u.type === 'input_cached' );
console.log( cached?.total ?? 0 );
Use these usage[].type values:
typeDescription
inputNon-cached prompt tokens.
input_cachedCached prompt read tokens.
outputCompletion tokens.
reasoningReasoning tokens, when separately priced.

Update cost:llm:request hooks

The event payload is now the LLM usage attribute.

Before

import { on } from '@outputai/core/hooks';

on( 'cost:llm:request', async ( { modelId, cost, usage } ) => {
  console.log( modelId, usage.totalTokens, cost.total );
} );

After

import { on } from '@outputai/core/hooks';

on( 'cost:llm:request', async ( { workflowId, modelId, tokensUsed, total, usage, activityId, activityName } ) => {
  console.log( workflowId, modelId, tokensUsed, total, usage, activityId, activityName );
} );

Cost attribute reference

HTTP and LLM cost payloads are now trace attributes. Hook payloads include workflowId; workflow result attributes are nested under a result that already has workflowId and runId, so they do not repeat the workflow ID.

HTTP request cost hook payload

{
  "type": "http:request:cost",
  "workflowId": "workflow-123",
  "activityId": "activity-456",
  "activityName": "lookupCompany",
  "requestId": "request-789",
  "url": "https://api.example.com/companies",
  "total": 0.42
}
FieldDescription
typeAlways "http:request:cost".
workflowIdWorkflow execution ID. Present on hook payloads.
activityIdActivity ID of the step that made the request, when available.
activityNameActivity name of the step that made the request, when available.
requestIdInternal ID linking the cost to the traced HTTP request.
urlFinal response URL.
totalDollar cost passed to addRequestCost.

LLM usage cost hook payload

{
  "type": "llm:usage",
  "workflowId": "workflow-123",
  "activityId": "activity-456",
  "activityName": "generateSummary",
  "modelId": "anthropic/claude-3-5-sonnet",
  "total": 0.0084,
  "tokensUsed": 1200,
  "usage": [
    { "type": "input", "ppm": 3, "amount": 800, "total": 0.0024 },
    { "type": "output", "ppm": 15, "amount": 400, "total": 0.006 }
  ]
}
FieldDescription
typeAlways "llm:usage".
workflowIdWorkflow execution ID. Present on hook payloads.
activityIdActivity ID of the step that made the LLM request, when available.
activityNameActivity name of the step that made the LLM request, when available.
modelIdModel identifier used for the request.
totalTotal computed dollar cost.
tokensUsedSum of token amounts included in usage.
usagePer-dimension token usage and cost entries.
Each usage entry includes type, ppm, amount, and total. Only available, finite usage dimensions are included.

Checklist

  • Replace every addRequestCost(response, { total, components }) call with addRequestCost(response, total).
  • Remove RequestCost imports and annotations.
  • Update cost:http:request hook handlers to read total directly from the payload.
  • Remove any logic that expected HTTP cost components; HTTP request costs are now a single total value.
  • Replace LLM response.cost.components reads with response.cost?.usage.
  • Handle response.cost === null when pricing cannot be computed; do not expect a cost object with total: null and message.
  • Update cost:llm:request hook handlers to read the LLM usage attribute payload directly.