Skip to content

serve: report cached prompt tokens, llama.cpp timings and GET /v1/status - #107

Merged
Niko1221 merged 1 commit into
Niko1221:mainfrom
architectds:api-status
Sep 29, 2026
Merged

Niko1221 merged 1 commit into
Niko1221:mainfrom
architectds:api-status

Conversation

@architectds

Copy link
Copy Markdown
Contributor

The conversation cache reuses prompt prefixes, and /metrics already records the reuse per request. But the chat APIs don't report it, so clients show a cached prompt as 0% cached. Front-ends that read speed from llama.cpp's timings show nothing.

This PR adds the missing fields and changes nothing else in the replies:

  • OpenAI (/v1/chat/completions): usage.prompt_tokens_details.cached_tokens is the part of the prompt the conversation cache held. It's on the last streamed chunk and on a whole reply.

  • Anthropic (/v1/messages): the final usage splits input_tokens from cache_read_input_tokens, the way Anthropic's API counts them. That's the stream's message_delta and a whole reply. message_start still carries the whole prompt, the only count known before the engine reads it.

  • llama.cpp's timings go on the last chunk and on a whole reply: prompt_n, cache_n, prompt_ms, prompt_per_second, predicted_n, predicted_ms, predicted_per_second and the per-token ms. They come from the engine's own clock, the same numbers /metrics shows.

  • GET /v1/status is a small read-only summary for front-ends that poll their server rather than guess. It's behind the API key when one is set. It gives:

    • the model and its context window;
    • images, and the APIs served;
    • whether a request is running;
    • the last request's timings;
    • the GPU and RAM, from the telemetry.

    The Monitor's /metrics is unchanged.

An engine without a clock (the mock engine) reports no timings and 0 cached tokens.

Tested:

  • python -m unittest serve.test_server serve.test_mcp passes. The new UsageAndStatus class covers both APIs, streaming, /v1/status and the no-clock case.
  • Live on an A100-40G on Linux (Colab, a 0.1.20 build with the same change):
    • a second turn reported cached_tokens: 2784, with timings cache_n: 2784, prompt_n: 20;
    • a front-end read the new /v1/status for its speed panel and for image upload.

…/status

The conversation cache's reuse is kept per request (GET /metrics shows it),
but the APIs did not report it, so clients showed a cached prompt as 0%:

- OpenAI: usage.prompt_tokens_details.cached_tokens, streamed and not.
- Anthropic: the final usage splits input_tokens from
  cache_read_input_tokens (message_start can only know the whole prompt).
- llama.cpp's `timings` block on the last chunk and on a whole reply
  (prompt_n, cache_n, prompt/predicted ms and per second), from the
  engine's own clock: what llama.cpp's clients already show as speed.
- GET /v1/status (with the API key when one is set): the model and its
  window, images, the APIs, whether a request is running, the last
  request's timings and the GPU and RAM from the telemetry, for a
  front-end that polls its server rather than guessing.

An engine without a clock (MockEngine) reports no timings and 0 cached.
Tests: serve/test_server.py UsageAndStatus.
architectds added a commit to architectds/collabosm that referenced this pull request Sep 29, 2026
…load

Measured on the A100-40G on 2026-09-29. Prefill on real text (code and
prose) was 240-410 t/s: the GPU sat idle 72% of each prompt while Strata
read its n-gram table, 16 random 4 KB O_DIRECT reads a token, from Colab's
PersistentDisk (~2,500 reads/s whatever the queue depth). /content is
overlayfs on a loop device that caches its backing file (dio=0). A
buffered read caches the table twice and evicts itself, but one O_DIRECT
pass leaves it in RAM once. strata_warm does that pass after every engine
start (serve.sh), about 90 s in the background.

- Prefill is now 905 / 1,202 / 1,301 / 1,376 t/s at 4K / 18K / 28K / 59K.
- Decode went from 42 to 61 t/s (66 after a 34K prompt, 72 on a next turn).
- STRATA_PREFILL_TIMING puts the rest in Strata's GPU kernels: at 33K,
  QSA attention 36%, GDN 17%, the MoE 27% (waiting on PCIe 3%).
- 16K prompt chunks were measured slower below 30K, so the recipe keeps
  Strata's own flags. STRATA_ENGINE_ARGS can still change them per recipe.

The recipe now runs the fork's r2 engine, whose image encoder read a test
picture right. It pins fd1e7d9, where Strata's server reports cached
prompt tokens, llama.cpp timings and GET /v1/status (sent upstream as
Niko1221/Strata#107). The speed rail, /props image upload and the idle
clock now work as they do for ExLlamaV3.

strata_weights fetches the GGUF and the image encoder at the model's
pinned revision with Xet, with setup.py's .done marks: 84.5 GB in 413 s,
where setup.py's one stream per file took most of a 22-minute start.
READY now takes 19 min 46 s.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Niko1221

Copy link
Copy Markdown
Owner

Thanks @architectds - merged into the 0.1.23 branch, after #122 (both added GET routes; kept /models, /props, /slots and your /v1/status). I also added #83's draft counts (draft_n, draft_n_accepted) to your timings with a test. It ships with 0.1.23 after the gate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants