Move freshness surface to CultNet types
This commit is contained in:
parent
a3bca1c7fa
commit
37ea4ff2c3
6 changed files with 168 additions and 22 deletions
27
epiphany-codex-bridge/src/cultnet.rs
Normal file
27
epiphany-codex-bridge/src/cultnet.rs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
use epiphany_core::EpiphanyGraphFreshness;
|
||||
use epiphany_core::EpiphanyInvalidationInput;
|
||||
use epiphany_core::EpiphanyRetrievalFreshness;
|
||||
pub use epiphany_core::EpiphanyGraphFreshnessStatus;
|
||||
pub use epiphany_core::EpiphanyInvalidationStatus;
|
||||
pub use epiphany_core::EpiphanyRetrievalFreshnessStatus;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum EpiphanySurfaceSource {
|
||||
Stored,
|
||||
Live,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct EpiphanyFreshnessSurface {
|
||||
pub thread_id: String,
|
||||
pub source: EpiphanySurfaceSource,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub state_revision: Option<u64>,
|
||||
pub retrieval: EpiphanyRetrievalFreshness,
|
||||
pub graph: EpiphanyGraphFreshness,
|
||||
pub watcher: EpiphanyInvalidationInput,
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
pub mod checkpoint;
|
||||
pub mod context;
|
||||
pub mod coordinator;
|
||||
pub mod cultnet;
|
||||
pub mod error;
|
||||
pub mod invalidation;
|
||||
pub mod jobs;
|
||||
|
|
|
|||
|
|
@ -51,18 +51,26 @@ pub fn map_epiphany_freshness(
|
|||
ThreadEpiphanyGraphFreshness,
|
||||
ThreadEpiphanyInvalidationInput,
|
||||
) {
|
||||
let freshness = derive_epiphany_freshness_view(state, retrieval_override, watcher_snapshot);
|
||||
map_core_epiphany_freshness(freshness)
|
||||
}
|
||||
|
||||
pub fn derive_epiphany_freshness_view(
|
||||
state: Option<&EpiphanyThreadState>,
|
||||
retrieval_override: Option<&EpiphanyRetrievalState>,
|
||||
watcher_snapshot: Option<EpiphanyFreshnessWatcherSnapshot<'_>>,
|
||||
) -> EpiphanyFreshnessView {
|
||||
let watcher = watcher_snapshot.map(|snapshot| EpiphanyFreshnessWatcherInput {
|
||||
available: snapshot.available,
|
||||
workspace_root: snapshot.workspace_root,
|
||||
observed_at_unix_seconds: snapshot.observed_at_unix_seconds,
|
||||
changed_paths: snapshot.changed_paths,
|
||||
});
|
||||
let freshness = derive_freshness(EpiphanyFreshnessInput {
|
||||
derive_freshness(EpiphanyFreshnessInput {
|
||||
state,
|
||||
retrieval_override,
|
||||
watcher,
|
||||
});
|
||||
map_core_epiphany_freshness(freshness)
|
||||
})
|
||||
}
|
||||
|
||||
fn map_core_epiphany_freshness(
|
||||
|
|
|
|||
|
|
@ -20,10 +20,13 @@ use crate::coordinator::map_epiphany_coordinator_view;
|
|||
use crate::coordinator::map_epiphany_crrc_recommendation;
|
||||
use crate::coordinator::map_epiphany_roles;
|
||||
use crate::coordinator::render_epiphany_roles_note;
|
||||
use crate::cultnet::EpiphanyFreshnessSurface;
|
||||
use crate::cultnet::EpiphanySurfaceSource;
|
||||
use crate::jobs::map_epiphany_jobs;
|
||||
use crate::launch::EPIPHANY_REORIENT_LAUNCH_BINDING_ID;
|
||||
use crate::pressure::map_epiphany_pressure;
|
||||
use crate::reorient::EpiphanyFreshnessWatcherSnapshot;
|
||||
use crate::reorient::derive_epiphany_freshness_view;
|
||||
use crate::reorient::map_epiphany_freshness;
|
||||
use crate::reorient::map_epiphany_reorient;
|
||||
use crate::runtime_results::load_epiphany_reorient_result_snapshot;
|
||||
|
|
@ -77,25 +80,25 @@ pub struct EpiphanyFreshnessResponseInput<'a> {
|
|||
pub watcher_snapshot: Option<EpiphanyFreshnessWatcherSnapshot<'a>>,
|
||||
}
|
||||
|
||||
pub fn map_epiphany_freshness_response(
|
||||
pub fn derive_epiphany_freshness_surface(
|
||||
input: EpiphanyFreshnessResponseInput<'_>,
|
||||
) -> ThreadEpiphanyFreshnessResponse {
|
||||
let (state_revision, retrieval, graph, watcher) = map_epiphany_freshness(
|
||||
) -> EpiphanyFreshnessSurface {
|
||||
let freshness = derive_epiphany_freshness_view(
|
||||
input.state,
|
||||
input.retrieval_override,
|
||||
input.watcher_snapshot,
|
||||
);
|
||||
ThreadEpiphanyFreshnessResponse {
|
||||
EpiphanyFreshnessSurface {
|
||||
thread_id: input.thread_id,
|
||||
source: if input.loaded {
|
||||
ThreadEpiphanyFreshnessSource::Live
|
||||
EpiphanySurfaceSource::Live
|
||||
} else {
|
||||
ThreadEpiphanyFreshnessSource::Stored
|
||||
EpiphanySurfaceSource::Stored
|
||||
},
|
||||
state_revision,
|
||||
retrieval,
|
||||
graph,
|
||||
watcher,
|
||||
state_revision: freshness.state_revision,
|
||||
retrieval: freshness.retrieval,
|
||||
graph: freshness.graph,
|
||||
watcher: freshness.watcher,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,14 @@
|
|||
use epiphany_state_model::EpiphanyRetrievalState;
|
||||
use epiphany_state_model::EpiphanyRetrievalStatus;
|
||||
use epiphany_state_model::EpiphanyThreadState;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use std::collections::HashSet;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum EpiphanyRetrievalFreshnessStatus {
|
||||
Missing,
|
||||
Ready,
|
||||
|
|
@ -14,51 +17,69 @@ pub enum EpiphanyRetrievalFreshnessStatus {
|
|||
Unavailable,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct EpiphanyRetrievalFreshness {
|
||||
pub status: EpiphanyRetrievalFreshnessStatus,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub semantic_available: Option<bool>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub last_indexed_at_unix_seconds: Option<i64>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub indexed_file_count: Option<u32>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub indexed_chunk_count: Option<u32>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub dirty_paths: Vec<PathBuf>,
|
||||
pub note: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum EpiphanyGraphFreshnessStatus {
|
||||
Missing,
|
||||
Ready,
|
||||
Stale,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct EpiphanyGraphFreshness {
|
||||
pub status: EpiphanyGraphFreshnessStatus,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub graph_freshness: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub checkpoint_id: Option<String>,
|
||||
pub dirty_path_count: u32,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub dirty_paths: Vec<PathBuf>,
|
||||
pub open_question_count: u32,
|
||||
pub open_gap_count: u32,
|
||||
pub note: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum EpiphanyInvalidationStatus {
|
||||
Unavailable,
|
||||
Clean,
|
||||
Changed,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct EpiphanyInvalidationInput {
|
||||
pub status: EpiphanyInvalidationStatus,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub watched_root: Option<PathBuf>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub observed_at_unix_seconds: Option<i64>,
|
||||
pub changed_path_count: u32,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub changed_paths: Vec<PathBuf>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub graph_node_ids: Vec<String>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub active_frontier_node_ids: Vec<String>,
|
||||
pub note: String,
|
||||
}
|
||||
|
|
@ -78,8 +99,10 @@ pub struct EpiphanyFreshnessInput<'a> {
|
|||
pub watcher: Option<EpiphanyFreshnessWatcherInput<'a>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct EpiphanyFreshnessView {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub state_revision: Option<u64>,
|
||||
pub retrieval: EpiphanyRetrievalFreshness,
|
||||
pub graph: EpiphanyGraphFreshness,
|
||||
|
|
|
|||
|
|
@ -2,6 +2,11 @@ use codex_app_server_protocol::*;
|
|||
use codex_core::CodexThread;
|
||||
use codex_protocol::ThreadId;
|
||||
use codex_protocol::protocol::EpiphanyRetrievalState;
|
||||
use epiphany_codex_bridge::cultnet::EpiphanyFreshnessSurface;
|
||||
use epiphany_codex_bridge::cultnet::EpiphanyGraphFreshnessStatus;
|
||||
use epiphany_codex_bridge::cultnet::EpiphanyInvalidationStatus;
|
||||
use epiphany_codex_bridge::cultnet::EpiphanyRetrievalFreshnessStatus;
|
||||
use epiphany_codex_bridge::cultnet::EpiphanySurfaceSource;
|
||||
use epiphany_codex_bridge::invalidation::epiphany_freshness_watcher_snapshot;
|
||||
use epiphany_codex_bridge::launch::EPIPHANY_REORIENT_LAUNCH_BINDING_ID;
|
||||
use epiphany_codex_bridge::launch::epiphany_role_binding_id;
|
||||
|
|
@ -20,7 +25,7 @@ use epiphany_codex_bridge::view::epiphany_view_needs_reorientation_inputs;
|
|||
use epiphany_codex_bridge::view::epiphany_view_needs_runtime_store;
|
||||
use epiphany_codex_bridge::view::map_epiphany_context_response;
|
||||
use epiphany_codex_bridge::view::map_epiphany_distill_response;
|
||||
use epiphany_codex_bridge::view::map_epiphany_freshness_response;
|
||||
use epiphany_codex_bridge::view::derive_epiphany_freshness_surface;
|
||||
use epiphany_codex_bridge::view::map_epiphany_graph_query_response;
|
||||
use epiphany_codex_bridge::view::map_epiphany_propose_response;
|
||||
use epiphany_codex_bridge::view::map_epiphany_reorient_result_response;
|
||||
|
|
@ -261,7 +266,7 @@ impl CodexMessageProcessor {
|
|||
} else {
|
||||
None
|
||||
};
|
||||
let response = map_epiphany_freshness_response(EpiphanyFreshnessResponseInput {
|
||||
let surface = derive_epiphany_freshness_surface(EpiphanyFreshnessResponseInput {
|
||||
thread_id,
|
||||
loaded: loaded_thread.is_some(),
|
||||
state: thread.epiphany_state.as_ref(),
|
||||
|
|
@ -270,6 +275,7 @@ impl CodexMessageProcessor {
|
|||
.as_ref()
|
||||
.map(epiphany_freshness_watcher_snapshot),
|
||||
});
|
||||
let response = thread_epiphany_freshness_response_from_surface(surface);
|
||||
self.outgoing.send_response(request_id, response).await;
|
||||
}
|
||||
|
||||
|
|
@ -569,6 +575,84 @@ impl CodexMessageProcessor {
|
|||
}
|
||||
}
|
||||
|
||||
fn thread_epiphany_freshness_response_from_surface(
|
||||
surface: EpiphanyFreshnessSurface,
|
||||
) -> ThreadEpiphanyFreshnessResponse {
|
||||
ThreadEpiphanyFreshnessResponse {
|
||||
thread_id: surface.thread_id,
|
||||
source: match surface.source {
|
||||
EpiphanySurfaceSource::Stored => ThreadEpiphanyFreshnessSource::Stored,
|
||||
EpiphanySurfaceSource::Live => ThreadEpiphanyFreshnessSource::Live,
|
||||
},
|
||||
state_revision: surface.state_revision,
|
||||
retrieval: ThreadEpiphanyRetrievalFreshness {
|
||||
status: match surface.retrieval.status {
|
||||
EpiphanyRetrievalFreshnessStatus::Missing => {
|
||||
ThreadEpiphanyRetrievalFreshnessStatus::Missing
|
||||
}
|
||||
EpiphanyRetrievalFreshnessStatus::Ready => {
|
||||
ThreadEpiphanyRetrievalFreshnessStatus::Ready
|
||||
}
|
||||
EpiphanyRetrievalFreshnessStatus::Stale => {
|
||||
ThreadEpiphanyRetrievalFreshnessStatus::Stale
|
||||
}
|
||||
EpiphanyRetrievalFreshnessStatus::Indexing => {
|
||||
ThreadEpiphanyRetrievalFreshnessStatus::Indexing
|
||||
}
|
||||
EpiphanyRetrievalFreshnessStatus::Unavailable => {
|
||||
ThreadEpiphanyRetrievalFreshnessStatus::Unavailable
|
||||
}
|
||||
},
|
||||
semantic_available: surface.retrieval.semantic_available,
|
||||
last_indexed_at_unix_seconds: surface.retrieval.last_indexed_at_unix_seconds,
|
||||
indexed_file_count: surface.retrieval.indexed_file_count,
|
||||
indexed_chunk_count: surface.retrieval.indexed_chunk_count,
|
||||
dirty_paths: surface.retrieval.dirty_paths,
|
||||
note: surface.retrieval.note,
|
||||
},
|
||||
graph: ThreadEpiphanyGraphFreshness {
|
||||
status: match surface.graph.status {
|
||||
EpiphanyGraphFreshnessStatus::Missing => {
|
||||
ThreadEpiphanyGraphFreshnessStatus::Missing
|
||||
}
|
||||
EpiphanyGraphFreshnessStatus::Ready => {
|
||||
ThreadEpiphanyGraphFreshnessStatus::Ready
|
||||
}
|
||||
EpiphanyGraphFreshnessStatus::Stale => {
|
||||
ThreadEpiphanyGraphFreshnessStatus::Stale
|
||||
}
|
||||
},
|
||||
graph_freshness: surface.graph.graph_freshness,
|
||||
checkpoint_id: surface.graph.checkpoint_id,
|
||||
dirty_path_count: surface.graph.dirty_path_count,
|
||||
dirty_paths: surface.graph.dirty_paths,
|
||||
open_question_count: surface.graph.open_question_count,
|
||||
open_gap_count: surface.graph.open_gap_count,
|
||||
note: surface.graph.note,
|
||||
},
|
||||
watcher: ThreadEpiphanyInvalidationInput {
|
||||
status: match surface.watcher.status {
|
||||
EpiphanyInvalidationStatus::Unavailable => {
|
||||
ThreadEpiphanyInvalidationStatus::Unavailable
|
||||
}
|
||||
EpiphanyInvalidationStatus::Clean => {
|
||||
ThreadEpiphanyInvalidationStatus::Clean
|
||||
}
|
||||
EpiphanyInvalidationStatus::Changed => {
|
||||
ThreadEpiphanyInvalidationStatus::Changed
|
||||
}
|
||||
},
|
||||
watched_root: surface.watcher.watched_root,
|
||||
observed_at_unix_seconds: surface.watcher.observed_at_unix_seconds,
|
||||
changed_path_count: surface.watcher.changed_path_count,
|
||||
changed_paths: surface.watcher.changed_paths,
|
||||
graph_node_ids: surface.watcher.graph_node_ids,
|
||||
active_frontier_node_ids: surface.watcher.active_frontier_node_ids,
|
||||
note: surface.watcher.note,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
async fn thread_epiphany_retrieval_state(thread: &CodexThread) -> EpiphanyRetrievalState {
|
||||
let config = thread.config_snapshot().await;
|
||||
let codex_home = thread.codex_home().await;
|
||||
|
|
|
|||
Reference in a new issue