fix(runtime): resolve compact-turn context once at the chat route

The first checkpoint removed terminal-metrics discovery, but a normal
compact chat turn still ran two context systems: build_chat_context's
legacy untyped lookup (directly or inside maybe_compact) and the typed
resolver inside stream_preview.

Resolve the typed ContextResolution once, at the chat route, before
build_chat_context, using the session's provider credentials. The
predicate mirrors _clean_v3_preview; every input it needs is known at
that point and the native-workspace term cannot veto a requested clean
route. The same object then:

- sizes legacy history shaping in build_chat_context through a new
  maybe_compact(context_length=...) override, so no legacy probe runs;
  an unknown window still shapes with DEFAULT_CONTEXT but gains no
  provenance;
- crosses stream_agent_loop (one new parameter, forwarded only at the
  compact dispatch) into stream_preview, which reuses it and probes only
  for callers that arrive without one or with one bound to another
  route.

ContextResolution now records the endpoint and model it describes
(endpoint URL excluded from repr and metrics). The bare legacy
context_length is never converted into typed evidence.

Credential scoping: origins compare with default ports normalized, an
empty host is never trusted, and the probe client never follows
redirects. Tests cover the configured origin, the server-resolved
Tailscale form, scheme/port/lookalike/userinfo/path origins, redirects,
and secret-free errors, logs and metrics.

The conftest guard now replaces only the resolver's I/O edges (HTTP
client and DNS-capable URL building) instead of the whole probe, and
exposes a context_probe_ledger fixture, so route integration tests run
the real resolver offline and can count metadata requests.
This commit is contained in:
Alexandre Teixeira
2026-10-01 22:31:21 +01:00
parent 837fbfd0ea
commit 0054557027
9 changed files with 666 additions and 26 deletions
+4 -2
View File
@@ -5254,8 +5254,10 @@ async def stream_preview(*, endpoint_url, model, messages, headers, turn_contrac
calendar_create_confirmation = ''
# Resolve the effective window once, before any model request, so the
# turn budgets against it and metrics report exactly what it ran under.
# Terminal metrics must never start this discovery themselves.
if context_resolution is None:
# The chat route prepares it; only callers arriving without one (or with
# one for a different route) resolve here. Terminal metrics must never
# start this discovery themselves.
if context_resolution is None or not context_resolution.applies_to(endpoint_url, model):
from src.agent_runtime.context_resolution import resolve_effective_context
context_resolution = await resolve_effective_context(
endpoint_url, model, headers=headers,