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

# Threads

> Perform agentic tasks using the threads system

<Info>
  This documentation is for **Wise Wolf** release (February 2026) and later.
  If you are on **Unique Urchin** (December 2025) or **Victorious Vicuna** (January 2026), please refer to [the legacy agentic threads documentation](/en/developer-resources/chat-and-ai-models/agent-api).
</Info>

## Motivation

The Thread API, allows you to engage in conversations leveraging multi-tool reasoning capabilities and using specialized [agents](/en/developer-resources/agents-and-threads/agents). It is the recommended way to interact with Paradigm tools.

## Terminology

### Turn

A single interaction between a user and the model, comprising a user query, multi-steps reasoning, tool calls and the model's final answer.

### Thread

A conversation comprising a sequence of turns.

### Parts

A component of the conversation turn's answer, it can be of type `reasoning`, `tool_call` or `text` (final answer to the user).
The parts in an agent message within a turn are structured in the following sequence:

* a `reasoning` part explaining the reasoning about wether the agent will choose tyo use a tool or return the final answer.
* a `tool_call` part containing information about the tool called as well as the tool's raw result.
* repeat the 2 first steps until the agent choose to return the final answer or the reasoning budget is reached.
* a `text` part containing the final answer.

### Message

A set of parts corresponding to, within a turn, either the agent answer or the user query. A **turn is thus primarily composed of a list of 2 messages**: the user query and the agent answer.

### Source

A source used by a tool to generate the turn's final answer, it can either of type `web` or `document`.

### Artifact

A file generated by a tool, attached to a turn.

## Quickstart

You can initialize a new conversation thread using the [POST /api/v3/threads/turns](/api-reference-v3/threads/create-a-conversation-thread-with-initial-turn) endpoint.

<Warning>
  The payload field `chat_setting_id` has been deprecated and now the use of `agent_id` is preffered, for back compatibility issues `chat_setting_id` is still supported. Note that if you specify both `agent_id` and `chat_setting_id`, the `agent_id` field will take precedence.
</Warning>

```py theme={null}
import os
import requests

# Get API key from environment
api_key = os.getenv("PARADIGM_API_KEY")
# Get base URL from environment (defaults to public instance)
base_url = os.getenv("PARADIGM_BASE_URL", "https://paradigm.lighton.ai/api/v3")

response = requests.post(
    f"{base_url}/threads/turns",
    headers={"Authorization": f"Bearer {api_key}"},
    json={
        "agent_id": 1,
        "query": "What is the capital of France?"
    }
).json()
```

While specifying:

* `agent_id` (*optional*): the ID of the [Agent](/en/developer-resources/agents-and-threads/agents) to use to perform this query, if left blank, your company's default agent will be used. You can list the available agents using the \[GET /api/v3/agents]\([api-reference-v3/threads/](/api-reference-v3/agents/list-all-agents) endpoint.
* `query`: the user query.

<Accordion title="Response example">
  ```json theme={null}
  {
    "id": "9339cf12-8530-421d-8dda-79cd3016a182",
    "object": "turn",
    "thread": "783b089b-0ecc-496b-b0c3-70d0f327d9b8",
    "status": "completed",
    "messages": [
      {
        "id": "2951681d-9477-4e8d-889b-0f63bef890f6",
        "object": "message",
        "role": "user",
        "parts": [
          {
            "type": "text",
            "text": "What is the capital of France?"
          }
        ],
        "created_at": "2025-12-16T16:01:53.806331Z"
      },
      {
        "id": "5ec22b40-ba6c-40ab-b94d-97fc05d5c142",
        "object": "message",
        "role": "assistant",
        "parts": [
          {
            "type": "reasoning",
            "reasoning": "Basic factual question - no tools needed."
          },
          {
            "type": "text",
            "text": "La capitale de la France est Paris."
          }
        ],
        "created_at": "2025-12-16T16:01:56.210968Z"
      }
    ],
    "created_at": "2025-12-16T16:01:53.804779Z"
  }
  ```
</Accordion>

In this case the agent answer on this turn is made of of two parts:

* a **reasoning** part explaining the reasoning behind the answer.
* a **text** part containing the final answer.

Note that **the last part of the agent answer is always of type `text` and consitute the final answer**
and that **the agent answer is always the second and last message**.

<Warning>
  If the turn takes too long to generate you will receive an **HTTP 202** response with the created
  **thread ID** (`tread`) and the **turn ID** (`turn_id`) in the payload. You can then use the [GET /api/v3/threads/:id/turns/:turn\_id](/api-reference-v3/threads/retrieve-a-conversation-thread) endpoint
  to poll for the `status` until it is in state `completed` and then retrieve the final answer.
</Warning>

<Tip>
  Alternatively you can skip the waiting and use [Background Mode](#background-mode) to generate the turn in the background.
</Tip>

You can access the agent final answer like this:

```py theme={null}
# Minimal structure example to illustrate access pattern
response = {
    "messages": [
        {"parts": []},
        {"parts": [{"type": "text", "text": "Paris"}]}
    ]
}
answer: str = response["messages"][-1]["parts"][-1]["text"]
```

You can also retrieve the `thread_id` like this:

```py theme={null}
response = {"thread": "783b089b-0ecc-496b-b0c3-70d0f327d9b8"}
thread_id: str = response["thread"]
```

And then you can follow-up on the same conversations using the [POST /api/v3/threads/:id/turns](/api-reference-v3/threads/create-a-conversation-turn-in-a-thread) endpoint
to create a new conversation turn.

## Recipes

For the following recipes, you can either use:

* the [POST /api/v3/threads/turns](/api-reference-v3/threads/create-a-conversation-thread-with-initial-turn) endpoint to create a turn a new conversation thread.
* the [POST /api/v3/threads/:id/turns](/api-reference-v3/threads/create-a-conversation-turn-in-a-thread) endpoint to create a turn in an existing conversation thread, thus benefiting from the context already there if needed.

<Warning>
  While the [POST /api/v3/threads/turns](/api-reference-v3/threads/create-a-conversation-thread-with-initial-turn) endpoint provides a shortcut to directly create a thread with a turn, **it does not support streaming mode**, if you want to use streaming then create a thread using the [POST /api/v3/threads](/api-reference-v3/threads/create-a-conversation-thread) endpoint and then create a turn in this thread using the [POST /api/v3/threads/:id/turns](/api-reference-v3/threads/create-a-conversation-turn-in-a-thread) while specifying `stream=true`.
</Warning>

In those examples we will use the method involving using a new thread, but both endpoints take the same payload and return the same response schema.
It will also be assumed that you parse the API response into a Python dictionary, like done in the [Quickstart](#quickstart) section.

<Tip>
  For single call usage in workflows it is recommented to use the first endpoint, creating a fresh thread per turn.
</Tip>

### Scoping by file, workspaces or tags

You can scope a query within a list of **Worspkaces** and/or **Tags** or **Files** (documents) using the `workspace_ids`, `tag_ids` or `file_ids` parameters in the payload. For instance, using the [POST /api/v3/threads/turns](/api-reference-v3/threads/create-a-conversation-thread-with-initial-turn) endpoint for scoping for files within workspaces of id `1` **or** `2` **and** that are attached to tags of id `4` **or** `5`:

```json theme={null}
{
  "agent_id": 1,
  "query": "What is the conclusion of the last quaterly meeting note?",
  "workspace_ids": [1, 2],
  "tag_ids": [4, 5],
}
```

Same here for scoping a query to files of id `8` and `9`:

```json theme={null}
{
  "agent_id": 1,
  "query": "What is the conclusion of the last quaterly meeting note?",
  "file_ids": [8, 9],
}
```

<Warning>
  While you can mix `workspace_ids` and `tag_ids`, you **cannot mix either of these with** `file_ids`.
</Warning>

<Info>
  The `agent_id` field is optional, if omitted the default agent of your company will be used. You can list available [agents](/en/developer-resources/agents-and-threads/agents) using the [GET /api/v3/agents](/api-reference-v3/agents/list-all-agents) endpoint.
</Info>

<Tip>
  It is recommended to not force a tool when scoping, as the automatic routing will ensure the optimal tool for
  your type of file(s) is used.
</Tip>

* You can retrieve the list of **workspaces** available for you when using a specific agent by calling the [GET /api/v3/agents/:id](http://localhost:3001/api-reference-v3/agents/retrieve-a-single-agent) endpoint and use the `workspaces` field of the component.

* You can retrieve the list of **files** available for you when using a specific agent by calling the [GET /api/v3/agents/:id/files](http://localhost:3001/api-reference-v3/agents/list-files-scoped-to-an-agent) endpoint.

* You can retrieve the list of **tags** available for you when using a specified agent by calling the [GET /api/v3/agents/:id/tags](/api-reference-v3/agents/list-tags-used-in-workspaces-for-an-agent) endpoint.

<Tip>
  If you are not specifying a particular agent then you are using your company's default agent, you can retrieve it by calling the [GET /api/v3/agents?is\_default=true](/api-reference-v3/agents/list-all-agents) endpoint (if you are sys-admin you might want to use the additional query parameter filter `&company_id=:id` with your company id).
</Tip>

### Using a specific tool

Call the [POST /api/v3/threads/turns](/api-reference-v3/threads/create-a-conversation-thread-with-initial-turn) endpoint,
while specifying the tool name to use in the payload like this:

```json theme={null}
{
  "agent_id": 1,
  "query": "What is the conclusion of the last quaterly meeting note?",
  "force_tool": "document_search"
}
```

<Info>
  The `agent_id` field is optional, if omitted the default agent of your company will be used. You can list available [agents](/en/developer-resources/agents-and-threads/agents) using the [GET /api/v3/agents](/api-reference-v3/agents/list-all-agents) endpoint.
</Info>

<Warning>
  Forcing a tool when working with documents is not recommended, prefer scoping files/workspaces to your query
  and let the automatic routing decides which tool is the best for your file(s).
</Warning>

You can list the available native tools available for the agent you are using through the [GET /api/v3/agents/:id/tools]() endpoint.

<Warning>
  Ensure the selected native tool is enabled for the agent you are using, you can check by calling the [GET /api/v3/agents/:id]() endpoint, if you are not specifying any agent then you can check using the [GET api/v3/agents?is\_default=true]() endpoint (if you have a sys-admin role you might want to use the `?company_id=:id` with your company id).
</Warning>

As seen in the [Quickstart](#quickstart) section, the agent answer is the last message of the turn.

You can then retrieve the final answer like this:

```py theme={null}
# Minimal structure example to illustrate access pattern
response = {
    "messages": [
        {"parts": []},
        {"parts": [{"type": "text", "text": "Paris"}]}
    ]
}
answer: str = response["messages"][-1]["parts"][-1]["text"]
```

In this scenario the first part of the agent answer is a **tool\_call** part. It contains information about
the tool called as well as the tool's raw result.

<Info>
  Note that since the tool was forced to a specific value, this turn won't contain a reasoning part.
</Info>

You can retrieve it like this:

```
tool_call: dict = response["messages"][-1]["parts"][0]
```

### Using a specific MCP server

If you want to restrict tool routing to the tools provided by a specific MCP server,
call the the [POST /api/v3/threads/turns](/api-reference-v3/threads/create-a-conversation-thread-with-initial-turn) endpoint, while specifying the MCP server name in the payload like this:

<Warning>
  Ensure the selected tool is enabled in the **Agent MCP Servers** section of your [Chat Settings](/en/administration/agent-management/agent-settings).
</Warning>

```json theme={null}
{
  "agent_id": 1,
  "query": "What are the latest news about LightOn ?",
  "force_mcp_server": "websearch-linkup"
}
```

<Info>
  The `agent_id` field is optional, if omitted the default agent of your company will be used. You can list available [agents](/en/developer-resources/agents-and-threads/agents) using the [GET /api/v3/agents](/api-reference-v3/agents/list-all-agents) endpoint.
</Info>

It will restrain the tool routing to the tools provided by the MCP server named `websearch-linkup` attached to the company
linked to the API key used.

<Tip>
  Note that even when forcing a specific MCP server, the model can still choose to use none of its tools if it believes it knows the answer.
</Tip>

### Extending the system prompt

You can extend the system prompt during one query and pass specific instructions using the `system_prompt_suffix`
parameter of the payload. For instance, using the [POST /api/v3/threads/turns](/api-reference-v3/threads/create-a-conversation-thread-with-initial-turn) endpoint:

```json theme={null}
{
  "agent_id": 1,
  "query": "What is the conclusion of the last quaterly meeting note?",
  "force_tool": "document_search",
  "system_prompt_suffix": "Rephrase technical term into more accessible language."
}
```

<Info>
  The `agent_id` field is optional, if omitted the default agent of your company will be used. You can list available [agents](/en/developer-resources/agents-and-threads/agents) using the [GET /api/v3/agents](/api-reference-v3/agents/list-all-agents) endpoint.
</Info>

<Tip>
  Using this method rather than adding more instructions in your query allow to tune the agent behaviour while ensuring
  an optimal search accuracy for your query in the case of `document_search` or `document_analysis` tools.
</Tip>

### Requesting structured output

You can request structured output from the agent by specifying the `response_format` parameter in the payload.
For instance, using the [POST /api/v3/threads/turns](/api-reference-v3/threads/create-a-conversation-thread-with-initial-turn) endpoint:

```json theme={null}
{
  agent_id: 1,
  "query": "What is the capital of France?",
  "response_format": {
    "type": "object",
    "properties": {
      "capital": {
        "type": "string"
      },
      "country": {
        "type": "string"
      }
    },
    "required": [
      "capital",
      "country"
    ]
  }
}
```

<Info>
  The `agent_id` field is optional, if omitted the default agent of your company will be used. You can list available [agents](/en/developer-resources/agents-and-threads/agents) using the [GET /api/v3/agents](/api-reference-v3/agents/list-all-agents) endpoint.
</Info>

For more information about `response_format`, please consult the [Guided JSON](/en/developer-resources/chat-and-ai-models/structured-output#guided-json) documentation.

### Generating artifacts

Some tools like `code_execution` can generate artifacts that can be downloaded afterwards. For instance, when using
the [POST /api/v3/threads/turns](/api-reference-v3/threads/create-a-conversation-thread-with-initial-turn) endpoint:

```json theme={null}
{
  "agent_id": 1,
  "query": "Draw me a graph of a sinusoidal function.",
  "force_tool": "code_execution"
}
```

<Info>
  The `agent_id` field is optional, if omitted the default agent of your company will be used. You can list available [agents](/en/developer-resources/agents-and-threads/agents) using the [GET /api/v3/agents](/api-reference-v3/agents/list-all-agents) endpoint.
</Info>

It will result into an agent answer consisting of 2 parts:

* a `tool_call` part in which you can find the generated artifacts.
* a `text` part containing the final answer.

You can then retrieve the artifacts like this:

```python theme={null}
artifacts: list[dict] = response["messages"][-1]["parts"][0]["tool_call"]["result"]["file_artifacts"]
```

Each file artifact contains the following fields:

* `id`: the ID of the artifact.
* `thumbnail_base64`: a base64 encoded 256x256 webp thumbnail of the artifact if the artifact is an image.

Once you have the artifact ID you can retrieve the artifact content using
the [GET /api/v3/artifacts/:id/content](/api-reference-v3/artifacts/retrieve-an-artifact-content) endpoint.

## Background mode

For heavy query that needs to be handled asynchronously, you can use the [POST /api/v3/threads/turns](/api-reference-v3/threads/create-a-conversation-thread-with-initial-turn) endpoint
with the `background` parameter set to `true`. For instance:

```json theme={null}
{
    "agent_id": 1,
    "query": "What is the capital of France?",
    "background": true
}
```

<Info>
  The `agent_id` field is optional, if omitted the default agent of your company will be used. You can list available [agents](/en/developer-resources/agents-and-threads/agents) using the [GET /api/v3/agents]() endpoint.
</Info>

You will receive an **HTTP 200** response with the thread object but containing only the user query, notice how the `status` field
is set to `running`:

<Accordion title="Response example">
  ```json theme={null}
  {
      "id": "6d0d54c3-a87b-4c66-8af2-8ef59418358e",
      "object": "turn",
      "thread": "12df8e86-e8b0-49ee-8634-f5ce8944591c",
      "status": "running",
      "messages": [
        {
          "id": "22461762-afd8-4533-8cf2-2e7d516a38d6",
          "object": "message",
          "role": "user",
          "parts": [
            {
              "type": "text",
              "text": "What is the capital of France?"
            }
      ],
      "created_at": "2025-12-17T14:46:00.703903Z"
      }
    ],
    "created_at": "2025-12-17T14:46:00.702207Z"
  }
  ```
</Accordion>

You can then retrieve the thread id in the following way:

```python theme={null}
thread_id: str = response["thread"]
```

You can now poll periodically the [GET /api/v3/threads/:id](/api-reference-v3/threads/retrieve-a-conversation-thread) endpoint
until the `status` field is set to `completed`.

When the thread is back in its `completed` status, you can fetch its turns using
the [GET /api/v3/threads/:id/turns](http://localhost:3001/api-reference-v3/threads/list-conversation-turns-in-a-thread) endpoint.

<Tip>
  To only retrieve the last turn, you can set the `limit` query parameter to `1`.
</Tip>
