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