This repository has been archived on 2026-10-29. You can view files and clone it, but you cannot make any changes to its state, such as pushing and creating new issues, pull requests or comments.
Epiphany/epiphany-codex-bridge/src/protocol_edge.rs
2026-05-20 13:50:45 +01:00

490 lines
22 KiB
Rust

use crate::cultnet::EpiphanyFreshnessSurface;
use crate::cultnet::EpiphanyGraphFreshnessStatus;
use crate::cultnet::EpiphanyInvalidationStatus;
use crate::cultnet::EpiphanyJobKind;
use crate::cultnet::EpiphanyJobStatus;
use crate::cultnet::EpiphanyJobView;
use crate::cultnet::EpiphanyReorientAction;
use crate::cultnet::EpiphanyReorientCheckpointStatus;
use crate::cultnet::EpiphanyReorientDecision;
use crate::cultnet::EpiphanyReorientFreshnessStatus;
use crate::cultnet::EpiphanyReorientPressureLevel;
use crate::cultnet::EpiphanyReorientReason;
use crate::cultnet::EpiphanyReorientStateStatus;
use crate::cultnet::EpiphanyRetrievalFreshnessStatus;
use crate::cultnet::EpiphanySurfaceSource;
use codex_app_server_protocol::ThreadEpiphanyContextParams;
use codex_app_server_protocol::ThreadEpiphanyDistillParams;
use codex_app_server_protocol::ThreadEpiphanyFreshnessResponse;
use codex_app_server_protocol::ThreadEpiphanyFreshnessSource;
use codex_app_server_protocol::ThreadEpiphanyGraphFreshness;
use codex_app_server_protocol::ThreadEpiphanyGraphFreshnessStatus;
use codex_app_server_protocol::ThreadEpiphanyGraphQuery;
use codex_app_server_protocol::ThreadEpiphanyGraphQueryDirection;
use codex_app_server_protocol::ThreadEpiphanyGraphQueryKind;
use codex_app_server_protocol::ThreadEpiphanyInvalidationInput;
use codex_app_server_protocol::ThreadEpiphanyInvalidationStatus;
use codex_app_server_protocol::ThreadEpiphanyJob;
use codex_app_server_protocol::ThreadEpiphanyJobKind;
use codex_app_server_protocol::ThreadEpiphanyJobStatus;
use codex_app_server_protocol::ThreadEpiphanyPressureLevel;
use codex_app_server_protocol::ThreadEpiphanyReorientAction;
use codex_app_server_protocol::ThreadEpiphanyReorientCheckpointStatus;
use codex_app_server_protocol::ThreadEpiphanyReorientDecision;
use codex_app_server_protocol::ThreadEpiphanyReorientReason;
use codex_app_server_protocol::ThreadEpiphanyReorientSource;
use codex_app_server_protocol::ThreadEpiphanyReorientStateStatus;
use codex_app_server_protocol::ThreadEpiphanyReorientWorkerLaunchDocument;
use codex_app_server_protocol::ThreadEpiphanyRetrievalFreshness;
use codex_app_server_protocol::ThreadEpiphanyRetrievalFreshnessStatus;
use codex_app_server_protocol::ThreadEpiphanyRoleWorkerLaunchDocument;
use codex_app_server_protocol::ThreadEpiphanyUpdatePatch;
use codex_app_server_protocol::ThreadEpiphanyViewLens;
use codex_app_server_protocol::ThreadEpiphanyWorkerLaunchDocument;
use epiphany_core::EpiphanyContextParams;
use epiphany_core::EpiphanyDistillInput;
use epiphany_core::EpiphanyGraphQuery;
use epiphany_core::EpiphanyGraphQueryDirection;
use epiphany_core::EpiphanyGraphQueryKind;
use epiphany_core::EpiphanyReorientWorkerLaunchDocument;
use epiphany_core::EpiphanyRoleStatePatchDocument;
use epiphany_core::EpiphanyRoleWorkerLaunchDocument;
use epiphany_core::EpiphanyViewLens;
use epiphany_core::EpiphanyWorkerLaunchDocument;
use epiphany_core::default_epiphany_view_lenses;
use epiphany_core::epiphany_view_needs_jobs;
use epiphany_core::epiphany_view_needs_pressure;
use epiphany_core::epiphany_view_needs_reorientation_inputs;
use epiphany_core::epiphany_view_needs_runtime_store;
pub fn default_core_epiphany_view_lenses() -> Vec<EpiphanyViewLens> {
default_epiphany_view_lenses()
}
pub fn protocol_view_lenses_to_core(lenses: Vec<ThreadEpiphanyViewLens>) -> Vec<EpiphanyViewLens> {
lenses.into_iter().map(protocol_view_lens_to_core).collect()
}
pub fn core_epiphany_view_needs_jobs(lenses: &[EpiphanyViewLens]) -> bool {
epiphany_view_needs_jobs(lenses)
}
pub fn core_epiphany_view_needs_reorientation_inputs(lenses: &[EpiphanyViewLens]) -> bool {
epiphany_view_needs_reorientation_inputs(lenses)
}
pub fn core_epiphany_view_needs_pressure(lenses: &[EpiphanyViewLens]) -> bool {
epiphany_view_needs_pressure(lenses)
}
pub fn core_epiphany_view_needs_runtime_store(lenses: &[EpiphanyViewLens]) -> bool {
epiphany_view_needs_runtime_store(lenses)
}
pub fn protocol_context_params_to_core(
params: &ThreadEpiphanyContextParams,
) -> EpiphanyContextParams {
EpiphanyContextParams {
graph_node_ids: params.graph_node_ids.clone(),
graph_edge_ids: params.graph_edge_ids.clone(),
observation_ids: params.observation_ids.clone(),
evidence_ids: params.evidence_ids.clone(),
include_active_frontier: params.include_active_frontier,
include_linked_evidence: params.include_linked_evidence,
}
}
pub fn protocol_distill_params_to_core(
params: ThreadEpiphanyDistillParams,
) -> EpiphanyDistillInput {
let ThreadEpiphanyDistillParams {
source_kind,
status,
text,
subject,
evidence_kind,
code_refs,
..
} = params;
EpiphanyDistillInput {
source_kind,
status,
text,
subject,
evidence_kind,
code_refs,
}
}
pub fn protocol_graph_query_to_core(query: &ThreadEpiphanyGraphQuery) -> EpiphanyGraphQuery {
EpiphanyGraphQuery {
kind: protocol_graph_query_kind_to_core(query.kind),
node_ids: query.node_ids.clone(),
edge_ids: query.edge_ids.clone(),
paths: query.paths.clone(),
symbols: query.symbols.clone(),
edge_kinds: query.edge_kinds.clone(),
direction: query.direction.map(protocol_graph_query_direction_to_core),
depth: query.depth,
include_links: query.include_links,
}
}
pub fn protocol_worker_launch_document_to_core(
document: ThreadEpiphanyWorkerLaunchDocument,
) -> EpiphanyWorkerLaunchDocument {
match document {
ThreadEpiphanyWorkerLaunchDocument::Role(document) => EpiphanyWorkerLaunchDocument::Role(
protocol_role_worker_launch_document_to_core(document),
),
ThreadEpiphanyWorkerLaunchDocument::Reorient(document) => {
EpiphanyWorkerLaunchDocument::Reorient(
protocol_reorient_worker_launch_document_to_core(document),
)
}
}
}
pub fn protocol_update_patch_to_core(
patch: &ThreadEpiphanyUpdatePatch,
) -> EpiphanyRoleStatePatchDocument {
EpiphanyRoleStatePatchDocument {
objective: patch.objective.clone(),
active_subgoal_id: patch.active_subgoal_id.clone(),
subgoals: patch.subgoals.clone(),
invariants: patch.invariants.clone(),
graphs: patch.graphs.clone(),
graph_frontier: patch.graph_frontier.clone(),
graph_checkpoint: patch.graph_checkpoint.clone(),
scratch: patch.scratch.clone(),
investigation_checkpoint: patch.investigation_checkpoint.clone(),
job_bindings: patch.job_bindings.clone(),
acceptance_receipts: patch.acceptance_receipts.clone(),
runtime_links: patch.runtime_links.clone(),
observations: patch.observations.clone(),
evidence: patch.evidence.clone(),
churn: patch.churn.clone(),
mode: patch.mode.clone(),
planning: patch.planning.clone(),
}
}
pub fn protocol_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,
},
}
}
pub fn protocol_job_from_surface(
job: EpiphanyJobView,
launcher_job_id: Option<String>,
backend_job_id_override: Option<String>,
) -> ThreadEpiphanyJob {
ThreadEpiphanyJob {
id: job.id,
kind: match job.kind {
EpiphanyJobKind::Indexing => ThreadEpiphanyJobKind::Indexing,
EpiphanyJobKind::Remap => ThreadEpiphanyJobKind::Remap,
EpiphanyJobKind::Verification => ThreadEpiphanyJobKind::Verification,
EpiphanyJobKind::Specialist => ThreadEpiphanyJobKind::Specialist,
},
scope: job.scope,
owner_role: job.owner_role,
launcher_job_id,
authority_scope: job.authority_scope,
backend_job_id: backend_job_id_override.or(job.runtime_job_id),
status: match job.status {
EpiphanyJobStatus::Idle => ThreadEpiphanyJobStatus::Idle,
EpiphanyJobStatus::Needed => ThreadEpiphanyJobStatus::Needed,
EpiphanyJobStatus::Pending => ThreadEpiphanyJobStatus::Pending,
EpiphanyJobStatus::Running => ThreadEpiphanyJobStatus::Running,
EpiphanyJobStatus::Completed => ThreadEpiphanyJobStatus::Completed,
EpiphanyJobStatus::Failed => ThreadEpiphanyJobStatus::Failed,
EpiphanyJobStatus::Cancelled => ThreadEpiphanyJobStatus::Cancelled,
EpiphanyJobStatus::Blocked => ThreadEpiphanyJobStatus::Blocked,
EpiphanyJobStatus::Unavailable => ThreadEpiphanyJobStatus::Unavailable,
},
items_processed: job.items_processed,
items_total: job.items_total,
progress_note: job.progress_note,
last_checkpoint_at_unix_seconds: job.last_checkpoint_at_unix_seconds,
blocking_reason: job.blocking_reason,
active_thread_ids: job.active_thread_ids,
linked_subgoal_ids: job.linked_subgoal_ids,
linked_graph_node_ids: job.linked_graph_node_ids,
}
}
pub fn protocol_reorient_state_status(
status: EpiphanyReorientStateStatus,
) -> ThreadEpiphanyReorientStateStatus {
match status {
EpiphanyReorientStateStatus::Missing => ThreadEpiphanyReorientStateStatus::Missing,
EpiphanyReorientStateStatus::Ready => ThreadEpiphanyReorientStateStatus::Ready,
}
}
pub fn protocol_reorient_source(source: EpiphanySurfaceSource) -> ThreadEpiphanyReorientSource {
match source {
EpiphanySurfaceSource::Stored => ThreadEpiphanyReorientSource::Stored,
EpiphanySurfaceSource::Live => ThreadEpiphanyReorientSource::Live,
}
}
pub fn protocol_reorient_decision(
decision: EpiphanyReorientDecision,
) -> ThreadEpiphanyReorientDecision {
ThreadEpiphanyReorientDecision {
action: match decision.action {
EpiphanyReorientAction::Resume => ThreadEpiphanyReorientAction::Resume,
EpiphanyReorientAction::Regather => ThreadEpiphanyReorientAction::Regather,
},
checkpoint_status: match decision.checkpoint_status {
EpiphanyReorientCheckpointStatus::Missing => {
ThreadEpiphanyReorientCheckpointStatus::Missing
}
EpiphanyReorientCheckpointStatus::ResumeReady => {
ThreadEpiphanyReorientCheckpointStatus::ResumeReady
}
EpiphanyReorientCheckpointStatus::RegatherRequired => {
ThreadEpiphanyReorientCheckpointStatus::RegatherRequired
}
},
checkpoint_id: decision.checkpoint_id,
pressure_level: match decision.pressure_level {
EpiphanyReorientPressureLevel::Unknown => ThreadEpiphanyPressureLevel::Unknown,
EpiphanyReorientPressureLevel::Low => ThreadEpiphanyPressureLevel::Low,
EpiphanyReorientPressureLevel::Medium => ThreadEpiphanyPressureLevel::Elevated,
EpiphanyReorientPressureLevel::High => ThreadEpiphanyPressureLevel::High,
EpiphanyReorientPressureLevel::Critical => ThreadEpiphanyPressureLevel::Critical,
},
retrieval_status: protocol_reorient_retrieval_status(decision.retrieval_status),
graph_status: protocol_reorient_graph_status(decision.graph_status),
watcher_status: protocol_reorient_watcher_status(decision.watcher_status),
reasons: decision
.reasons
.into_iter()
.map(protocol_reorient_reason)
.collect(),
checkpoint_dirty_paths: decision.checkpoint_dirty_paths,
checkpoint_changed_paths: decision.checkpoint_changed_paths,
active_frontier_node_ids: decision.active_frontier_node_ids,
next_action: decision.next_action,
note: decision.note,
}
}
fn protocol_view_lens_to_core(lens: ThreadEpiphanyViewLens) -> EpiphanyViewLens {
match lens {
ThreadEpiphanyViewLens::Scene => EpiphanyViewLens::Scene,
ThreadEpiphanyViewLens::Jobs => EpiphanyViewLens::Jobs,
ThreadEpiphanyViewLens::Roles => EpiphanyViewLens::Roles,
ThreadEpiphanyViewLens::Planning => EpiphanyViewLens::Planning,
ThreadEpiphanyViewLens::Pressure => EpiphanyViewLens::Pressure,
ThreadEpiphanyViewLens::Reorient => EpiphanyViewLens::Reorient,
ThreadEpiphanyViewLens::Crrc => EpiphanyViewLens::Crrc,
ThreadEpiphanyViewLens::Coordinator => EpiphanyViewLens::Coordinator,
}
}
fn protocol_graph_query_kind_to_core(kind: ThreadEpiphanyGraphQueryKind) -> EpiphanyGraphQueryKind {
match kind {
ThreadEpiphanyGraphQueryKind::Node => EpiphanyGraphQueryKind::Node,
ThreadEpiphanyGraphQueryKind::Path => EpiphanyGraphQueryKind::Path,
ThreadEpiphanyGraphQueryKind::FrontierNeighborhood => {
EpiphanyGraphQueryKind::FrontierNeighborhood
}
ThreadEpiphanyGraphQueryKind::Neighbors => EpiphanyGraphQueryKind::Neighbors,
}
}
fn protocol_graph_query_direction_to_core(
direction: ThreadEpiphanyGraphQueryDirection,
) -> EpiphanyGraphQueryDirection {
match direction {
ThreadEpiphanyGraphQueryDirection::Incoming => EpiphanyGraphQueryDirection::Incoming,
ThreadEpiphanyGraphQueryDirection::Outgoing => EpiphanyGraphQueryDirection::Outgoing,
ThreadEpiphanyGraphQueryDirection::Both => EpiphanyGraphQueryDirection::Both,
}
}
fn protocol_role_worker_launch_document_to_core(
document: ThreadEpiphanyRoleWorkerLaunchDocument,
) -> EpiphanyRoleWorkerLaunchDocument {
EpiphanyRoleWorkerLaunchDocument {
thread_id: document.thread_id,
role_id: document.role_id,
state_revision: document.state_revision,
objective: document.objective,
active_subgoal_id: document.active_subgoal_id,
active_subgoals: document.active_subgoals,
active_graph_node_ids: document.active_graph_node_ids,
investigation_checkpoint: document.investigation_checkpoint,
scratch: document.scratch,
invariants: document.invariants,
graphs: document.graphs,
recent_evidence: document.recent_evidence,
recent_observations: document.recent_observations,
graph_frontier: document.graph_frontier,
graph_checkpoint: document.graph_checkpoint,
planning: document.planning,
churn: document.churn,
}
}
fn protocol_reorient_worker_launch_document_to_core(
document: ThreadEpiphanyReorientWorkerLaunchDocument,
) -> EpiphanyReorientWorkerLaunchDocument {
EpiphanyReorientWorkerLaunchDocument {
thread_id: document.thread_id,
mode: document.mode,
checkpoint_id: document.checkpoint_id,
checkpoint_kind: document.checkpoint_kind,
checkpoint_disposition: document.checkpoint_disposition,
checkpoint_focus: document.checkpoint_focus,
checkpoint_summary: document.checkpoint_summary,
checkpoint_next_action: document.checkpoint_next_action,
checkpoint_open_questions: document.checkpoint_open_questions,
checkpoint_evidence_ids: document.checkpoint_evidence_ids,
checkpoint_code_refs: document.checkpoint_code_refs,
decision_reasons: document.decision_reasons,
decision_note: document.decision_note,
pressure_level: document.pressure_level,
retrieval_status: document.retrieval_status,
graph_status: document.graph_status,
watcher_status: document.watcher_status,
checkpoint_dirty_paths: document.checkpoint_dirty_paths,
checkpoint_changed_paths: document.checkpoint_changed_paths,
scratch: document.scratch,
graphs: document.graphs,
recent_evidence: document.recent_evidence,
recent_observations: document.recent_observations,
active_frontier_node_ids: document.active_frontier_node_ids,
linked_subgoal_ids: document.linked_subgoal_ids,
linked_graph_node_ids: document.linked_graph_node_ids,
}
}
fn protocol_reorient_retrieval_status(
status: EpiphanyReorientFreshnessStatus,
) -> ThreadEpiphanyRetrievalFreshnessStatus {
match status {
EpiphanyReorientFreshnessStatus::Unknown => ThreadEpiphanyRetrievalFreshnessStatus::Missing,
EpiphanyReorientFreshnessStatus::Clean => ThreadEpiphanyRetrievalFreshnessStatus::Ready,
EpiphanyReorientFreshnessStatus::Dirty => ThreadEpiphanyRetrievalFreshnessStatus::Indexing,
EpiphanyReorientFreshnessStatus::Stale | EpiphanyReorientFreshnessStatus::Changed => {
ThreadEpiphanyRetrievalFreshnessStatus::Stale
}
}
}
fn protocol_reorient_graph_status(
status: EpiphanyReorientFreshnessStatus,
) -> ThreadEpiphanyGraphFreshnessStatus {
match status {
EpiphanyReorientFreshnessStatus::Unknown => ThreadEpiphanyGraphFreshnessStatus::Missing,
EpiphanyReorientFreshnessStatus::Clean => ThreadEpiphanyGraphFreshnessStatus::Ready,
EpiphanyReorientFreshnessStatus::Dirty
| EpiphanyReorientFreshnessStatus::Stale
| EpiphanyReorientFreshnessStatus::Changed => ThreadEpiphanyGraphFreshnessStatus::Stale,
}
}
fn protocol_reorient_watcher_status(
status: EpiphanyReorientFreshnessStatus,
) -> ThreadEpiphanyInvalidationStatus {
match status {
EpiphanyReorientFreshnessStatus::Unknown => ThreadEpiphanyInvalidationStatus::Unavailable,
EpiphanyReorientFreshnessStatus::Clean => ThreadEpiphanyInvalidationStatus::Clean,
EpiphanyReorientFreshnessStatus::Dirty
| EpiphanyReorientFreshnessStatus::Stale
| EpiphanyReorientFreshnessStatus::Changed => ThreadEpiphanyInvalidationStatus::Changed,
}
}
fn protocol_reorient_reason(reason: EpiphanyReorientReason) -> ThreadEpiphanyReorientReason {
match reason {
EpiphanyReorientReason::MissingState => ThreadEpiphanyReorientReason::MissingState,
EpiphanyReorientReason::MissingCheckpoint => {
ThreadEpiphanyReorientReason::MissingCheckpoint
}
EpiphanyReorientReason::CheckpointReady => ThreadEpiphanyReorientReason::CheckpointReady,
EpiphanyReorientReason::CheckpointRequestedRegather => {
ThreadEpiphanyReorientReason::CheckpointRequestedRegather
}
EpiphanyReorientReason::CheckpointPathsDirty => {
ThreadEpiphanyReorientReason::CheckpointPathsDirty
}
EpiphanyReorientReason::CheckpointPathsChanged => {
ThreadEpiphanyReorientReason::CheckpointPathsChanged
}
EpiphanyReorientReason::FrontierChanged => ThreadEpiphanyReorientReason::FrontierChanged,
EpiphanyReorientReason::UnanchoredCheckpointWhileStateStale => {
ThreadEpiphanyReorientReason::UnanchoredCheckpointWhileStateStale
}
}
}