Three-way concurrent retrieval (directive Redis, hot memories HTTP, cold search HTTP) with per-branch timeouts, outer IBEX_CONTEXT_TIMEOUT (45ms) fail-open, and history_tokens from request recent_messages.
Milestone 3.5.C.2 — Parallel Retrieval Orchestration
Status: Completed
Goal: Track C — Context Assembly Engine
Phase: 3.5 — Extraction & Context Assembly
Estimated effort: 3 days
Track: Track C — Context Assembly Engine
Depends on: 3.5.C.1, Phase 3 exit (HNSW vector store)
Why This Milestone Exists
The Phase 3 Track B work already specified the ContextRetriever.retrieve() component well — launching directive/hot-cache/embedding concurrently via asyncio.gather(..., return_exceptions=True), only starting cold search once the query embedding is ready, merging and deduplicating hot/cold results. This milestone wires it into the assembly pipeline directly and adds the pieces the original spec left implicit.
Non-Goals
- Scoring and ranking (3.5.C.3)
- Packing (3.5.C.4)
- gRPC
ContextAssemblyServicewiring (3.5.C.6) - Postgres/session-checkpoint history fetch (impossible — see Additions §1)
Orientation (indicative)
Named paths, package layouts, libraries, schemas, env vars, and commands anywhere on this page are rough sketches for orientation — inspiration and a baseline, not a required change list.
During implementation, expect to:
- open the live tree and follow existing patterns before inventing new ones
- research current constraints (latency, tenancy, deploy shape, libraries) more deeply than this page can
- advance the design beyond the sketch where measurement or code reality says so
- land work in different filenames, merged packages, deferred docs, or new surfaces when the situation calls for it
Prefer outcomes over matching any particular file tree or command sequence.
Areas that may be involved (situational — not a checklist):
- Context assembly library (
services/context) - Memory hot-cache HTTP surface
- Token budget calculator (3.5.C.1)
Suggested naming (provisional)
Rename freely to match the change that actually lands.
- Branch:
feature/m3-5-c2-parallel-retrieval - PR title:
feat(context): parallel retrieval orchestration with three-way concurrency (m3.5.C.2)
Additions on Top of the Existing Retriever Design
1. History is request input — not a fourth I/O branch (correction)
An earlier sketch proposed a fourth concurrent history_task reading conversation text from the
session-checkpoint store. That branch must not be implemented:
AssembleContextRequest.recent_messagesalready carries history (zero I/O).ibex_core.checkpointsstoresmessages_hashonly — not message text.packages/session.Storehas no history-read API (proxy owns session checkpoints).
Fix: treat recent_messages as already-available input; count tokens into history_tokens
via BudgetCalculator (3.5.C.1). The orchestrator has exactly three concurrent I/O branches:
directive (Redis cache envelope), hot memories (GET /v1/memories/hot), and cold search
(POST /v1/memories/search, which embeds server-side — context must not pre-embed).
2. Outer deadline + per-branch timeouts
IBEX_CONTEXT_TIMEOUT defaults to 45ms (fail-open). Directive (~5ms) and hot (~15ms) use
tighter budgets; cold uses the outer budget and often times out when the embedder is 100–500ms —
partial results (directive + hot) are the intended degradation.
3. Tenant scoping enforced at the data layer
Every hot-cache key and cold-search query is namespaced ({org_id}:hot_memories:{agent_id}) /
filtered by token org_id. Directive Redis keys use {org_id}:directive:{agent_id}.
4. RetrievalResult (internal Python; proto mapping deferred to 3.5.C.6)
@dataclass
class RetrievalResult:
directive: ResolvedDirective | None
directive_outcome: BranchOutcome
hot_memories: list[MemoryHit]
hot_outcome: BranchOutcome
cold_memories: list[MemoryHit]
cold_outcome: BranchOutcome
recent_messages: list[Message]
history_tokens: int
sources_available: frozenset[str] # subset of {"directive","hot","cold"}Success signals
Outcome-oriented signals that the milestone is in good shape. Exact filenames, package layouts, and commands may differ from any sketches above.
- Three-way concurrent retrieval (directive, hot memories, cold search — cold embeds server-side)
- Each branch has its own timeout; total wall-clock bounded by outer
IBEX_CONTEXT_TIMEOUT(45ms) -
RetrievalResultwithhistory_tokens/recent_messages(not a Postgres history fetch) - Integration test: memory HTTP failure / timeout → retriever returns partial results without crashing
Last updated on