Skip to content

Per-turn context window and what fills it - #318

Merged
fylorn merged 1 commit into
mainfrom
feat/turn-context
Oct 10, 2026
Merged

fylorn merged 1 commit into
mainfrom
feat/turn-context

Conversation

@fylorn

@fylorn fylorn commented Oct 10, 2026

Copy link
Copy Markdown
Contributor

What

A session's turns only carried their measured usage. The desktop app wants to show how full a turn's context window was and what was occupying it.

  • TurnView gains context_window: number | null: the window of the model that answered the turn, resolved now through the one spec resolution core already has (tw_config::model_specs: the upstream's manual model_specs first, then the price table), looked up by the model name the upstream actually received (sent_model, now carried by TurnRow).
  • New endpoint GET /sessions/{id}/turns/{turn}/context answering TurnContext:
    • parts: the stored request body decoded with the client's dialect (Anthropic system + messages; Chat system/developer messages; Responses instructions + input items; Gemini systemInstruction + contents) and estimated in one pass as system, tools (tool definitions), history (every message before the last user message), last_user (the last user message with the tool results it carries) and total, by the same estimator count_tokens answers with (tw_engine::estimate_parts, the per-part twin of estimate_tokens; each part rounds on its own, so the sum can differ from the whole-body estimate by a few tokens).
    • window, input_tokens, cache_read_tokens from the spec and the history row.
    • kept: false with parts: null when the body was never kept, has expired, was truncated or cannot be decoded.
    • 404 control.session_not_found for an unknown session; 404 control.request_not_found for a turn that is not in that session.
  • CONTROL_API_VERSION 44 → 45, with the version notes above it; the new types are in the TypeScript export (not kept in-tree; CI regenerates it).
  • tw-control now depends on tw-dialect directly to decode stored bodies (one line in Cargo.lock).

New messages

None. The endpoint reuses control.session_not_found and control.request_not_found.

Verified

  • cargo fmt --all --check
  • cargo clippy -p tw-api -p tw-engine -p tw-store -p tw-control -p twcore --all-targets -- -D warnings
  • cargo test --workspace with the local proxy unset: all green
  • cargo run -p tw-api --features ts --example export_ts: exports TurnContext, ContextParts, TurnView.context_window
  • New tests: crates/tw-control/tests/turn_context.rs (Anthropic, Chat, Responses and Gemini bodies split into four parts; body gone; manual spec vs price table vs unknown model; the two 404s), tw_engine::facts::tests::parts_split_the_body_at_the_last_user_message, and a ts.rs test pinning the exported shape.

🤖 Generated with Claude Code

A session's turns only carried their measured usage. The desktop app
wants to show how full a turn's context window was and what was
occupying it, so:

- `TurnView` gains `context_window`: the window of the model that
  answered the turn, resolved now through the one spec resolution
  core already has (`tw_config::model_specs`: the upstream's manual
  spec first, then the price table), looked up by the model name the
  upstream actually received (`sent_model`, now carried by `TurnRow`).
- New endpoint `GET /sessions/{id}/turns/{turn}/context` answering
  `TurnContext`: the stored request body decoded with the client's
  dialect and estimated in one pass as four parts (system prompt,
  tool definitions, every message before the last user message, the
  last user message with the tool results it carries) by the same
  estimator `count_tokens` answers with, next to the measured input
  and cache-read tokens from the history row. A body that was never
  kept, has expired, was truncated or cannot be decoded answers
  `kept: false` with `parts: null`. An unknown session is
  `control.session_not_found`; a turn that is not in that session is
  `control.request_not_found`.
- `tw_engine::estimate_parts` is the per-part twin of
  `estimate_tokens`; each part rounds on its own, so the sum differs
  from the whole-body estimate by at most a few tokens.
- Protocol version 45. tw-control now depends on tw-dialect directly
  to decode stored bodies.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@fylorn
fylorn merged commit b8ae3f3 into main Oct 10, 2026
6 checks passed
@fylorn
fylorn deleted the feat/turn-context branch October 10, 2026 10:55
@fylorn fylorn mentioned this pull request Oct 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant