# How the turntype.Detect Component Classifies Request Types in WorkWeave Router

> Discover how the turntype.Detect component in WorkWeave Router classifies request types. Learn about its heuristic cascade for distinguishing probes, compaction tasks, and more.

- Repository: [Weave/router](https://github.com/workweave/router)
- Tags: how-to-guide
- Published: 2026-08-30

---

**The `turntype.Detect` component classifies incoming requests by executing a strict ordered cascade of heuristics in `DetectFromEnvelope`, analyzing the request envelope and routing features to distinguish specialized turn types—such as probes, compaction tasks, and sub-agent dispatches—from standard conversation loops.**

The `turntype` package in the `workweave/router` repository provides intelligent request classification for AI conversation routing. By evaluating the inbound request envelope alongside extracted routing features, the component determines whether a turn represents a quota check, title generation, context compaction, or ordinary user interaction. This classification enables the router to apply precise resource policies and routing logic based on operational intent.

## The Core Entry Point: `DetectFromEnvelope`

The classification logic centers on the `DetectFromEnvelope` function, located in [`internal/router/turntype/detect.go`](https://github.com/workweave/router/blob/main/internal/router/turntype/detect.go) (lines 53-86). This function serves as the primary entry point for the classification system, accepting three parameters: the request envelope, routing features, and an optional sub-agent header string. It implements a **strict ordered cascade** where the most specific signals are evaluated first, ensuring high-impact operational classifications take precedence over general conversation turns.

## Turn Type Constants

The component defines seven distinct turn type constants in [`internal/router/turntype/detect.go`](https://github.com/workweave/router/blob/main/internal/router/turntype/detect.go) (lines 14-29):

- **`Probe`** – Tiny quota-checking requests with `max_tokens` ≤ 4
- **`TitleGen`** – Claude Code sidebar-title generation (no tools + JSON-schema title response)
- **`Compaction`** – Claude Code context-compaction instruction (specific marker phrase in Anthropic format)
- **`SubAgentDispatch`** – Requests originating from sub-agents (header or metadata hints)
- **`Classifier`** – Short-form classifier calls (no tools, limited token and message counts)
- **`ToolResult`** – Turns where the last message kind is `"tool_result"`
- **`MainLoop`** – Default classification for ordinary user-assistant turns

## The Heuristic Decision Cascade

The `DetectFromEnvelope` function processes these heuristics in a specific sequence, returning immediately upon the first match to prevent misclassification.

### 1. Null Envelope Handling

If the request envelope is `nil`, the function immediately returns `MainLoop`. This safety check ensures the system gracefully handles malformed or missing envelope data without crashing.

### 2. Probe Detection

The `isProbe` helper (lines 88-90) checks if `features.MaxTokens` is less than or equal to a hard-coded threshold of **4 tokens**. This identifies tiny quota-checking requests that require minimal resource allocation.

### 3. Title Generation Detection

The `isTitleGen` function (lines 109-116) identifies Claude Code sidebar-title generation by verifying two conditions: the envelope's `RequestsTitleSchema()` method returns true, and the request contains **no tools**. This distinguishes UI metadata requests from functional conversation turns.

### 4. Context Compaction Detection

For Anthropic-format requests, the `isCompaction` heuristic (lines 70-75) scans the system prompt and the tail of the last user message for the compaction marker phrase: `"your task is to create a detailed summary"`. It also verifies the presence of the `"do not call any tools"` clause to confirm this is a context-summarization operation rather than a functional request.

### 5. Sub-Agent Dispatch Detection

The `isSubAgentDispatch` function (lines 76-86) detects requests originating from sub-agents through three signals:

- The `x-weave-subagent-type` header is present
- `metadata.user_id` begins with the literal prefix `"subagent:"`
- The first user message starts with `"<transcript>"` within the first 64 bytes

### 6. Classifier Detection

The `isClassifier` helper (lines 92-106) identifies short-form classification calls by verifying:

- The request contains **no tools**
- `features.MaxTokens` is ≤ 256 tokens
- `features.MessageCount` is ≤ 3 messages

### 7. Tool Result Detection

If the most recent message kind (`features.LastKind`) equals `"tool_result"`, the turn is classified as `ToolResult`. This identifies conversation turns that are processing function call results rather than initiating new user queries.

### 8. MainLoop Fallback

Any request not matching the preceding heuristics defaults to `MainLoop`. This conservative fallback ensures that standard user-assistant conversations receive full resource allocation and routing treatment.

## Safety and Precision Design

The helper functions—`isProbe`, `isTitleGen`, `isCompaction`, `hasCompactionMarker`, `isSubAgentDispatch`, and `isClassifier`—are deliberately **tight** in their validation logic. A false positive would incorrectly hard-pin a request to a specialized routing path, potentially breaking functionality, while a false negative safely falls back to `MainLoop`. This design prioritizes operational safety over aggressive optimization.

## Practical Implementation Example

The following Go example demonstrates how to integrate the classification component within a proxy handler:

```go
// Example: Classify an incoming request inside a proxy handler.
import (
    "workweave/router/internal/translate"
    "workweave/router/internal/router/turntype"
)

// env is the parsed request envelope (already built by translate).
// feats are populated from the request header and body (maxTokens, etc.).
func classify(env *translate.RequestEnvelope, feats translate.RoutingFeatures, subAgentHeader string) turntype.TurnType {
    // DetectFromEnvelope implements the full heuristic cascade.
    return turntype.DetectFromEnvelope(env, feats, subAgentHeader)
}

// Usage:
tt := classify(envelope, routingFeatures, r.Header.Get("x-weave-subagent-type"))
switch tt {
case turntype.Probe:
    // cheap quota-check handling …
case turntype.TitleGen:
    // generate sidebar title …
case turntype.Compaction:
    // apply Claude Code compaction logic …
case turntype.SubAgentDispatch:
    // route to the appropriate sub-agent …
case turntype.Classifier:
    // run short-form classification …
case turntype.ToolResult:
    // process tool result turn …
default:
    // normal main-loop conversation
}

```

## Key Source Files

The classification system spans these critical files within the `workweave/router` codebase:

- **[`internal/router/turntype/detect.go`](https://github.com/workweave/router/blob/main/internal/router/turntype/detect.go)** – Core classification logic, `DetectFromEnvelope` implementation, and `TurnType` constants
- **[`internal/router/turntype/detect_test.go`](https://github.com/workweave/router/blob/main/internal/router/turntype/detect_test.go)** – Unit tests exercising each heuristic branch
- **[`internal/translate/envelope.go`](https://github.com/workweave/router/blob/main/internal/translate/envelope.go)** – Defines `translate.RequestEnvelope` structure
- **[`internal/translate/features.go`](https://github.com/workweave/router/blob/main/internal/translate/features.go)** – Populates routing-feature fields (`MaxTokens`, `HasTools`, `MessageCount`, `LastKind`) from incoming requests

## Summary

- The `turntype.Detect` component uses an **ordered cascade** of heuristics in `DetectFromEnvelope` to classify requests
- **Seven distinct turn types** handle specialized operations from quota probes to context compaction
- **Strict evaluation order** ensures high-impact classifications (like probes and sub-agent dispatches) take precedence
- **Conservative fallback** to `MainLoop` prevents misclassification of standard conversations
- **Tight validation logic** in helper functions minimizes false positives while accepting safe false negatives

## Frequently Asked Questions

### What is the order of precedence for turn type classification?

The `DetectFromEnvelope` function evaluates heuristics in this strict sequence: Null check → Probe → TitleGen → Compaction → SubAgentDispatch → Classifier → ToolResult → MainLoop. This ordering ensures that lightweight system operations (probes) and specialized routing needs (sub-agents) are identified before standard conversational turns.

### How does the component distinguish a probe request from a regular turn?

The `isProbe` helper function in [`internal/router/turntype/detect.go`](https://github.com/workweave/router/blob/main/internal/router/turntype/detect.go) (lines 88-90) classifies a request as a `Probe` when `features.MaxTokens` is less than or equal to 4 tokens. This hard-coded threshold identifies quota-checking requests that require minimal processing resources compared to full conversation turns.

### What triggers a SubAgentDispatch classification?

The `isSubAgentDispatch` function detects sub-agent origins through three signals: the presence of an `x-weave-subagent-type` header, a `metadata.user_id` starting with `"subagent:"`, or the first user message beginning with `"<transcript>"` within the initial 64 bytes. Any of these conditions indicates the request requires sub-agent routing logic.

### Why does the classifier heuristic check both token and message limits?

The `isClassifier` function (lines 92-106) verifies that requests contain no tools, have `max_tokens` ≤ 256, and contain ≤ 3 messages. These combined constraints distinguish short-form classification calls—which are typically lightweight, structured queries—from complex, multi-turn conversations that require `MainLoop` processing and full resource allocation.