> ## Documentation Index
> Fetch the complete documentation index at: https://docs.thecontextcompany.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Step Usage

> Using steps with The Context Company custom instrumentation for Python

A [step](/concepts#steps) represents a single request to an LLM and its response within an [agent run](/concepts#agent-runs). A step requires both a **prompt** and a **response** before calling `.end()`.

All setter methods return `self`, so you can chain calls:

```python theme={null}
s.prompt("Hello").response("World").model(requested="gpt-4", used="gpt-4-0613").end()
```

## Required

### Create step

There are two ways to create a step:

```python theme={null}
s = r.step()
```

```python theme={null}
s = tcc.step(run_id=r.run_id)
```

| Parameter | Required | Description                                                         |
| --------- | -------- | ------------------------------------------------------------------- |
| `step_id` | No       | Custom step ID. If not provided, a UUID is automatically generated. |

```python theme={null}
import contextcompany as tcc

r = tcc.run()

# Option 1: Create a step from a run
s = r.step()

# Option 2: Create a step directly with a run ID
s = tcc.step(run_id=r.run_id)
```

### Set prompt

The prompt is **required** before calling `.end()`.

```python theme={null}
s.prompt(text)
```

| Parameter | Required | Description                |
| --------- | -------- | -------------------------- |
| `text`    | **Yes**  | The prompt sent to the LLM |

```python theme={null}
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()`.

```python theme={null}
s.response(text)
```

| Parameter | Required | Description                      |
| --------- | -------- | -------------------------------- |
| `text`    | **Yes**  | The response returned by the LLM |

```python theme={null}
s.response("The weather in London is 15°C and cloudy.")
```

### End step

End the step and export it. A step must have both a **prompt** and a **response** set before calling `.end()`. The step cannot be modified after calling `.end()`.

```python theme={null}
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

### Tracking costs

Costs are calculated automatically based on the model and token usage you provide, or you can set the cost directly with your own value.

#### Set model

Track which model was requested and which was actually used.

```python theme={null}
s.model(requested, used)
```

| Parameter   | Required | Description                      |
| ----------- | -------- | -------------------------------- |
| `requested` | No       | The model that was requested     |
| `used`      | No       | The model that was actually used |

```python theme={null}
s.model(requested="gpt-4", used="gpt-4-0613")
```

#### Set token usage

Track token counts for the step.

```python theme={null}
s.tokens(prompt_uncached, prompt_cached, completion)
```

| Parameter         | Required | Description                      |
| ----------------- | -------- | -------------------------------- |
| `prompt_uncached` | No       | Number of uncached prompt tokens |
| `prompt_cached`   | No       | Number of cached prompt tokens   |
| `completion`      | No       | Number of completion tokens      |

```python theme={null}
s.tokens(
    prompt_uncached=150,
    prompt_cached=50,
    completion=25,
)
```

#### Set cost

Alternatively, set the cost directly.

```python theme={null}
s.cost(real_total)
```

| Parameter    | Required | Description                |
| ------------ | -------- | -------------------------- |
| `real_total` | **Yes**  | The total cost of the step |

```python theme={null}
s.cost(real_total=0.0035)
```

### Set finish reason

Set the finish reason returned by the LLM.

```python theme={null}
s.finish_reason(reason)
```

| Parameter | Required | Description                                                          |
| --------- | -------- | -------------------------------------------------------------------- |
| `reason`  | **Yes**  | The finish reason returned by the LLM (e.g. `"stop"`, `"tool_call"`) |

```python theme={null}
s.finish_reason("stop")
```

### Set tool definitions

Set the tool definitions available to the LLM for this step.

```python theme={null}
s.tool_definitions(definitions)
```

| Parameter     | Required | Description                                             |
| ------------- | -------- | ------------------------------------------------------- |
| `definitions` | **Yes**  | The tool definitions available to the LLM for this step |

```python theme={null}
s.tool_definitions('[{"name": "get_weather", "description": "Get the weather for a location"}]')
```

### Mark step as failed

Sets the status code to error and exports the payload. The step cannot be modified after calling `.error()`. Unlike `.end()`, calling `.error()` does not require a prompt or response to be set.

```python theme={null}
s.error(status_message)
```

| Parameter        | Required | Description                |
| ---------------- | -------- | -------------------------- |
| `status_message` | No       | A description of the error |

```python theme={null}
import contextcompany as tcc

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

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

try:
    result = call_weather_api()
    s.response(result)
    s.end()
except Exception as e:
    s.error(status_message=str(e))

# Run still ends successfully even if a step fails
r.end()
```
