Skip to main content
The @contextcompany/custom package provides full control over instrumentation for AI agents that don’t use standard frameworks. It supports two patterns: builder pattern (instrument as you go) and factory pattern (send pre-built data).

Installation

npm install @contextcompany/custom

Quick Start

import { run } from '@contextcompany/custom';

const r = run({ sessionId: 'session_123' });
r.prompt('What is the weather in SF?');

// Create a step for LLM call
const s = r.step();
s.prompt(JSON.stringify(messages));
s.response(assistantContent);
s.model('gpt-4o');
s.tokens({ uncached: 120, cached: 30, completion: 45 });
s.end();

r.response('72°F and sunny.');
await r.end();

Configuration

configure

Set global SDK options that apply to all runs.
function configure(options: ClientConfig): void
options
ClientConfig
required
Example:
import { configure } from '@contextcompany/custom';

configure({
  apiKey: 'tcc_abc123',
  debug: true,
  runTimeout: 600000, // 10 minutes
});

Builder Pattern API

run

Create a new Run builder. This is the main entry point for incremental instrumentation.
function run(options?: RunOptions): Run
options
RunOptions
Run
Run
A Run builder instance with the following methods.

Run Methods

prompt

Set the user prompt/input that initiated the run.
run.prompt(input: string | { user_prompt: string; system_prompt?: string }): Run
input
string | object
required
User prompt as a string, or an object with user_prompt and optional system_prompt.
Example:
r.prompt('What is the weather?');
// or
r.prompt({ 
  user_prompt: 'Summarize this', 
  system_prompt: 'You are a helpful assistant.' 
});

response

Set the agent’s final response to the user.
run.response(text: string): Run
text
string
required
The final response text.

metadata

Attach arbitrary key-value metadata to the run. Multiple calls are merged together.
run.metadata(...entries: Record<string, string>[]): Run
entries
Record<string, string>[]
required
One or more metadata objects to merge. Values must be strings.
Example:
r.metadata({ agent: 'weather-bot', version: '1.2.0' });

status

Set the outcome status code and optional message.
run.status(code: number, message?: string): Run
code
number
required
Status code: 0 for success, 2 for error.
message
string
Human-readable status message (e.g., error description).

endTime

Override the run’s end time (defaults to automatic capture when .end() is called).
run.endTime(date: Date): Run

step

Create a new Step attached to this run.
run.step(stepIdOrOptions?: string | StepOptions): Step
stepIdOrOptions
string | StepOptions
A custom step ID string, or a StepOptions object. Omit to auto-generate an ID.
Step
Step
A Step builder instance. See Step Methods.

toolCall

Create a new ToolCall attached to this run.
run.toolCall(nameOrOptions?: string | ToolCallOptions): ToolCall
nameOrOptions
string | ToolCallOptions
A tool name string, or a ToolCallOptions object.
ToolCall
ToolCall
A ToolCall builder instance. See ToolCall Methods.

end

Finalize the run and send the payload (including all attached steps and tool calls) in a single batch request.
await run.end(): Promise<void>
Throws if:
  • The run has already been ended
  • .prompt() was not called
  • Any attached steps or tool calls have not been ended

error

End the run with error status (2) and send the payload. Any un-ended child steps and tool calls are automatically marked as errored.
await run.error(message?: string): Promise<void>
message
string
Optional error message.

Step Methods

A Step represents a single LLM invocation within a Run.

prompt

Set the prompt sent to the LLM.
step.prompt(text: string): Step
text
string
required
The prompt text (typically serialized messages).

response

Set the LLM’s response text.
step.response(text: string): Step
text
string
required
The response text from the LLM.

model

Set the model used for this step.
step.model(config: string | { requested?: string; used?: string }): Step
config
ModelConfig
required
Pass a string when requested and used model are the same, or an object to distinguish them.
Example:
s.model('gpt-4o');
// or
s.model({ requested: 'gpt-4o', used: 'gpt-4o-2024-08-06' });

tokens

Record token usage for this step. Multiple calls are merged.
step.tokens(usage: TokenUsage): Step
usage
TokenUsage
required
Example:
s.tokens({ uncached: 120, cached: 30, completion: 45 });

cost

Set the actual cost of this step in USD.
step.cost(amount: number): Step
amount
number
required
Cost in USD.

finishReason

Set the model’s finish/stop reason.
step.finishReason(reason: string): Step
reason
string
required
Finish reason (e.g., "stop", "length", "tool_calls").

toolDefinitions

Set the tool definitions/function schemas available to the model during this step.
step.toolDefinitions(defs: string | unknown[]): Step
defs
string | unknown[]
required
A JSON string or an array of tool definition objects (auto-serialized).

status

Set the outcome status code and optional message.
step.status(code: number, message?: string): Step
code
number
required
Status code: 0 for success, 2 for error.

endTime

Override the step’s end time.
step.endTime(date: Date): Step

end

Finalize this step. Both .prompt() and .response() must have been called.
step.end(): void
Throws if the step has already been ended, or if .prompt() or .response() was not called.

error

Mark this step as errored (status code 2).
step.error(message?: string): void

ToolCall Methods

A ToolCall represents a single tool/function invocation within a Run.

name

Set the tool name.
toolCall.name(toolName: string): ToolCall
toolName
string
required
The tool name (e.g., "search", "get_weather").

args

Set the arguments passed to the tool.
toolCall.args(value: string | Record<string, unknown>): ToolCall
value
string | object
required
A JSON string or a plain object (auto-serialized).
Example:
tc.args({ city: 'San Francisco' });

result

Set the return value from the tool.
toolCall.result(value: string | Record<string, unknown>): ToolCall
value
string | object
required
A JSON string or a plain object (auto-serialized).
Example:
tc.result({ temp: 72, unit: 'F' });

status

Set the outcome status code and optional message.
toolCall.status(code: number, message?: string): ToolCall

endTime

Override the tool call’s end time.
toolCall.endTime(date: Date): ToolCall

end

Finalize this tool call. A tool name must have been set.
toolCall.end(): void
Throws if the tool call has already been ended, or if no tool name was set.

error

Mark this tool call as errored (status code 2).
toolCall.error(message?: string): void

Factory Pattern API

sendRun

Send a complete run (with optional nested steps and tool calls) in a single request. Use this when all data is already available.
async function sendRun(input: RunInput): Promise<void>
input
RunInput
required
Example:
await sendRun({
  prompt: { user_prompt: 'What\'s the weather?' },
  response: '72°F in SF',
  startTime: new Date('2025-01-01T00:00:00Z'),
  endTime: new Date('2025-01-01T00:00:01Z'),
  steps: [{
    prompt: '...',
    response: '...',
    model: 'gpt-4o',
    startTime: new Date('2025-01-01T00:00:00Z'),
    endTime: new Date('2025-01-01T00:00:01Z'),
  }],
});

sendStep

Send a single step independently. Requires runId.
async function sendStep(input: StepInput & { runId: string }): Promise<void>
input
StepInput & { runId: string }
required
Example:
await sendStep({
  runId: 'run_abc',
  prompt: '...',
  response: '...',
  model: 'gpt-4o',
  startTime: new Date(),
  endTime: new Date(),
});

sendToolCall

Send a single tool call independently. Requires runId.
async function sendToolCall(input: ToolCallInput & { runId: string }): Promise<void>
input
ToolCallInput & { runId: string }
required
Example:
await sendToolCall({
  runId: 'run_abc',
  name: 'search',
  args: { query: 'weather' },
  result: { temp: 72 },
  startTime: new Date(),
  endTime: new Date(),
});

submitFeedback

Submit user feedback for a specific run.
function submitFeedback(params: {
  runId: string;
  score?: "thumbs_up" | "thumbs_down";
  text?: string;
}): Promise<Response | undefined>
params
object
required

Environment Variables

TCC_API_KEY
string
required
Your Context Company API key. Get one from the dashboard.
TCC_URL
string
Custom ingestion endpoint URL. Overrides the default endpoint.
TCC_DEBUG
boolean
Enable debug logging. Set to true or 1.

Next Steps

View Dashboard

View your instrumented runs in the dashboard

Metadata

Learn about adding metadata to traces

Build docs developers (and LLMs) love