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

# Task extraction for AI agent runs

> Laminar extracts the task from every agent run, shows it in the traces table and transcript view, and makes it queryable with SQL.

Task extraction is how Laminar answers "what was this agent asked to do?" for every trace. Laminar reads the LLM calls in each agent run, finds the user's actual request, and stores it on the trace as its **input**. You see it as a column in the traces table, at the top of the transcript view, and as `agent_input` in SQL, so you can search, group, and filter agent runs by the task they were given.

It needs no configuration. You do not have to pass the task to the root span, name a span in a special way, or set an attribute. If your agent makes LLM calls that Laminar traces, it gets a task.

## Where the task shows up

### Traces table

Every trace has an **Input** column next to the root span name. Instead of reading a list of identical `agent.run` rows, you read the requests your users sent. Drag the column edge to widen it, sort by it, or filter on it like any other column.

![Traces table with the Input column showing each agent run's task](https://mintcdn.com/laminarai/3cHkEEbJgGCE3HXz/images/tracing/traces-table-input-column.png?fit=max\&auto=format\&n=3cHkEEbJgGCE3HXz\&q=85\&s=6e22cd21aab45e5d638e6176fbacf302)

### Transcript view

Open a trace and the task is the first block in the [transcript view](/docs/platform/viewing-traces#transcript-view), labelled **Input**. Each subagent card shows its own input the same way, so in a multi-agent run you can see what the orchestrator asked every subagent to do without expanding anything.

![Transcript view of a failed support agent run with the extracted Input block at the top](https://mintcdn.com/laminarai/3cHkEEbJgGCE3HXz/images/tracing/transcript-view-task.png?fit=max\&auto=format\&n=3cHkEEbJgGCE3HXz\&q=85\&s=4ac605c694d80e590bf3c7b55f335e4f)

The task also appears on traces in the [sessions view](/docs/tracing/structure/sessions) and in the [debugger](/docs/debugger/introduction), and it fills in while a trace is still running, so you can see what a live agent is working on in [realtime](/docs/platform/live-tracing).

## How Laminar finds the task

Real agents rarely send the user's request as a clean string. It sits in the last user message, wrapped in system reminders, environment details, user profiles, retrieved context, and earlier turns of the conversation. The root span often carries something else entirely: a request ID, a config object, or nothing at all.

Laminar looks for the task where the model actually received it:

* **Any span, any depth.** There is no requirement to put the task on the root span or anywhere else. Laminar reads the LLM calls inside the trace, wherever your framework or your own code created them.
* **The main agent's call, not a helper's.** Agents make small side calls: generating a title, classifying intent, summarizing a tool result. Laminar takes the request from the call that drives the agent and ignores the rest.
* **Only the request, not the scaffolding.** From the last user turn, Laminar keeps the part a person wrote and drops the template around it, such as `<system_reminder>` blocks, environment details, and user info.
* **Subagents get their own input.** Each subagent's input is extracted separately, so the trace-level task stays the user's original request while subagent cards show the instructions the orchestrator passed down.

Laminar learns the shape of each agent's prompt template from its traces and reuses it for later runs, which keeps extraction consistent across thousands of runs of the same agent. If you change the template, Laminar picks up the new shape on its own.

For how this works under the hood, and how it holds up across millions of runs, read [Extracting Tasks from Millions of Agent Runs](https://laminar.sh/blog/extracting-tasks-from-agent-runs) on the Laminar blog.

> [!NOTE]
>
> On a [self-hosted](/docs/self-hosting/overview) deployment, task extraction uses the server's AI provider configuration, the same `LLM_PROVIDER` and `LLM_API_KEY` that power chat with trace and SQL with AI. If they are not set, tasks can come back empty. See [Self-hosting configuration](/docs/self-hosting/configuration#ai-features-and-llm-provider).

## Query tasks with SQL

The task is stored in the `agent_input` column of the [`traces` table](/docs/platform/sql-editor#traces), as plain text. You can query it from:

* **[SQL editor](/docs/platform/sql-editor)** in the Laminar UI.
* **[SQL API](/docs/platform/sql-editor#sql-api)**: `POST /v1/sql/query` with your project API key, for notebooks, scheduled jobs, and your own dashboards.
* **[Laminar CLI](/docs/platform/cli#query-data-with-sql)**: `lmnr-cli sql query "..."`, from a terminal or a coding agent.

Find runs about a topic:

```sql theme={null}
SELECT id, start_time, status, agent_input
FROM traces
WHERE start_time > now() - INTERVAL 1 DAY
  AND agent_input ILIKE '%refund%'
ORDER BY start_time DESC
LIMIT 50
```

Pair each task with the agent's final answer, which lives in the [`trace_outputs`](/docs/platform/sql-editor#trace_outputs) table:

```sql theme={null}
SELECT
    t.id,
    substring(t.agent_input, 1, 2000) AS task,
    o.agent_output[-1] AS final_message
FROM traces t
JOIN trace_outputs o ON o.trace_id = t.id
WHERE t.start_time > now() - INTERVAL 1 DAY
ORDER BY t.start_time DESC
LIMIT 20
```

Long tasks can be large. Wrap `agent_input` in `substring(agent_input, 1, 2000)` when you select many rows.

## What you can do with it

### Error rate per task

A project-wide error rate tells you the agent is failing. Grouping by task tells you on what:

```sql theme={null}
SELECT
    agent_input AS task,
    count() AS runs,
    countIf(status = 'error') AS errors,
    round(errors / runs, 2) AS error_rate
FROM traces
WHERE start_time > now() - INTERVAL 7 DAY
  AND agent_input != ''
GROUP BY task
ORDER BY error_rate DESC, runs DESC
LIMIT 20
```

Exact grouping works well for agents with a fixed set of tasks, like evaluation suites, scheduled jobs, or a product with a handful of entry points. For free-form user requests, group on keywords with `multiIf(agent_input ILIKE '%refund%', 'refund', agent_input ILIKE '%status%', 'order status', 'other')`, or use [Signals](/docs/signals/introduction) to label each run with a category and group by that.

The same pattern works for cost and latency: swap the error columns for `avg(total_cost)` or `quantile(0.95)(duration)` to find the tasks that are expensive or slow.

### Understand what users ask your agent

Read the Input column, or query it, to see the real distribution of requests. It is the fastest way to learn which tasks matter, which ones your prompt never anticipated, and which ones users keep retrying.

### Build datasets and evals from real tasks

Filter the traces table on the Input column, or query `agent_input`, to find runs worth keeping, then [export their spans](/docs/datasets/adding-data) to a [dataset](/docs/datasets/introduction). Real tasks from production make better evaluation inputs than examples you write by hand.

## What's next

> **[Viewing traces](/docs/platform/viewing-traces)**
>
> Read a run as a transcript, starting from its task.

> **[SQL editor](/docs/platform/sql-editor)**
>
> The full `traces` and `trace_outputs` schema, with more example queries.

> **[Signals](/docs/signals/introduction)**
>
> Describe an outcome in plain language and track it across every run.

> **[Datasets](/docs/datasets/introduction)**
>
> Turn real tasks from production into evaluation data.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.