Skip to content

feat: emit turn_start event carrying provider and model - #726

Open
akandola wants to merge 1 commit into
gethouston:mainfrom
SAIFE-Inc:add-turn-start-event
Open

feat: emit turn_start event carrying provider and model#726
akandola wants to merge 1 commit into
gethouston:mainfrom
SAIFE-Inc:add-turn-start-event

Conversation

@akandola

@akandola akandola commented Jul 7, 2026

Copy link
Copy Markdown

Closes #725.

What

Implements the accepted spec in #725 (emit provider + model on the wire per turn).

Adds an additive turn_start WireEvent carrying the turn's provider and resolved model, emitted once per turn. Consumers currently cannot attribute a turn's output to a provider/model on protocol v3 — provider and model are internal-only and only surface indirectly via a later provider_switched / provider_error, which fire only on a switch or a failure. turn_start gives observers the provider + concrete model up front, deterministically, on every turn.

| {
    type: "turn_start";
    data: { provider: string; model: string };
  }

Emission points (one turn_start per turn)

turn_start is emitted exactly once per turn. The two emission sites cover the two mutually-exclusive execution paths — a turn runs through one or the other, never both:

  • Local / in-process runtimepackages/runtime/src/session/chat.ts (runTurn, via publish). This is the long-lived desktop / self-host runtime (conversation-routes.tsrunTurnexecTurn → backend/session). The model is pin-resolved (resolveModel(pin?.model, pin?.provider)); resolution is best-effort and degrades to blank rather than blocking the turn.
  • Cloud per-turn executorpackages/runtime/src/turn/turn-session.ts (runPiTurn, via emit). This is the stateless per-request cloud server (turn/server.ts: one HTTP request = one agent turn). It emits at the first point the concrete model is known, after applying the pin (m.id), so it carries the real model id, not the raw pin.

execTurn (local path) never calls runPiTurn (cloud path); the two are separate code paths, so a given turn produces a single turn_start carrying the concrete model it runs against.

Backward-compatible / additive

  • New arm in the WireEvent discriminated union — no existing event is changed.
  • Snapshot reducer (packages/runtime-client/src/snapshot.ts) handles the new arm as a metadata marker (grouped with provider_switched / context_compacted): it does not touch running / partial, so live-turn snapshot semantics are unchanged.

Rebase

Rebased onto engine-pod-v0.5.24 (ef469f25), current main. Rebases cleanly — no conflicts. Upstream's chat.ts refactor and this PR's turn_start emission touch non-overlapping regions, so the three-way merge applies them side by side. resolveModel's signature (resolveModel(override?, providerOverride?)) is unchanged across the range, so the local-path call resolveModel(pin?.model, pin?.provider) still matches, and the cloud path still exposes provider + resolved m.id at the emission point.

Tests (all green on ef469f25)

  • @houston/protocol typecheck → clean
  • packages/protocol/src/wire.test.ts (protocol re-export + discriminant narrowing) → 1/1 pass
  • @houston/runtime → 737/737
  • @houston/runtime-client → 136/136

Files

  • packages/protocol/src/wire.ts — new turn_start union arm
  • packages/protocol/src/wire.test.ts — type test
  • packages/runtime/src/session/chat.ts — local-runtime emission
  • packages/runtime/src/turn/turn-session.ts — cloud-executor emission
  • packages/runtime-client/src/snapshot.ts — reducer handles the new arm

@akandola
akandola force-pushed the add-turn-start-event branch from a2f73e8 to 64d9031 Compare July 15, 2026 14:47
@akandola
akandola force-pushed the add-turn-start-event branch from 64d9031 to 84570bc Compare July 23, 2026 19:45
Adds an additive turn_start WireEvent emitted once per turn after the model is
resolved, so consumers can attribute a turn to its provider and model without
inferring from a later provider_switched/provider_error (which only fire on a
switch or failure). Model resolution degrades to blank rather than blocking the
turn. Handles the new arm in the runtime-client snapshot reducer's metadata group.
Adds a protocol type test.
@akandola
akandola force-pushed the add-turn-start-event branch from 84570bc to e13e2db Compare July 29, 2026 21:35
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.

Feature: emit provider + model on the wire per turn

1 participant