v2 given tests compiled against a panic-only skeleton (go vet clean); no reference implementation. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
65 lines
2.7 KiB
Markdown
65 lines
2.7 KiB
Markdown
# v2 task 01: learn each host's context size from `/props`
|
|
|
|
**Branch:** `v2` (create it from `master`: `git switch master && git switch -c v2`; `git status --short` must be empty first, otherwise stop)
|
|
**Commit subject:** `Health: learn n_ctx and total_slots from /props`
|
|
|
|
## Goal
|
|
|
|
The poller already asks each host `/health` and `/v1/models`. It now also reads `/props` and
|
|
remembers the context size and slot count, so the proxy (task 02) can tell whether a prompt fits.
|
|
A missing or malformed `/props` is **not** a health failure: context is then simply unknown (0).
|
|
|
|
## Context
|
|
|
|
`llama-server` answers `GET /props` with a JSON object containing
|
|
`default_generation_settings.n_ctx` (the total context the server was started with) and
|
|
`total_slots` (how many parallel slots share it). With unified KV, one slot can use up to
|
|
`n_ctx / total_slots` tokens. Some builds omit fields; old ones 404. Read at most `MaxModelsBody`
|
|
bytes as for the other endpoints.
|
|
|
|
## Files
|
|
|
|
- Copy: `internal/health/props_test.go`
|
|
- Modify: `internal/health/health.go`, `internal/admin/admin.go` (or wherever `HostView` is built), `docs/implementer-log.md`
|
|
|
|
## Interfaces
|
|
|
|
`internal/health`, additions:
|
|
|
|
```go
|
|
type Status struct {
|
|
// …existing fields…
|
|
NCtx int `json:"n_ctx"` // total context from /props; 0 = unknown
|
|
Slots int `json:"slots"` // total_slots from /props; 0 = unknown
|
|
}
|
|
// PerSlotCtx is the context one request may use: NCtx / Slots, or NCtx when Slots is 0.
|
|
func (s Status) PerSlotCtx() int
|
|
```
|
|
|
|
Rules the tests check:
|
|
|
|
1. A poll is `/health`, `/v1/models` (as before), then `GET <base>/props`. If that request fails,
|
|
returns non-200, is not JSON, or lacks the fields, set `NCtx = 0`, `Slots = 0` and **do not
|
|
count the poll as failed**. Otherwise `NCtx = default_generation_settings.n_ctx`,
|
|
`Slots = total_slots` (negative values → 0).
|
|
2. `PerSlotCtx()` is integer division; `NCtx` when `Slots == 0`; 0 when `NCtx == 0`.
|
|
3. `admin.HostView` gains `NCtx int \`json:"n_ctx"\`` and `Slots int \`json:"slots"\`` copied
|
|
from the status (the v2 smoke reads `"n_ctx":8192` from `/_crossbar/hosts`). `admin_test.go`
|
|
must keep passing unchanged.
|
|
|
|
## Steps
|
|
|
|
- [ ] **1.** `git switch master && git switch -c v2`; `cp docs/plans/v2/_files/internal/health/props_test.go internal/health/`.
|
|
- [ ] **2. See it fail** (compile: `NCtx` undefined). **3. Write the code.** `gofmt -w internal/`.
|
|
- [ ] **4.** `go test -race -count=1 ./internal/health/ ./internal/admin/` → both `ok`.
|
|
- [ ] **5.** `make gate` → `gate: ok`. **6.** Row `v2/01-props`; commit.
|
|
|
|
```sh
|
|
git add internal/health internal/admin docs/implementer-log.md
|
|
git commit
|
|
```
|
|
|
|
## Done when
|
|
|
|
- Both packages pass; gate ok; `props_test.go` byte-identical to `_files/`.
|