Skip to main content
With W&B Weave Threads, you can track and analyze multi-turn conversations in your LLM applications. Threads group related calls under a shared thread_id, allowing you to visualize complete sessions and track conversation-level metrics across turns. You can create threads programmatically, and visualize them in the Weave UI. To get started with Threads, do the following:
  1. Familiarize yourself with the basics of Threads.
  2. Try the code samples, which demonstrate common usage patterns and real-world use cases.

Use cases

Threads are useful when you want to organize and analyze:
  • Multi-turn conversations
  • Session-based workflows
  • Any sequence of related operations.
Threads let you group calls by context, making it easier to understand how your system responds across multiple steps. For example, you can track a single user session, an agent’s chain of decisions, or a complex request that spans infrastructure and business logic layers. By structuring your application with threads and turns, you get cleaner metrics and better visibility in the Weave UI. Instead of seeing every low-level operation, you can focus on the high-level steps that matter.

Definitions

Thread

A Thread is a logical grouping of related calls that share a common conversational context. A Thread:
  • Has a unique thread_id
  • Contains one or more turns
  • Maintains context across calls
  • Represent complete user sessions or interaction flows

Turn

A Turn is a high-level operation within a Thread, displayed in the UI as individual rows in a thread view. Each Turn:
  • Represents one logical step in a conversation or workflow
  • Turns are the direct children of a thread context and may include nested lower-level calls (not shown in thread-level stats).

Call

A Call is any @weave.op-decorated function execution in your application.
  • Turn calls are top-level operations that start new turns
  • Nested calls are lower-level operations within a turn

Trace

A Trace captures the full call stack for a single operation. Threads group traces together that are part of the same logical conversation or session. In other words, a thread is made up of multiple turns, each representing one part in the conversation. For more information on Traces, see the Tracing overview.

UI overview

In the Weave sidebar, select Threads to access the Threads list view.
The Threads icon in the Weave sidebar

Threads list view

  • Lists recent threads in your project
  • Columns include number of turns, start time, and last updated
  • Click a row to open its detail drawer
The Threads list view

Threads detail drawer

  • Click any row to open the detail drawer for that row
  • Shows all turns within a thread.
  • Turns are listed in the order they started (based on their start time, not by duration or end time).
  • Includes call-level metadata (latency, inputs, outputs)
  • Optionally shows message content or structured data if logged
  • To view the full execution of a turn, you can open it from the thread detail drawer. This lets you drill into all nested operations that occurred during that specific turn.
  • If a turn includes messages extracted from LLM calls, they will appear in the right-hand chat pane. These messages typically come from calls made by supported integrations (e.g., openai.ChatCompletion.create) and must meet specific criteria to display. For more information, see Chat view behavior.

Chat view behavior

The chat pane displays structured message data extracted from LLM calls made during each turn. This view gives you a conversational-style rendering of the interaction.
Chat view

What qualifies as a message?

Messages are extracted from calls within a turn that represent direct interactions with LLM providers (e.g., sending a prompt and receiving a response). Only calls that are not further nested inside other calls are shown as messages. This avoids duplicating intermediate steps or aggregated internal logic. Typically, messages are emitted by automatically patched third-party SDKs like:
  • openai.ChatCompletion.create
  • anthropic.Anthropic.completion

What happens if no messages are present?

If a turn doesn’t emit any messages, the chat pane will show an empty message section for that turn. However, the chat pane may still include messages from other turns in the same thread.

Turn and Chat interactions

  • Clicking a turn scrolls the chat pane to that turn’s message location (pinning behavior).
  • Scrolling the chat pane highlights the corresponding turn in the left-hand list.
You can open the full trace for a turn by clicking into it. A back button appears in the upper left corner to return to the thread detail view. UI state (like scroll position) is not preserved across the transition.
The Threads drawer view

SDK usage

Each example in this section demonstrates a different strategy for organizing turns and threads in your application. For most examples, you should provide your own LLM call or system behavior inside the stub functions.
  • To track a session or conversation, use the weave.thread() context manager.
  • Decorate logical operations with @weave.op to track them as turns or nested calls.
  • If you pass a thread_id, Weave uses it to group all operations in that block under the same thread. If you omit the thread_id, Weave auto-generates a unique one for you.
The return value from weave.thread() is a ThreadContext object with a thread_id property, which you can log, reuse, or pass to other systems. Nested weave.thread() contexts always start a new thread unless the same thread_id is reused. Ending a child context does not interrupt or overwrite the parent context. This allows for forked thread structures or layered thread orchestration, depending on your app logic.

Basic thread creation

The following code sample demonstrates how to use weave.thread() to group one or more operations under a shared thread_id. This is the simplest way to start using Threads in your application.

Manual agent loop implementation

This example shows how to manually define a conversational agent using @weave.op decorators and weave.thread() context management. Each call to process_user_message creates a new turn in the thread. You can use this pattern when building your own agent loop and want full control over how context and nesting are handled. Use the auto-generated thread ID for short-lived interactions, or pass a custom session ID (like user_session_123) to persist thread context across sessions.

Manual agent with unbalanced call depth

This example demonstrates that turns can be defined at different depths in the call stack depending on how thread context is applied. The sample uses two providers (OpenAI and Anthropic), each with a different call depth before reaching the turn boundary. All turns share the same thread_id, but the turn boundary appears at different levels in the stack depending on the provider logic. This is useful when calls need to be traced differently for different backends, while still grouping them into the same thread.

Resume a previous session

Sometimes you need to resume a previously started session and continue adding calls to the same thread. In other cases, you may not be able to resume an existing session and must start a new thread instead. When implementing optional thread resumption, never leave the thread_id parameter as None, as this will disable thread grouping entirely. Instead, always provide a valid thread ID. If you need to create a new thread, generate a unique identifier using a function like generate_id(). When no thread_id is specified, Weave’s internal implementation automatically generates a random UUID v7. You can replicate this behavior in your own generate_id() function or use any unique string value you prefer.

Nested threads

This example illustrates how to structure complex applications using multiple coordinated threads. Each layer runs in its own thread context, allowing for clean separation of concerns. The parent application thread coordinates these layers by setting up thread IDs using a shared ThreadContext. Use this pattern when you want to analyze or monitor different parts of the system independently while still tying them to a shared session.

API specification

Endpoint

Endpoint: POST /threads/query

Request schema

Response schema

Query recent active threads

This example fetches the 50 most recently updated threads. Replace my-project with your actual project ID.

Query threads by activity level

This example fetches the 20 most active threads, ordered by number of turns.

Query recent threads only

This example returns threads that started in the past 24 hours. You can change the time window by adjusting the value of days in timedelta.