Skip to content

Commit dfb5c89

Browse files
enriquephlclaude
andcommitted
docs: scope model_name_display_override to chat_companion only
chat_companion's stream is the only path that sends meta.model to a client, so the override is honored there alone; the dead sync path stays out of scope. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent b6fabe2 commit dfb5c89

1 file changed

Lines changed: 27 additions & 16 deletions

File tree

docs/superpowers/specs/2026-05-25-model-name-display-override-design.md

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
**Status**: design, pending implementation plan
44
**Target release**: 0.x patch (additive schema; **changes the default SSE wire behavior** — see §1)
5-
**Audience**: anyone implementing the engine-side `model_name_display_override` knob for `tasks.*`
5+
**Audience**: anyone implementing the engine-side `model_name_display_override` knob for `tasks.chat_companion`
66

77
---
88

@@ -32,19 +32,25 @@ Only the **streaming SSE path** (`crates/eros-engine-server/src/pipeline/stream.
3232

3333
Not client-facing (left untouched):
3434
- `pipeline/mod.rs` sync `run` builds `ChatResponse.model` (~L177) but is
35-
**unrouted dead code**; the gift route returns `reply: None`. We apply the
36-
override there too (trivial, keeps the contract honest if re-wired) but it
37-
has no live effect today.
35+
**unrouted dead code**; the gift route returns `reply: None`. Out of scope —
36+
not wired to the override (§1 non-goals).
3837
- Background tasks (affinity / memory / dreaming) build requests with the
3938
resolved model and never expose it to a client.
4039

4140
---
4241

4342
## 1. Goal / Non-goals
4443

45-
**Goal:** a TOML-driven, **task-level** `model_name_display_override` that
46-
controls the `model` value sent to clients in chat `meta` frames. Four forms:
47-
`boolean | string | array | dict`.
44+
**Goal:** a TOML-driven `model_name_display_override` on
45+
`[tasks.chat_companion]` that controls the `model` value sent to clients in
46+
chat `meta` frames. Four forms: `boolean | string | array | dict`. It is a
47+
top-level (default-block) field; tiers inherit it.
48+
49+
**Scope: `chat_companion` only.** It is the only task that streams a `model`
50+
to a client, so the override is documented, exampled, and honored there alone.
51+
The field still lives on `TaskConfig` (the resolver is generic), so setting it
52+
on another task block parses without error but is **inert** — no task other
53+
than `chat_companion` ever reaches a `display_model()` call.
4854

4955
**Default behavior change (approved):** the compiled-in / field-absent default
5056
is **`false` → omit the `model` field**. This flips today's "always show the
@@ -53,12 +59,16 @@ shipped `examples/model_config.toml.example` sets
5359
`model_name_display_override = true` on `chat_companion`.
5460

5561
**Non-goals:**
62+
- Honoring the override on non-chat tasks (insight/affinity/memory/dreaming) —
63+
they never stream a `model` to a client; the field is inert there.
5664
- Per-tier override (task-level only; tiers inherit, exactly like
5765
`reasoning`/`temperature`/`max_tokens`).
5866
- Changing the model sent to OpenRouter (`per_model_req.model`), the persisted
5967
`AssistantInsert.model`, or any usage logging — all keep the **real** id.
6068
- Persisting the display name (so the DB stays the source of truth for the
61-
real model; see the replay note in §2.5).
69+
real model; see the replay note in §2.6).
70+
- Wiring the override into the dead sync `pipeline::run` path (§0) — it is
71+
unrouted; out of scope until/unless that path is revived.
6272

6373
---
6474

@@ -170,9 +180,8 @@ In `stream.rs`:
170180
builds via `resolve(CHAT_TASK, None)` too), so one resolve covers all rows.
171181
- **Ghost** (both live and replay): `model: None`.
172182

173-
In `pipeline/mod.rs` (currently dead sync path): apply
174-
`resolved.display_model(llm_resp.model.as_deref().unwrap_or(&resolved.model))`
175-
when building `ChatResponse.model`, for contract consistency.
183+
The dead sync `pipeline/mod.rs` path (`ChatResponse.model`, ~L177) is left
184+
unchanged — it is unrouted (§0) and out of scope.
176185

177186
### 2.6 Replay consistency (explicit consequence)
178187

@@ -183,12 +192,14 @@ Because the display name is intentionally **not** persisted, the `array` form
183192
after a reload. `bool` / `string` / `dict` are deterministic across live and
184193
replay. This is acceptable for a cosmetic field.
185194

186-
### 2.7 "All task types"
195+
### 2.7 Scope — `chat_companion` only
187196

188-
The field is valid on every task block (it lives on `TaskConfig`) and is
189-
carried on every `ResolvedModel`, but it only has an **observable effect** for
190-
`chat_companion`, the only task that streams a model to a client. On
191-
background tasks it is inert.
197+
The field lives on `TaskConfig` and is carried on `ResolvedModel` (the resolver
198+
is generic), but `display_model()` is only ever called from the chat streaming
199+
path. No other task reaches an apply site, so the override is honored for
200+
`chat_companion` alone. Setting it on another task block parses without error
201+
and is silently inert — consistent with the absence of `deny_unknown_fields`
202+
elsewhere in the config.
192203

193204
---
194205

0 commit comments

Comments
 (0)