Problem
auto works in the TUI because a session exists to bind to. The HTTP surface has two gaps:
- app-server
POST /v1/chat/completions resolves the model per request, stateless (crates/app-server/src/chat_completions.rs:50-110) — there is nothing for a sticky route to bind to, and auto/empty model ids are rejected where an exact model is required (lib.rs:1592, :3650).
auto is explicitly forbidden as a configured-catalog model id (crates/config/src/catalog/configured.rs:83), so it cannot be advertised in the model listing (registry.list(), lib.rs:2535) the way a client expects.
For auto to work over the API the way it works in the TUI, the binding needs a session-scoped identity on the HTTP path.
Change
- Define the binding key for HTTP traffic: thread id for
/v1/threads/{id}/turns (lib.rs:3448-3454); for stateless /v1/chat/completions, either reject auto with a clear error pointing at the threads API, or accept an explicit binding/conversation header that the client must supply. Pick one and document it; do not silently re-route per request.
- Advertise
auto as a pseudo-model in the model listing with metadata marking it session-scoped, behind the same catalog overlay authority used for account-specific models — carve out the configured.rs:83 guard for this one reserved id.
- The server-side binding store reuses the same sticky-binding semantics as the TUI (revalidation, rebind reasons, receipts), keyed by the HTTP binding id instead of
SavedSession.
Acceptance
- Two requests on the same thread/binding id with
model: "auto" resolve to the same provider+model, receipted as one binding.
- A stateless chat-completions call with
auto gets the documented behavior (error or explicit binding), never a per-request coin flip.
GET model listing shows auto with session-scoped metadata; configured catalog entries named auto remain rejected.
Problem
autoworks in the TUI because a session exists to bind to. The HTTP surface has two gaps:POST /v1/chat/completionsresolves the model per request, stateless (crates/app-server/src/chat_completions.rs:50-110) — there is nothing for a sticky route to bind to, andauto/empty model ids are rejected where an exact model is required (lib.rs:1592,:3650).autois explicitly forbidden as a configured-catalog model id (crates/config/src/catalog/configured.rs:83), so it cannot be advertised in the model listing (registry.list(),lib.rs:2535) the way a client expects.For
autoto work over the API the way it works in the TUI, the binding needs a session-scoped identity on the HTTP path.Change
/v1/threads/{id}/turns(lib.rs:3448-3454); for stateless/v1/chat/completions, either rejectautowith a clear error pointing at the threads API, or accept an explicit binding/conversation header that the client must supply. Pick one and document it; do not silently re-route per request.autoas a pseudo-model in the model listing with metadata marking it session-scoped, behind the same catalog overlay authority used for account-specific models — carve out theconfigured.rs:83guard for this one reserved id.SavedSession.Acceptance
model: "auto"resolve to the same provider+model, receipted as one binding.autogets the documented behavior (error or explicit binding), never a per-request coin flip.GETmodel listing showsautowith session-scoped metadata; configured catalog entries namedautoremain rejected.