Split retrieval protocol projection

This commit is contained in:
Meta Vens 2026-05-20 15:08:06 +01:00
commit d32136531a
8 changed files with 95 additions and 83 deletions

View file

@ -15,6 +15,7 @@ pub mod protocol_edge;
pub mod reorient;
pub mod results;
pub mod retrieve;
pub mod retrieve_protocol;
pub mod runtime_results;
pub mod scene;
pub mod scene_protocol;

View file

@ -1,14 +1,5 @@
use codex_app_server_protocol::ThreadEpiphanyIndexResponse;
use codex_app_server_protocol::ThreadEpiphanyRetrieveIndexSummary;
use codex_app_server_protocol::ThreadEpiphanyRetrieveResponse;
use codex_app_server_protocol::ThreadEpiphanyRetrieveResult;
use codex_app_server_protocol::ThreadEpiphanyRetrieveResultKind;
use codex_app_server_protocol::ThreadEpiphanyRetrieveShardSummary;
use codex_utils_absolute_path::AbsolutePathBuf;
use epiphany_core::EpiphanyRetrieveQuery;
use epiphany_core::EpiphanyRetrieveResponse as CoreEpiphanyRetrieveResponse;
use epiphany_core::EpiphanyRetrieveResult as CoreEpiphanyRetrieveResult;
use epiphany_core::EpiphanyRetrieveResultKind as CoreEpiphanyRetrieveResultKind;
use epiphany_core::index_workspace;
use epiphany_core::normalize_epiphany_retrieve_query;
use epiphany_core::retrieval_state_for_workspace;
@ -16,30 +7,12 @@ use epiphany_core::retrieve_workspace;
use epiphany_state_model::EpiphanyRetrievalState;
use std::path::PathBuf;
pub fn map_epiphany_retrieve_response(
response: CoreEpiphanyRetrieveResponse,
) -> anyhow::Result<ThreadEpiphanyRetrieveResponse> {
Ok(ThreadEpiphanyRetrieveResponse {
query: response.query,
index_summary: map_epiphany_retrieve_index_summary(response.index_summary)?,
results: response
.results
.into_iter()
.map(map_epiphany_retrieve_result)
.collect(),
})
}
pub async fn index_epiphany_retrieval_for_paths(
workspace_root: PathBuf,
codex_home: PathBuf,
force_full_rebuild: bool,
) -> anyhow::Result<ThreadEpiphanyIndexResponse> {
let index_summary =
index_epiphany_retrieval_state_for_paths(workspace_root, codex_home, force_full_rebuild)
.await
.and_then(map_epiphany_retrieve_index_summary)?;
Ok(ThreadEpiphanyIndexResponse { index_summary })
) -> anyhow::Result<EpiphanyRetrievalState> {
index_epiphany_retrieval_state_for_paths(workspace_root, codex_home, force_full_rebuild).await
}
pub fn normalize_thread_epiphany_retrieve_query(
@ -88,55 +61,3 @@ pub async fn retrieve_epiphany_for_paths(
.await
.map_err(|err| anyhow::anyhow!("epiphany retrieval worker failed: {err}"))?
}
pub fn map_epiphany_retrieve_index_summary(
summary: EpiphanyRetrievalState,
) -> anyhow::Result<ThreadEpiphanyRetrieveIndexSummary> {
Ok(ThreadEpiphanyRetrieveIndexSummary {
workspace_root: AbsolutePathBuf::from_absolute_path(summary.workspace_root)
.map_err(anyhow::Error::from)?,
index_revision: summary.index_revision,
status: summary.status,
semantic_available: summary.semantic_available,
last_indexed_at_unix_seconds: summary.last_indexed_at_unix_seconds,
indexed_file_count: summary.indexed_file_count,
indexed_chunk_count: summary.indexed_chunk_count,
shards: summary
.shards
.into_iter()
.map(|shard| ThreadEpiphanyRetrieveShardSummary {
shard_id: shard.shard_id,
path_prefix: shard.path_prefix,
indexed_file_count: shard.indexed_file_count,
indexed_chunk_count: shard.indexed_chunk_count,
status: shard.status,
exact_available: shard.exact_available,
semantic_available: shard.semantic_available,
})
.collect(),
dirty_paths: summary.dirty_paths,
})
}
fn map_epiphany_retrieve_result(
result: CoreEpiphanyRetrieveResult,
) -> ThreadEpiphanyRetrieveResult {
ThreadEpiphanyRetrieveResult {
kind: match result.kind {
CoreEpiphanyRetrieveResultKind::ExactFile => {
ThreadEpiphanyRetrieveResultKind::ExactFile
}
CoreEpiphanyRetrieveResultKind::ExactDirectory => {
ThreadEpiphanyRetrieveResultKind::ExactDirectory
}
CoreEpiphanyRetrieveResultKind::SemanticChunk => {
ThreadEpiphanyRetrieveResultKind::SemanticChunk
}
},
path: result.path,
score: result.score,
line_start: result.line_start,
line_end: result.line_end,
excerpt: result.excerpt,
}
}

View file

@ -0,0 +1,83 @@
use codex_app_server_protocol::ThreadEpiphanyIndexResponse;
use codex_app_server_protocol::ThreadEpiphanyRetrieveIndexSummary;
use codex_app_server_protocol::ThreadEpiphanyRetrieveResponse;
use codex_app_server_protocol::ThreadEpiphanyRetrieveResult;
use codex_app_server_protocol::ThreadEpiphanyRetrieveResultKind;
use codex_app_server_protocol::ThreadEpiphanyRetrieveShardSummary;
use codex_utils_absolute_path::AbsolutePathBuf;
use epiphany_core::EpiphanyRetrieveResponse as CoreEpiphanyRetrieveResponse;
use epiphany_core::EpiphanyRetrieveResult as CoreEpiphanyRetrieveResult;
use epiphany_core::EpiphanyRetrieveResultKind as CoreEpiphanyRetrieveResultKind;
use epiphany_state_model::EpiphanyRetrievalState;
pub fn protocol_retrieve_response(
response: CoreEpiphanyRetrieveResponse,
) -> anyhow::Result<ThreadEpiphanyRetrieveResponse> {
Ok(ThreadEpiphanyRetrieveResponse {
query: response.query,
index_summary: protocol_retrieve_index_summary(response.index_summary)?,
results: response
.results
.into_iter()
.map(protocol_retrieve_result)
.collect(),
})
}
pub fn protocol_index_response(
index_summary: EpiphanyRetrievalState,
) -> anyhow::Result<ThreadEpiphanyIndexResponse> {
Ok(ThreadEpiphanyIndexResponse {
index_summary: protocol_retrieve_index_summary(index_summary)?,
})
}
pub fn protocol_retrieve_index_summary(
summary: EpiphanyRetrievalState,
) -> anyhow::Result<ThreadEpiphanyRetrieveIndexSummary> {
Ok(ThreadEpiphanyRetrieveIndexSummary {
workspace_root: AbsolutePathBuf::from_absolute_path(summary.workspace_root)
.map_err(anyhow::Error::from)?,
index_revision: summary.index_revision,
status: summary.status,
semantic_available: summary.semantic_available,
last_indexed_at_unix_seconds: summary.last_indexed_at_unix_seconds,
indexed_file_count: summary.indexed_file_count,
indexed_chunk_count: summary.indexed_chunk_count,
shards: summary
.shards
.into_iter()
.map(|shard| ThreadEpiphanyRetrieveShardSummary {
shard_id: shard.shard_id,
path_prefix: shard.path_prefix,
indexed_file_count: shard.indexed_file_count,
indexed_chunk_count: shard.indexed_chunk_count,
status: shard.status,
exact_available: shard.exact_available,
semantic_available: shard.semantic_available,
})
.collect(),
dirty_paths: summary.dirty_paths,
})
}
fn protocol_retrieve_result(result: CoreEpiphanyRetrieveResult) -> ThreadEpiphanyRetrieveResult {
ThreadEpiphanyRetrieveResult {
kind: match result.kind {
CoreEpiphanyRetrieveResultKind::ExactFile => {
ThreadEpiphanyRetrieveResultKind::ExactFile
}
CoreEpiphanyRetrieveResultKind::ExactDirectory => {
ThreadEpiphanyRetrieveResultKind::ExactDirectory
}
CoreEpiphanyRetrieveResultKind::SemanticChunk => {
ThreadEpiphanyRetrieveResultKind::SemanticChunk
}
},
path: result.path,
score: result.score,
line_start: result.line_start,
line_end: result.line_end,
excerpt: result.excerpt,
}
}

View file

@ -90,6 +90,7 @@ remembers doctrine; the branch remembers the blade.
- Coordinator projection is split out too. `coordinator.rs` no longer imports app-server protocol DTOs; it owns typed coordinator status, CRRC input shaping, role-board derivation, automation verdict selection, and note rendering. `coordinator_protocol.rs` owns Codex JSON-RPC projection for coordinator, CRRC, and role-board response payloads.
- Context/planning/graph projection is split out too. `context.rs` returns typed `epiphany-core` view documents; `context_protocol.rs` owns Codex JSON-RPC tuple/projection cargo for context, planning, and graph-query responses.
- Scene projection is split out too. `scene.rs` returns the typed core `EpiphanyScene`; `scene_protocol.rs` owns `ThreadEpiphanyScene` and scene-action response projection.
- Retrieval projection is split out too. `retrieve.rs` normalizes, indexes, looks up state, and retrieves typed core results; `retrieve_protocol.rs` owns Codex JSON-RPC retrieve/index response projection and absolute-path DTO validation.
- MCP remains JSON because MCP is a JSON protocol. The latest processor cut only moved MCP refresh/OAuth/status/resource/tool-call route handling into `codex_message_processor/mcp_routes.rs`, reducing the root processor to about 8,977 lines; it did not claim MCP payloads are CultNet or make MCP an Epiphany-owned runtime contract.
- Codex account auth route handling remains in vendored Codex but now lives in `codex_message_processor/auth_routes.rs`: API-key login, ChatGPT browser/device-code/external-token login, logout, auth status, account, rate limits, and add-credits nudge handling. This preserves Codex ownership of subscription auth while cutting the root processor to about 8,094 lines.
- One-off command execution and command stream write/resize/terminate route handling now live in `codex_message_processor/command_routes.rs`; `CommandExecManager` remains the lifecycle owner, while the root processor is about 7,800 lines.

Binary file not shown.

View file

@ -439,6 +439,10 @@ current_status:
Scene derivation follows that boundary too: `scene.rs` now returns the
typed core `EpiphanyScene`, and `scene_protocol.rs` owns projection into
`ThreadEpiphanyScene` plus scene-action DTOs for view responses.
Retrieval follows the boundary too: `retrieve.rs` executes normalization,
indexing, state lookup, and typed retrieval responses; `retrieve_protocol.rs`
owns Codex JSON-RPC retrieve/index response projection and absolute-path DTO
validation.
The bridge still depends on vendored Codex for app-server protocol DTOs and
absolute path validation, so the purification is not done.
next_action: Continue Codex starvation and CultNet liberation by cutting bridge-internal response/projection authority. Prioritize the next coordinator/view seam that still composes policy-shaped facts instead of merely loading host facts and projecting core surfaces; keep MCP/OpenAI JSON only at their true protocol/text edges. Do not add compatibility adapters unless they protect a named ownership invariant.

View file

@ -32,6 +32,7 @@ use epiphany_codex_bridge::protocol_edge::protocol_update_patch_to_core;
use epiphany_codex_bridge::protocol_edge::protocol_worker_launch_document_to_core;
use epiphany_codex_bridge::retrieve::epiphany_retrieval_state_for_paths;
use epiphany_codex_bridge::retrieve::index_epiphany_retrieval_for_paths;
use epiphany_codex_bridge::retrieve_protocol::protocol_index_response;
use std::sync::Arc;
use super::CodexMessageProcessor;
@ -440,6 +441,7 @@ impl CodexMessageProcessor {
force_full_rebuild,
)
.await
.and_then(protocol_index_response)
{
Ok(response) => response,
Err(err) => {

View file

@ -18,9 +18,9 @@ use epiphany_codex_bridge::protocol_edge::protocol_graph_query_to_core;
use epiphany_codex_bridge::protocol_edge::protocol_role_id_to_core;
use epiphany_codex_bridge::protocol_edge::protocol_view_lenses_to_core;
use epiphany_codex_bridge::retrieve::epiphany_retrieval_state_for_paths;
use epiphany_codex_bridge::retrieve::map_epiphany_retrieve_response;
use epiphany_codex_bridge::retrieve::normalize_thread_epiphany_retrieve_query;
use epiphany_codex_bridge::retrieve::retrieve_epiphany_for_paths;
use epiphany_codex_bridge::retrieve_protocol::protocol_retrieve_response;
use epiphany_codex_bridge::view::EpiphanyFreshnessResponseInput;
use epiphany_codex_bridge::view::EpiphanyReorientResultResponseInput;
use epiphany_codex_bridge::view::EpiphanyRoleResultResponseInput;
@ -460,7 +460,7 @@ impl CodexMessageProcessor {
let response =
match retrieve_epiphany_for_paths(config.cwd.to_path_buf(), codex_home, query)
.await
.and_then(map_epiphany_retrieve_response)
.and_then(protocol_retrieve_response)
{
Ok(response) => response,
Err(err) => {