feat(app-server): session-scoped auto resolution for HTTP routes (binding id, stateless-path policy)
- Dominant language
- Rust
- Stars
- 41k
- Forks
- 3.6k
- Avg merge
- 13h 59m
- Merged PRs (30d)
- 299
Description
## Problem
`auto` works in the TUI because a session exists to bind to. The HTTP surface has two gaps:
1. 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`).
2. `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
1. 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.
2. 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.
3. 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.
Contributor guide
Research direction
Start with the HTTP route logic in crates/app-server/src/chat_completions.rs and the cited lib.rs thread, model-resolution, and model-listing locations. Read the configured catalog guard in crates/config/src/catalog/configured.rs and trace the TUI sticky-binding semantics, including revalidation, rebind reasons, and receipts. Done means thread or explicit binding requests remain stable, stateless behavior is documented, and the model listing exposes session-scoped auto without allowing configured auto entries.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- api, backend
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100