## Extend trajectories with a next user turn (or estimate cost)

**post** `/api/v1/datasets/{dataset_id}/extend-trajectories`

For each row's conversation, generates the user's next message: a single question or request that can only be answered correctly by remembering details from earlier in the conversation, written in the conversation's language. No completion is generated for it. Each request creates a new dataset for the result, returned as `dataset_id`; the dataset in the path is left unchanged. Poll GET /datasets/{dataset_id}/status and download from GET /datasets/{dataset_id}/download with the new id. If the dataset has been adapted (POST /datasets/{dataset_id}/adapt finished), the extension builds on its adapted download: `column_mapping` names columns of that download, so `column_mapping.completion` can be `enhanced_completion`, and the result keeps the adapted columns next to `extended_prompt`. Only `prompt` + `completion` applies there, since adapt splits a chat column into `original_prompt` and `original_completion`. Otherwise the extension reads the uploaded file, with one of two mappings. `column_mapping.chat`: a column of `{"role", "content"}` turns (or a JSON string of that list), ending on the assistant's reply. Or `column_mapping.prompt` with `column_mapping.completion`: the conversation up to the user's last turn (a turn list, or a plain string), plus the final reply as plain text. Each row of the result carries the conversation (split as for /adapt) plus an `extended_prompt` column. `context`, `universal_prompt` and `image` mappings are not currently supported. Credits and status polling behave as for /adapt; an `idempotency_key` replays the extension it first created, returning its `dataset_id` and `run_id` with zero estimates, since the replay starts and charges nothing (as for /translate). Set estimate=true to validate and get a cost quote without starting a run.

### Path Parameters

- `dataset_id: string`

### Body Parameters

- `column_mapping: optional object { chat, prompt, completion }`

  Column role assignments. Required for real runs, optional for estimate-only requests.

  - `chat: optional string`

    Column holding each row's conversation as a list of `{"role", "content"}` turns (or a JSON string encoding that list), ending on the assistant's reply. The full conversation is the trajectory the next user message is generated from. Send `chat` alone, or `prompt` with `completion` instead. Not available on an adapted dataset: adapt splits the chat column into `original_prompt` and `original_completion`, so map those with `prompt` and `completion`.

  - `prompt: optional string`

    Column holding the conversation up to and including the user's last turn: a list of `{"role", "content"}` turns (or a JSON string encoding that list), or a plain string read as a single user turn. Requires `completion`; not allowed with `chat`. On an adapted dataset, a column of its download: `original_prompt` if it was adapted from a chat column, otherwise the dataset's own prompt column.

  - `completion: optional string`

    Column holding the assistant's final reply to `prompt`, as plain text. It becomes the last turn of the trajectory. Requires `prompt`; not allowed with `chat`. On an adapted dataset, a column of its download: `enhanced_completion` extends the adapted reply, the original completion column extends the reply as uploaded.

- `job_specification: optional object { max_rows, idempotency_key }`

  Job execution parameters

  - `max_rows: optional number`

    Maximum number of rows to process in this run

  - `idempotency_key: optional string`

    Client-generated idempotency key for safe retries. If a launch with the same key already exists, the original response is returned.

- `estimate: optional boolean`

  When true, validates the request and returns the estimated credit cost without starting a run.

### Returns

- `run_id: optional string`

  Unique identifier for this pipeline run. Null for estimate-only requests.

- `estimatedMinutes: number`

  Estimated processing time in minutes

- `estimatedCreditsConsumed: number`

  Estimated number of credits that will be consumed by this run

- `estimate: boolean`

  Whether this was an estimate-only request (no run started)

- `multimodalPricingApplied: boolean`

  True when an image column is mapped and also listed in context_columns; each output row is billed at a higher rate.

- `creditMultiplier: optional number`

  10 credits per 100 output rows when multimodalPricingApplied is true. Omitted for text-only pricing.

- `dataset_id: string`

  The new dataset holding the extended trajectories. Poll GET /datasets/{dataset_id}/status and download from GET /datasets/{dataset_id}/download with this id, not the source dataset's. Null for estimate-only requests.

### Example

```http
curl https://api.prod.adaptionlabs.ai/api/v1/datasets/$DATASET_ID/extend-trajectories \
    -H 'Content-Type: application/json' \
    -H "Authorization: Bearer $ADAPTION_API_KEY" \
    -d '{}'
```

#### Response

```json
{
  "run_id": "dataset-550e8400-e29b-41d4-a716-446655440000-1712234567890",
  "estimatedMinutes": 0,
  "estimatedCreditsConsumed": 0,
  "estimate": true,
  "multimodalPricingApplied": true,
  "creditMultiplier": 0,
  "dataset_id": "7d1f3c2a-9b4e-4f60-8a1d-2e5c6b7a8f90"
}
```
