What Is the handover.Summarizer in WorkWeave Router?

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 (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 (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 (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 (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 (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

// 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

// 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

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, the interface requires implementations to generate summaries, respect timeouts, and expose their upstream provider.
  • The concrete ProviderSummarizer in 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), with invocation happening in the turn loop (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 (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 (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 (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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →