Base URL (local dev): http://localhost:8085
Request body:
{ "sessionId": "s1", "latest": "How do Java records work?" }SSE event types (see SseConstants):
status→ shared status/error payload, used for progress and non-terminal warningsprovider→{"provider":"OpenAI"}(the shared LLM gateway selected for this request)text→{"text":"..."}citation→ JSON array of citationserror→ shared status/error payload for a terminal stream failure
status and error both serialize the payload fields below. The event type determines whether
the payload is a progress/warning notice or a terminal failure. Backend emission and frontend
validation each own the small declaration required at their transport boundary.
| Field | Meaning |
|---|---|
message |
Human-readable summary. |
details |
Additional diagnostic detail; it can be null. |
code |
Stable machine-readable status/error code. It can be null when no classification applies. Clients must branch on this field rather than the message text. |
retryable |
Whether a client may retry the operation. It can be null for ordinary progress notices. |
stage |
Pipeline stage associated with the notice or failure, such as citation or stream. It can be null for ordinary progress notices. |
Stream-provider error events populate code, retryable, and stage; a citation warning
emits the same metadata on a status event. Treat null metadata as absent.
The first event for POST /api/chat/stream and POST /api/guided/stream is a status event with
code: "stream.preparing" and stage: "retrieval". It confirms that the stream was admitted
before history and retrieval work begin; a later dependency failure still emits a terminal error
event.
While retrieval runs, the stream emits live status events for each retrieval step so clients can
show which step is in progress: first message: "Searching the Java documentation index" (embedding
and hybrid search across the indexed JDK documentation, books, and GitHub repositories), then
message: "Reviewing the top matches" (reranking) when the query path reranks. These progress
events carry message/details only (code, retryable, and stage are null) and always
arrive before the provider event.
Chat uses the shared OpenAI-compatible gateway with Claude Haiku 5.5 at low reasoning effort. An unavailable, rate-limited,
or failed gateway request terminates the stream with an error event; no alternate provider exists.
API responses include X-Request-ID, including security rejections and HTTP-200 SSE streams.
Application logs distinguish HTTP completion (api_request_completed) from a terminal SSE
error (search_stream_failed); HTTP 200 alone does not establish that the answer succeeded.
Embedding rate-limit records retain the upstream status, workload, model, gateway request ID,
and Retry-After when supplied. Missing retry timing does not replace the original provider cause.
An in-band Responses failure retains its finite terminalReason on the request-correlated log;
that protocol outcome is not reported as a transport HTTP 429.
POST /api/diagnostics/search-failures accepts bounded search-transport observations and returns
202. It requires the same CSRF protection as other browser POSTs. Reports identify the API path,
failure kind (HTTP, SSE, NETWORK, or PROTOCOL), optional HTTP status/request ID/error code/
retry timing, page path, loaded module asset, and elapsed milliseconds. URL queries, prompts,
cookies, authorization headers, and raw response bodies are not report fields and are not emitted into logs.
Browser reports use event=browser_search_failed and provenance=client_reported; they are not
verified server failures. A search failure sends one report without replaying the search. A failed
diagnostic submission remains console-visible and never recursively reports itself.
Example:
curl -N -H "Content-Type: application/json" \
-d '{"sessionId":"s1","latest":"Explain Java records"}' \
http://localhost:8085/api/chat/stream- GET
/api/chat/citations?q=... - GET
/api/chat/health/embeddings - POST
/api/chat/clear?sessionId=... - GET
/api/chat/session/validate?sessionId=... - GET
/api/chat/export/last?sessionId=... - GET
/api/chat/export/session?sessionId=... - GET
/api/chat/diagnostics/retrieval?q=...
- GET
/api/guided/toc - GET
/api/guided/lesson?slug=... - GET
/api/guided/citations?slug=... - GET
/api/guided/enrich?slug=... - GET
/api/guided/content/stream?slug=...(SSEtextevents, JSON-wrapped chunks) - GET
/api/guided/content?slug=...(JSON) - GET
/api/guided/content/html?slug=...(HTML) - POST
/api/guided/stream(SSE; request includessessionId,slug,latest)
- POST
/api/markdown/render - POST
/api/markdown/preview - POST
/api/markdown/render/structured - GET
/api/markdown/cache/stats - POST
/api/markdown/cache/clear
- GET
/api/enrich?q=... - GET
/api/chat/enrich?q=...(alias)
- GET
/api/knowledge/groups— lists every ingested document group (documentation-set tokens for the books/docs/articles/PDFs collections, repository URLs for indexed GitHub collections) with canonical source URLs, exact stored versions or revisions, and chunk counts. Requires authentication (Clerk session orak_API key); the response is{groups: [{collection, kind, name, canonicalUrls, ingestedVersions, chunks}], totalChunks}. A backing-store failure, unknown documentation source, or facet overflow returns HTTP 502 instead of an incomplete inventory.
- Available only outside the
prodprofile. - POST
/api/ingest?maxPages=... - POST
/api/ingest/local?dir=...&maxFiles=...