docs: serve front door in README + REPORT

README: status line, OpenAI front door section (routes table, stateless
semantics, OWUI connection recipe), mermaid flow for the OWUI door, CLI
subcommand + flags rows, [serve] config rows, status table rows (serve
works; streaming + serve tool use stubbed as Next). REPORT.md: phase 3b
entry with the live LAN proof and the Next list.

💘 Generated with Crush

Assisted-by: Crush:glm-5.2
This commit is contained in:
2026-08-29 01:22:12 -05:00
parent c9e86eefa8
commit 704f905a90
2 changed files with 140 additions and 9 deletions
+57 -1
View File
@@ -191,6 +191,60 @@ slot-file cap; `~/.coordinate/scripts/queue-next.sh`, `queue-after.sh`,
it targets screen `reachableceo-PMO`, the live screen is `RCEO-PMO`, so
the message was silently dropped).
## Build phase 3b — OWUI front door (`harness serve`) — 2026-08-29
Charles' TASK (2026-08-29 00:00): OpenAI-compatible front door, OWUI is the
client; DESIGN "OWUI front door" (hermes killed). OWUI chat and webhooks are
two doors into the same conductor loop.
Works:
- **`harness serve` CLI**: stdlib net/http receiver in the events style,
SIGINT/SIGTERM graceful shutdown, `-config` / `-listen` flags, own port
(`[serve] listen`, default `:8090`) so it coexists with `harness events`.
Routes: `POST /v1/chat/completions`, `GET /v1/models`, `GET /healthz`.
- **Catalog = the class -> tier map**: every `[models.classes]` class is
served as model `mopac-<class>` (mopac-study, mopac-code, mopac-primary,
...); the request's model routes through the SAME tier table `once` uses
to a concrete proxy model. Unknown model = 400 naming the valid ones.
`[serve] enabled_models` optionally narrows the catalog (validated at
load).
- **Stateless bounded turns**: OWUI sends the full history each call; the
server runs ONE conductor turn over it (shared `runTurn` after a clean
refactor — `turn()` and `ServeTurn` both delegate; no copy-paste) and
returns the final text as a single assistant message + usage (summed over
rounds). No session storage. Client system message preserved verbatim; a
minimal vertical-identity system prompt is prepended only when the
history has none.
- **Auth**: Bearer vkey (`[serve] vkey_ref`, refs only, resolved at
startup), SHA-256 digest compare in constant time; missing/malformed/
wrong keys get one byte-identical generic 401; vkey never logged, never
in any response.
- **v0 knobs**: `temperature` + `max_tokens` forwarded upstream; `stream:
true` = explicit 400 (OWUI tolerates non-streaming providers); tools
OFF — a hallucinated tool call is refused as a tool result and counted,
never executed; upstream failures = terse 502 (bodies never forwarded).
- **dev.sh serve**: digest-pinned builder, host port 8090 published,
`HARNESS_SERVE_VKEY` / `HARNESS_LITELLM_KEY` passed through.
- **Tests**: scripted fake OpenAI upstream against the REAL server
(httptest): auth matrix (401 paths + no-leak), catalog + subset,
end-to-end chat (concrete model out, no tools on the wire, OpenAI
response shape, usage), history assembly both ways, multi-round usage
sums with refused tool-call feedback, knob forwarding, 400/502 table,
fail-fast construction. Loop-package tests cover ServeTurn prepend/
preserve/tools-off/knobs.
- **Live LAN proof (2026-08-29)**: port 8090, python urllib driver —
healthz 200, wrong key 401, catalog 200 (9 models), unknown model 400
naming them, stream 400, real turns through LiteLLM: `mopac-primary` ->
glm-5.3 (255 tokens) and `mopac-study` -> glm-4.7-flash (166 tokens),
audit lines clean.
Stubbed / Next:
- Streaming (SSE) on the serve door; tool use inside serve turns (gated
palette per vertical); per-connection vkeys via LiteLLM/keyproxy minting
(today one vkey per harness instance).
## Next chunk (phase 3)
1. bitwarden-go wrapper + `bw:` refs (unblocks secret posture).
@@ -199,5 +253,7 @@ the message was silently dropped).
3. Event → turn dispatch wiring: stored actionable events actually chain
conductor iterations for the affected stack.
4. Budget gate via LiteLLM spend APIs; cost line in REPORT.
5. Streaming with truncation retry + turn resume.
5. Streaming with truncation retry + turn resume (serve door SSE included).
6. Loop concurrency knob (in-process limit) once load justifies it.
7. Tool use inside serve turns (per-vertical gated palette) + per-connection
vkey minting.