Real Gralkor.Client implementation over HTTP using Req.
Reads config from Application.get_env(:gralkor_ex, :client_http):
:url— required. Base URL of the Gralkor server (e.g."http://127.0.0.1:4000").:plug— optionalReq.Testplug tuple for stubbing in tests. Unset in production so Req hits the network directly.
No auth: Gralkor is expected to run under the consumer app's supervision tree, bound to loopback. The consumer owns the trust boundary.
Per-endpoint receive_timeouts, calibrated to the workload. 429 retry
ownership for Vertex-upstream rate-limits lives inside /recall on
the server — see gralkor/TEST_TREES.md > Retry ownership. No layer
above the server retries this class. Under sustained Vertex throttling
/recall returns 429 (for exhausted retries) or 504 (for deadline);
the consumer's jido_gralkor plugin then degrades gracefully to a
memory-less turn.
/health(2 s) — cheap liveness check; tight soGralkor.Connectiondoesn't flap when the server is under LLM load./recall(12 s) — matches the server's/recalldeadline. The server body runs graph search (graphiti.search()— RRF, edges only, calls the embedder) plusinterpret_facts, with one 429 retry absorbed internally inside the 12 s budget. Tight — a server-side 504 may race the transport; revisit if it bites./tools/memory_search(30 s) — slow graph search (graphiti.search_()withCOMBINED_HYBRID_SEARCH_CROSS_ENCODER— cross-encoder reranking + BFS) plusinterpret_facts. More upstream work per call than/recall; sized a few seconds higher./capture(5 s) — server returns 204 immediately after buffering. No synchronous LLM call here; the flush runs in the server-side capture buffer (its own retry schedule)./session_end(5 s) — server returns 204 immediately after scheduling the flush./tools/memory_add(60 s) — Graphiti entity/edge extraction is slow; only reached from a backgroundTaskin the consumer, so the agent never waits./build-indices,/build-communities(:infinity) — admin operations that scan the whole graph; can run for minutes to hours on a populated database. The operator invokes them explicitly, so blocking the caller is fine.
Returns {:error, reason} on non-2xx or transport failure; raises on
missing config or blank session_id. Callers let those surface.