# What Is the handover.Summarizer in WorkWeave Router?

> Discover how WorkWeave Router's handover.Summarizer creates concise conversation summaries. Seamlessly switch inference models mid-session while preserving context and managing token limits.

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

---

**The handover.Summarizer is a core interface in WorkWeave Router that generates compact prose summaries of active conversations, enabling the router to switch inference models mid-session without losing critical context or exceeding token limits.**

The `handover.Summarizer` sits at the heart of WorkWeave Router's **mid-session model hand-off** mechanism. When the router dynamically upgrades or downgrades models during an active conversation, the new model risks receiving an oversized context window or missing prior context entirely. According to the WorkWeave Router source code, the summarizer solves this by compressing the full message history into a bounded summary before the hand-off occurs.

## Why Model Handover Requires Conversation Summarization

Dynamic model switching allows WorkWeave Router to route expensive reasoning tasks to capable models while using cheaper alternatives for simple queries. However, switching models mid-conversation presents a critical challenge: the new model's context window may be smaller than the accumulated message history, or the full history may exceed cost constraints. The `handover.Summarizer` addresses this by producing a **prose summary** of the conversation so far, which replaces the full history in the request payload sent to the new model.

## The Summarizer Interface and Core Responsibilities

The `Summarizer` interface is defined in [`internal/router/handover/summarizer.go`](https://github.com/workweave/router/blob/main/internal/router/handover/summarizer.go) (lines 30-42). Any implementation must satisfy three key responsibilities:

- **Generate conversation summaries**: The `Summarize(ctx, env)` method returns summary text and usage metrics.
- **Respect request deadlines**: If the summarizer times out or errors, the router preserves the full history unchanged (lines 33-35).
- **Expose upstream provider identity**: The `Provider()` method (lines 40-41) returns the provider enum (e.g., Anthropic) so the router can attach the correct BYOK credentials.

## The ProviderSummarizer Implementation

The concrete implementation, `ProviderSummarizer`, lives in [`internal/proxy/handover.go`](https://github.com/workweave/router/blob/main/internal/proxy/handover.go) (lines 66-98). This struct adapts a `providers.Client` (typically Anthropic) to the `Summarizer` contract.

When invoked, `ProviderSummarizer` builds a minimal Anthropic Messages request and dispatches it under a **hard timeout**. On success, it returns the generated summary along with token-usage data for billing telemetry (lines 110-118). On failure, it returns an empty summary, signaling the router to fall back to the unmodified message history rather than fail the request.

## Integrating the Summarizer into the Routing Pipeline

The summarizer is wired into the proxy service via the `WithSummarizer` method in [`internal/proxy/service.go`](https://github.com/workweave/router/blob/main/internal/proxy/service.go) (lines 1636-1640). This method "installs the cheap-model summarizer for handover on switch," registering the summarizer for invocation during model transitions.

During the turn loop, found in [`internal/proxy/turnloop.go`](https://github.com/workweave/router/blob/main/internal/proxy/turnloop.go) (lines 1309-1322), the router checks if a model switch requires hand-over. If so, it resolves credentials for the summarizer's provider, invokes `Summarize()`, and—on success—records the usage metrics for billing before proceeding with the envelope rewrite.

## Rewriting the Request Envelope

The actual insertion of the summary into the request occurs via `handover.RewriteEnvelope` in [`internal/router/handover/summarizer.go`](https://github.com/workweave/router/blob/main/internal/router/handover/summarizer.go) (lines 44-52). This function mutates the request envelope to retain system messages while replacing the user message history with a compact payload consisting of the **assistant summary** followed by the **latest user message**.

This rewrite ensures the new model receives essential conversation context without the token overhead of the full history, enabling **bounded-cost context handover**.

## Implementation Examples

### Attaching a Summarizer to the Proxy Service

```go
// Create a provider-client (e.g., Anthropic) – the client implements providers.Client.
anthropicClient := providers.NewAnthropicClient(...)

// Build a summarizer that uses the cheap "claude-haiku-4-5" model and default timeout.
summarizer := proxy.NewProviderSummarizer(anthropicClient, "", 0)

// Wire the summarizer into the proxy service.
svc := proxy.NewService(...)
svc = svc.WithSummarizer(summarizer)

```

The `WithSummarizer` call registers the summarizer so the router will invoke it during a hand-off.

### Invoking the Summarizer During Model Switch

```go
// Inside the turn-loop, when a model switch is required:
if needHandover {
    // Resolve credentials for the summarizer's upstream provider.
    sumCreds := resolveSummarizerCreds(ctx, providers.ProviderAnthropic, reqHeaders)

    // Summarize the prior conversation.
    summary, usage, err := svc.summarizer.Summarize(ctx, requestEnv)
    if err == nil {
        // Replace the envelope messages with the compact summary.
        handover.RewriteEnvelope(requestEnv, summary)
        // Record the usage for billing.
        billing.RecordUsage(usage)
    }
    // If err != nil the full history is left unchanged.
}

```

### Direct Envelope Manipulation for Testing

```go
env := translate.NewRequestEnvelope(...)
summary := "Prior conversation summary."
elided := handover.RewriteEnvelope(env, summary)
// `elided` is the number of messages removed; `env` now contains
// system blocks + the summary + the latest user message.

```

## Summary

- The `handover.Summarizer` enables **mid-session model switching** by compressing conversation history before hand-off.
- Defined in [`internal/router/handover/summarizer.go`](https://github.com/workweave/router/blob/main/internal/router/handover/summarizer.go), the interface requires implementations to generate summaries, respect timeouts, and expose their upstream provider.
- The concrete `ProviderSummarizer` in [`internal/proxy/handover.go`](https://github.com/workweave/router/blob/main/internal/proxy/handover.go) uses Anthropic's API under a hard timeout, falling back to full history on failure.
- Integration occurs via `proxy.Service.WithSummarizer` ([`internal/proxy/service.go`](https://github.com/workweave/router/blob/main/internal/proxy/service.go)), with invocation happening in the turn loop ([`internal/proxy/turnloop.go`](https://github.com/workweave/router/blob/main/internal/proxy/turnloop.go)).
- `handover.RewriteEnvelope` performs the final payload transformation, replacing full message history with `[assistantSummary, latestUser]` to maintain context within token limits.

## Frequently Asked Questions

### What happens if the summarizer fails or times out?

If the `Summarize` method returns an error or exceeds its deadline, the router preserves the full conversation history unchanged and proceeds with the hand-off. This failsafe, documented in the interface comments at [`internal/router/handover/summarizer.go`](https://github.com/workweave/router/blob/main/internal/router/handover/summarizer.go) (lines 33-35), ensures that a temporary summarizer outage never drops user context.

### Which upstream provider does the summarizer use?

The default `ProviderSummarizer` implementation uses **Anthropic** as the upstream provider. The `Provider()` method exposes this identity so the router can resolve the correct Bring-Your-Own-Key (BYOK) credentials before invoking the summary generation.

### How does RewriteEnvelope modify the conversation history?

`handover.RewriteEnvelope` mutates the request envelope to retain system messages while replacing all previous user and assistant messages with a two-element sequence: the generated assistant summary followed by the latest user message. This transformation occurs in [`internal/router/handover/summarizer.go`](https://github.com/workweave/router/blob/main/internal/router/handover/summarizer.go) (lines 44-52) and drastically reduces token count while preserving semantic context.

### Where is the summarizer configured in the service lifecycle?

The summarizer is attached to the proxy service via the `WithSummarizer` method defined in [`internal/proxy/service.go`](https://github.com/workweave/router/blob/main/internal/proxy/service.go) (lines 1636-1640). This method is called during service initialization to "install the cheap-model summarizer for handover on switch," ensuring the summarizer is available when the turn loop evaluates model transitions.