Skip to main content
A step represents a single request to an LLM and its response within an agent run. A step requires both a prompt and a response before calling .end(). All setter methods return this, so you can chain calls:
s.prompt("Hello").response("World").model("gpt-4o").end();

Required

Create step

Create a step from a run:
const s = r.step();
ParameterRequiredDescription
stepIdNoCustom step ID. If not provided, a UUID is automatically generated.
import { run } from "@contextcompany/custom";

const r = run();
const s = r.step();
// or with custom ID
const s2 = r.step("custom-step-id");

Set prompt

The prompt is required before calling .end().
s.prompt(text);
ParameterRequiredDescription
textYesThe prompt sent to the LLM
s.prompt("You are a weather agent. The user asked: What is the weather in London?");

Set response

The response is required before calling .end().
s.response(text);
ParameterRequiredDescription
textYesThe response returned by the LLM
s.response("The weather in London is 15°C and cloudy.");

End step

End the step. A step must have both a prompt and a response set before calling .end(). The step cannot be modified after calling .end().
const s = r.step();
s.prompt("You are a weather agent. The user asked: What is the weather in London?");

// --- Your LLM call ---
// ...
// --- End of LLM call ---

s.response("The weather in London is 15°C and cloudy.");
s.end();

Optional step data

Set model

Track which model was used. You can use the shorthand or provide both requested and used models.
s.model(name);
// or
s.model({ requested, used });
ParameterRequiredDescription
nameNoThe model name (shorthand)
requestedNoThe model that was requested
usedNoThe model that was actually used
// Shorthand
s.model("gpt-4o");

// With requested and used
s.model({ requested: "gpt-4o", used: "gpt-4o-2024-08-06" });

Set token usage

Track token counts for the step.
s.tokens({ uncached, cached, completion });
ParameterRequiredDescription
uncachedNoNumber of uncached prompt tokens
cachedNoNumber of cached prompt tokens
completionNoNumber of completion tokens
s.tokens({
  uncached: 150,
  cached: 50,
  completion: 25,
});

Set cost

Track the cost of the step in USD.
s.cost(amount);
ParameterRequiredDescription
amountYesThe total cost of the step in USD
s.cost(0.0035);

Set finish reason

Set the finish reason returned by the LLM.
s.finishReason(reason);
ParameterRequiredDescription
reasonYesThe finish reason returned by the LLM (e.g. "stop", "tool_call")
s.finishReason("stop");

Set tool definitions

Set the tool definitions available to the LLM for this step.
s.toolDefinitions(definitions);
ParameterRequiredDescription
definitionsYesThe tool definitions available to the LLM (string or array)
s.toolDefinitions('[{"name": "get_weather", "description": "Get the weather for a location"}]');

// Or as an array
s.toolDefinitions([
  { name: "get_weather", description: "Get the weather for a location" },
]);

Mark step as failed

Sets the status code to error. The step cannot be modified after calling .error(). Unlike .end(), calling .error() does not require a prompt or response to be set.
s.error(statusMessage?);
ParameterRequiredDescription
statusMessageNoA description of the error
import { run } from "@contextcompany/custom";

const r = run();
r.prompt("What is the weather in London?");

const s = r.step();
s.prompt("Calling weather API...");

try {
  const result = await callWeatherApi();
  s.response(result);
  s.end();
} catch (e) {
  s.error(String(e));
}

// Run still ends successfully even if a step fails
await r.end();

Factory pattern

If you have all step data available upfront, use the sendStep function:
import { sendStep } from "@contextcompany/custom";

await sendStep({
  runId: "run_abc",
  prompt: JSON.stringify(messages),
  response: assistantContent,
  model: { requested: "gpt-4o", used: "gpt-4o-2024-08-06" },
  tokens: { uncached: 120, cached: 30, completion: 45 },
  cost: 0.0042,
  startTime: new Date(),
  endTime: new Date(),
});