Problem
guides/serve-over-http.mdx shows only a string message and never says a string is all the surface
takes. The Python API documents richer input on the same underlying methods, so a reader reasonably
expects parity and gets a 422:
$ curl -X POST .../agents/HandoverBot/chat \
-d '{"session_id":"s1","message":[{"type":"text","text":"hi"}]}'
422 {"detail": "message must be a string, got list"}
Meanwhile reference/deck.mdx lists TextBlock/ImageBlock/AudioBlock/DataBlock/ResourceBlock
under What input accepts for run/stream — the methods the HTTP route calls. A clean-room
reviewer recorded parity as an explicit expectation during recon and found the gap only by testing it.
Proof of absence:
$ grep -rni "content.block\|ImageBlock\|content_blocks" docs/ README.md
docs/reference/deck.mdx: (3 hits)
Nothing in guides/serve-over-http.mdx.
The behavior itself is correct and deliberate — the v1 chat body is exactly {"session_id", "message"},
frozen byte-for-byte by tests/golden/ (see #227). This is the docs half only: images and audio are
Python-API-only, and the guide should say so where someone plans an integration rather than leaving it
to a 422.
Proposed shape
One short subsection in guides/serve-over-http.mdx, next to the first chat example:
### What the wire accepts
`message` is a string. The packaged surface is the frozen v1 body — `{"session_id", "message"}` —
so the content blocks the Python API accepts (`ImageBlock`, `AudioBlock`, ...) do not cross it, and
a list is refused with `422 message must be a string`. An application that needs rich input calls
`deck.run()` / `deck.stream()` from its own route.
And a matching line in reference/deck.mdx where the block list is introduced, saying which of those
blocks reach the packaged HTTP surface (none) — the page currently qualifies the list for the engine
but not for the wire.
Out of scope: changing the wire (frozen) and the design question of what asgi() is for (#227).
Notes
Done when
Problem
guides/serve-over-http.mdxshows only a stringmessageand never says a string is all the surfacetakes. The Python API documents richer input on the same underlying methods, so a reader reasonably
expects parity and gets a 422:
Meanwhile
reference/deck.mdxlistsTextBlock/ImageBlock/AudioBlock/DataBlock/ResourceBlockunder What
inputaccepts forrun/stream— the methods the HTTP route calls. A clean-roomreviewer recorded parity as an explicit expectation during recon and found the gap only by testing it.
Proof of absence:
Nothing in
guides/serve-over-http.mdx.The behavior itself is correct and deliberate — the v1 chat body is exactly
{"session_id", "message"},frozen byte-for-byte by
tests/golden/(see #227). This is the docs half only: images and audio arePython-API-only, and the guide should say so where someone plans an integration rather than leaving it
to a 422.
Proposed shape
One short subsection in
guides/serve-over-http.mdx, next to the first chat example:And a matching line in
reference/deck.mdxwhere the block list is introduced, saying which of thoseblocks reach the packaged HTTP surface (none) — the page currently qualifies the list for the engine
but not for the wire.
Out of scope: changing the wire (frozen) and the design question of what
asgi()is for (#227).Notes
(DataBlock refused on input) is the engine-side sibling. Neither covers the guide's silence.
--help).Done when
guides/serve-over-http.mdxstatesmessageis string-only and why, naming the 422deck.run/deck.streamreference/deck.mdx's block list says which blocks reach the packaged HTTP surfacetests/golden/untouched