diff --git a/epiphany-core/Cargo.toml b/epiphany-core/Cargo.toml index 686c035c..18394474 100644 --- a/epiphany-core/Cargo.toml +++ b/epiphany-core/Cargo.toml @@ -21,6 +21,7 @@ epiphany-openai-adapter = { path = "../epiphany-openai-adapter" } ignore = "0.4.23" postgres = "0.19" reqwest = { version = "0.12", features = ["blocking", "json"] } +rmp-serde = "1" serde = { version = "1", features = ["derive"] } serde_json = "1" sha1 = "0.10.6" diff --git a/epiphany-core/src/lib.rs b/epiphany-core/src/lib.rs index 4781dbbb..075b52e0 100644 --- a/epiphany-core/src/lib.rs +++ b/epiphany-core/src/lib.rs @@ -99,6 +99,7 @@ pub use runtime_spine::EpiphanyRuntimeJobStatus; pub use runtime_spine::EpiphanyRuntimeSession; pub use runtime_spine::EpiphanyRuntimeSessionStatus; pub use runtime_spine::EpiphanyRuntimeSpineStatus; +pub use runtime_spine::EpiphanyRuntimeWorkerLaunchRequest; pub use runtime_spine::RUNTIME_EVENT_TYPE; pub use runtime_spine::RUNTIME_IDENTITY_KEY; pub use runtime_spine::RUNTIME_IDENTITY_TYPE; @@ -106,10 +107,12 @@ pub use runtime_spine::RUNTIME_JOB_RESULT_TYPE; pub use runtime_spine::RUNTIME_JOB_TYPE; pub use runtime_spine::RUNTIME_SESSION_TYPE; pub use runtime_spine::RUNTIME_SPINE_SCHEMA_VERSION; +pub use runtime_spine::RUNTIME_WORKER_LAUNCH_REQUEST_SCHEMA_VERSION; +pub use runtime_spine::RUNTIME_WORKER_LAUNCH_REQUEST_TYPE; pub use runtime_spine::RuntimeSpineEventOptions; +pub use runtime_spine::RuntimeSpineHeartbeatJobOptions; pub use runtime_spine::RuntimeSpineHeartbeatLaunchPlan; pub use runtime_spine::RuntimeSpineHeartbeatLaunchPlanOptions; -pub use runtime_spine::RuntimeSpineHeartbeatJobOptions; pub use runtime_spine::RuntimeSpineInitOptions; pub use runtime_spine::RuntimeSpineJobOptions; pub use runtime_spine::RuntimeSpineJobResultOptions; diff --git a/epiphany-core/src/runtime_spine.rs b/epiphany-core/src/runtime_spine.rs index cf795205..eab468e4 100644 --- a/epiphany-core/src/runtime_spine.rs +++ b/epiphany-core/src/runtime_spine.rs @@ -1,11 +1,12 @@ -use anyhow::Context; -use anyhow::Result; -use anyhow::anyhow; +use crate::EpiphanyWorkerLaunchDocument; use crate::agent_memory::AGENT_MEMORY_TYPE; use crate::heartbeat_state::HEARTBEAT_STATE_SCHEMA_VERSION; use crate::heartbeat_state::HEARTBEAT_STATE_TYPE; use crate::state_ledger::STATE_LEDGER_SCHEMA_VERSION; use crate::state_ledger::STATE_LEDGER_STORE_TYPE; +use anyhow::Context; +use anyhow::Result; +use anyhow::anyhow; use codex_protocol::protocol::EpiphanyJobBinding; use codex_protocol::protocol::EpiphanyJobKind; use codex_protocol::protocol::EpiphanyRuntimeLink; @@ -28,7 +29,6 @@ use epiphany_openai_adapter::EpiphanyOpenAiAdapterStatus; use epiphany_openai_adapter::EpiphanyOpenAiModelReceipt; use epiphany_openai_adapter::EpiphanyOpenAiModelRequest; use epiphany_openai_adapter::EpiphanyOpenAiStreamEvent; -use crate::EpiphanyWorkerLaunchDocument; use serde::Deserialize; use serde::Serialize; use std::collections::BTreeMap; @@ -39,6 +39,7 @@ use std::path::PathBuf; pub const RUNTIME_IDENTITY_TYPE: &str = "epiphany.runtime.identity"; pub const RUNTIME_SESSION_TYPE: &str = "epiphany.runtime.session"; pub const RUNTIME_JOB_TYPE: &str = "epiphany.runtime.job"; +pub const RUNTIME_WORKER_LAUNCH_REQUEST_TYPE: &str = "epiphany.runtime.worker_launch_request"; pub const RUNTIME_JOB_RESULT_TYPE: &str = "epiphany.runtime.job_result"; pub const RUNTIME_EVENT_TYPE: &str = "epiphany.runtime.event"; pub const OPENAI_ADAPTER_STATUS_TYPE: &str = "epiphany.openai_adapter_status.v0"; @@ -66,6 +67,8 @@ pub const SURFACE_RIDER_BRIDGE_TYPE: &str = "epiphany.surface.rider_bridge"; pub const SURFACE_UNITY_BRIDGE_TYPE: &str = "epiphany.surface.unity_bridge"; pub const RUNTIME_IDENTITY_KEY: &str = "self"; pub const RUNTIME_SPINE_SCHEMA_VERSION: &str = "epiphany.runtime_spine.v0"; +pub const RUNTIME_WORKER_LAUNCH_REQUEST_SCHEMA_VERSION: &str = + "epiphany.runtime.worker_launch_request.v0"; pub const OPENAI_ADAPTER_STATUS_SCHEMA_VERSION: &str = "epiphany.openai_adapter_status.v0"; pub const OPENAI_MODEL_REQUEST_SCHEMA_VERSION: &str = "epiphany.openai_model_request.v0"; pub const OPENAI_MODEL_STREAM_EVENT_SCHEMA_VERSION: &str = "epiphany.openai_model_stream_event.v0"; @@ -87,8 +90,7 @@ pub const FACE_SURFACE_SCHEMA_VERSION: &str = "epiphany.face_surface.v0"; pub const VOID_MEMORY_SURFACE_SCHEMA_VERSION: &str = "epiphany.void_memory_surface.v0"; pub const REPO_INITIALIZATION_SURFACE_SCHEMA_VERSION: &str = "epiphany.repo_initialization_surface.v0"; -pub const REPO_BIRTH_RUNNER_SURFACE_SCHEMA_VERSION: &str = - "epiphany.repo_birth_runner_surface.v0"; +pub const REPO_BIRTH_RUNNER_SURFACE_SCHEMA_VERSION: &str = "epiphany.repo_birth_runner_surface.v0"; pub const RIDER_BRIDGE_SURFACE_SCHEMA_VERSION: &str = "epiphany.rider_bridge_surface.v0"; pub const UNITY_BRIDGE_SURFACE_SCHEMA_VERSION: &str = "epiphany.unity_bridge_surface.v0"; pub const AGENT_MEMORY_PAYLOAD_SCHEMA_VERSION: &str = "epiphany.agent_memory.v0"; @@ -183,6 +185,51 @@ pub struct EpiphanyRuntimeJob { pub metadata: BTreeMap, } +#[derive(Clone, Debug, PartialEq, DatabaseEntry)] +#[cultcache( + type = "epiphany.runtime.worker_launch_request", + schema = "EpiphanyRuntimeWorkerLaunchRequest" +)] +pub struct EpiphanyRuntimeWorkerLaunchRequest { + #[cultcache(key = 0)] + pub schema_version: String, + #[cultcache(key = 1)] + pub job_id: String, + #[cultcache(key = 2)] + pub binding_id: String, + #[cultcache(key = 3)] + pub role: String, + #[cultcache(key = 4)] + pub authority_scope: String, + #[cultcache(key = 5)] + pub instruction: String, + #[cultcache(key = 6)] + pub output_contract_id: String, + #[cultcache(key = 7)] + pub document_kind: String, + #[cultcache(key = 8)] + pub launch_document_msgpack: Vec, + #[cultcache(key = 9, default)] + pub metadata: BTreeMap, +} + +impl EpiphanyRuntimeWorkerLaunchRequest { + pub fn launch_document(&self) -> Result { + let document: EpiphanyWorkerLaunchDocument = + rmp_serde::from_slice(&self.launch_document_msgpack) + .context("failed to decode worker launch document MessagePack")?; + let actual_kind = worker_launch_document_kind(&document); + if actual_kind != self.document_kind { + return Err(anyhow!( + "worker launch document kind mismatch: indexed {:?}, payload {:?}", + self.document_kind, + actual_kind + )); + } + Ok(document) + } +} + #[derive(Clone, Debug, PartialEq, DatabaseEntry)] #[cultcache( type = "epiphany.runtime.job_result", @@ -325,7 +372,7 @@ pub struct RuntimeSpineJobResultOptions { pub artifact_refs: Vec, } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq)] pub struct RuntimeSpineHeartbeatJobOptions { pub runtime_id: String, pub display_name: String, @@ -336,6 +383,9 @@ pub struct RuntimeSpineHeartbeatJobOptions { pub role: String, pub binding_id: String, pub authority_scope: String, + pub instruction: String, + pub launch_document: EpiphanyWorkerLaunchDocument, + pub output_contract_id: String, pub created_at: String, } @@ -373,6 +423,7 @@ pub fn runtime_spine_cache(store_path: impl AsRef) -> Result { cache.register_entry_type::()?; cache.register_entry_type::()?; cache.register_entry_type::()?; + cache.register_entry_type::()?; cache.register_entry_type::()?; cache.register_entry_type::()?; cache.register_entry_type::()?; @@ -554,7 +605,10 @@ pub fn plan_runtime_spine_heartbeat_launch( blocking_reason: None, }, runtime_link: EpiphanyRuntimeLink { - id: format!("runtime-link-{}-{}", options.binding_id, options.runtime_job_id), + id: format!( + "runtime-link-{}-{}", + options.binding_id, options.runtime_job_id + ), binding_id: options.binding_id, surface: "jobLaunch".to_string(), role_id: options.owner_role, @@ -579,8 +633,26 @@ pub fn open_runtime_spine_heartbeat_job( validate_non_empty(&options.role, "role")?; validate_non_empty(&options.binding_id, "binding id")?; validate_non_empty(&options.authority_scope, "authority scope")?; + validate_non_empty(&options.instruction, "instruction")?; + validate_non_empty( + options.launch_document.thread_id(), + "worker launch document thread id", + )?; + validate_non_empty(&options.output_contract_id, "output contract id")?; + if options.output_contract_id != options.launch_document.output_contract_id() { + return Err(anyhow!( + "worker launch output_contract_id must match the typed launch document" + )); + } validate_non_empty(&options.created_at, "created at")?; let store_path = store_path.as_ref(); + let job_id = options.job_id.clone(); + let binding_id = options.binding_id.clone(); + let role = options.role.clone(); + let authority_scope = options.authority_scope.clone(); + let instruction = options.instruction.clone(); + let output_contract_id = options.output_contract_id.clone(); + let launch_document = options.launch_document.clone(); initialize_runtime_spine( store_path, RuntimeSpineInitOptions { @@ -598,7 +670,7 @@ pub fn open_runtime_spine_heartbeat_job( coordinator_note: options.coordinator_note, }, )?; - create_runtime_job( + let job = create_runtime_job( store_path, RuntimeSpineJobOptions { job_id: options.job_id, @@ -611,7 +683,32 @@ pub fn open_runtime_spine_heartbeat_job( ), artifact_refs: Vec::new(), }, - ) + )?; + let mut cache = runtime_spine_cache(store_path)?; + cache.pull_all_backing_stores()?; + if cache + .get::(&job_id)? + .is_some() + { + return Err(anyhow!( + "runtime worker launch request {:?} already exists", + job_id + )); + } + let request = EpiphanyRuntimeWorkerLaunchRequest { + schema_version: RUNTIME_WORKER_LAUNCH_REQUEST_SCHEMA_VERSION.to_string(), + job_id: job_id.clone(), + binding_id, + role, + authority_scope, + instruction, + output_contract_id, + document_kind: worker_launch_document_kind(&launch_document).to_string(), + launch_document_msgpack: encode_worker_launch_document(&launch_document)?, + metadata: BTreeMap::new(), + }; + cache.put(&job_id, &request)?; + Ok(job) } pub fn runtime_job_snapshot( @@ -1056,6 +1153,21 @@ fn epiphany_mutation_contracts() -> Vec { "Heartbeat activation owns agent work; external callers submit intents and watch receipts.", ], ), + mutation_contract( + RUNTIME_WORKER_LAUNCH_REQUEST_TYPE, + RUNTIME_WORKER_LAUNCH_REQUEST_SCHEMA_VERSION, + vec![ + CultNetDocumentOperation::Snapshot, + CultNetDocumentOperation::IntentSubmit, + CultNetDocumentOperation::ReceiptWatch, + ], + CultNetMutationAuthority::Coordinator, + vec![RUNTIME_WORKER_LAUNCH_REQUEST_TYPE], + vec![RUNTIME_JOB_TYPE], + vec![ + "Worker launch requests are typed task-intent documents; runtime jobs are lifecycle receipts, not the source of work intent.", + ], + ), mutation_contract( RUNTIME_JOB_RESULT_TYPE, RUNTIME_SPINE_SCHEMA_VERSION, @@ -1385,6 +1497,17 @@ fn validate_non_empty(value: &str, field: &str) -> Result<()> { Ok(()) } +fn worker_launch_document_kind(document: &EpiphanyWorkerLaunchDocument) -> &'static str { + match document { + EpiphanyWorkerLaunchDocument::Role(_) => "role", + EpiphanyWorkerLaunchDocument::Reorient(_) => "reorient", + } +} + +fn encode_worker_launch_document(document: &EpiphanyWorkerLaunchDocument) -> Result> { + rmp_serde::to_vec_named(document).context("failed to encode worker launch document MessagePack") +} + fn validate_heartbeat_launch_options( state: &EpiphanyThreadState, options: &RuntimeSpineHeartbeatLaunchPlanOptions, @@ -1602,6 +1725,29 @@ mod tests { role: "modeling".to_string(), binding_id: "modeling-checkpoint-worker".to_string(), authority_scope: "modeling".to_string(), + instruction: "Inspect the checkpoint and return typed role findings.".to_string(), + launch_document: EpiphanyWorkerLaunchDocument::Role( + crate::EpiphanyRoleWorkerLaunchDocument { + thread_id: "thread-1".to_string(), + role_id: "modeling".to_string(), + state_revision: 7, + objective: Some("Run heartbeat worker.".to_string()), + active_subgoal_id: None, + active_subgoals: Vec::new(), + active_graph_node_ids: vec!["node-model".to_string()], + investigation_checkpoint: None, + scratch: None, + invariants: Vec::new(), + graphs: None, + recent_evidence: Vec::new(), + recent_observations: Vec::new(), + graph_frontier: None, + graph_checkpoint: None, + planning: None, + churn: None, + }, + ), + output_contract_id: crate::ROLE_WORKER_OUTPUT_CONTRACT_ID.to_string(), created_at: "2026-05-06T00:02:00Z".to_string(), }, )?; @@ -1614,6 +1760,21 @@ mod tests { assert_eq!(status.jobs, 1); assert_eq!(status.open_jobs, 1); assert_eq!(status.events, 1); + let mut cache = runtime_spine_cache(&store)?; + cache.pull_all_backing_stores()?; + let launch_request = cache + .get::("heartbeat-job-1")? + .expect("typed worker launch request should be durable"); + assert_eq!(launch_request.job_id, "heartbeat-job-1"); + assert_eq!(launch_request.binding_id, "modeling-checkpoint-worker"); + assert_eq!(launch_request.role, "modeling"); + assert_eq!( + launch_request.output_contract_id, + crate::ROLE_WORKER_OUTPUT_CONTRACT_ID + ); + assert_eq!(launch_request.document_kind, "role"); + assert!(!launch_request.launch_document_msgpack.is_empty()); + assert_eq!(launch_request.launch_document()?.thread_id(), "thread-1"); Ok(()) } diff --git a/notes/fresh-workspace-handoff.md b/notes/fresh-workspace-handoff.md index 0392303d..95bb5e96 100644 --- a/notes/fresh-workspace-handoff.md +++ b/notes/fresh-workspace-handoff.md @@ -598,6 +598,14 @@ initialize-session-open-job sequence. That is a small cut, but a real ownership move: native runtime lifecycle belongs to the runtime spine, not the Codex thread wrapper. +That job-opening path now preserves the work order instead of shaving it into a +generic job id. `epiphany-core::EpiphanyRuntimeWorkerLaunchRequest` is a +CultCache document keyed by runtime job id, with indexed binding/role/authority, +instruction, output contract, document kind, and a MessagePack-encoded typed +worker launch document. `EpiphanyRuntimeJob` owns lifecycle; the launch request +owns task intent. The MessagePack field is a compatibility wound around +ordinary Serde nested documents, not permission to reintroduce JSON cargo. + The job-launch plan has now followed it. `epiphany-core` owns `plan_runtime_spine_heartbeat_launch`, which validates heartbeat launch requests, reserved binding ids, output contract/document consistency, active diff --git a/state/ledgers.msgpack b/state/ledgers.msgpack index f2de5bc8..06012fa3 100644 Binary files a/state/ledgers.msgpack and b/state/ledgers.msgpack differ diff --git a/state/map.yaml b/state/map.yaml index 154a413b..03d890f6 100644 --- a/state/map.yaml +++ b/state/map.yaml @@ -279,5 +279,5 @@ rejected_paths: reason: making Epiphany cleaner inside Codex still preserves the wrong organ; Codex must be starved down to OpenAI subscription auth/model transport, while Epiphany data and subsystem communication move to typed CultCache/CultNet. current_status: - summary: The Codex starvation pass has five typing receipts, eighteen processor cuts, a real physical extraction in `epiphany-codex-bridge`, a source-grounded Codex auth spine inventory, the native `epiphany-openai-adapter` document boundary, a buildable Codex auth/model wrapper in `epiphany-openai-codex-spine`, the first native runtime caller in `epiphany-openai-runtime`, native heartbeat launch planning/job opening in `epiphany-core`, native state-update contract/validation/application in `epiphany-core`, and the route-facing mutation service in `epiphany-codex-bridge`. The bridge owns Codex-facing Epiphany adapters for scene, jobs, context/planning/graph query, retrieval/indexing projection, result projection, runtime-spine result adaptation, launch/prompt doctrine, mutation document mechanics, mutation service update/promote/role-accept/reorient-accept/role-launch/reorient-launch/job-launch/job-interrupt application, live-state projection, pressure/pre-compaction rendering, freshness/reorientation projection, CRRC/coordinator/role-board projection, and acceptance/evidence signal helpers. Vendored app-server now retains only `epiphany_invalidation.rs` as a root Epiphany module because watcher lifecycle is still app-server machinery; `codex_message_processor.rs` still contains route dispatch, JSON-RPC response shaping, watcher registration/snapshotting, and notification emission. The processor is about 10,339 lines, `epiphany_mutation_routes.rs` is about 691 lines after the route-load/notification helper cut and index projection move, `epiphany_state_helpers.rs` is down to a 19-line rollout-state loader, and `codex_thread.rs` is about 1,425 lines after state-update law moved native. `epiphany-openai-adapter` defines CultCache `DatabaseEntry` request/event/receipt/auth-status documents with no Codex app-server or generic JSON dependency. `epiphany-openai-codex-spine` projects `AuthManager` / `CodexAuth` into typed `EpiphanyOpenAiAdapterStatus`, maps typed `EpiphanyOpenAiModelRequest` into Codex API `ResponsesApiRequest`, resolves auth/provider through keeper Codex crates, opens HTTP Responses streams through `codex-api`, maps deltas / completion into typed stream events and receipts, and no longer directly depends on `codex-app-server-protocol` just to name auth mode. `epiphany-openai-runtime` writes OpenAI status/request/stream-event/receipt records plus runtime sessions/jobs/results/events into `epiphany-core::runtime_spine_cache`, can emit the assistant text artifact for legacy result consumers, and is now the default executor for startup-only repo birth specialists; `codex exec` survives there only as explicit fallback. `epiphany-core::plan_runtime_spine_heartbeat_launch` validates launch contracts/conflicts and projects durable job bindings/runtime links; `epiphany-core::open_runtime_spine_heartbeat_job` owns the initialize-runtime/ensure-session/create-job sequence; `epiphany-core::EpiphanyStateUpdate`, `epiphany_state_update_validation_errors`, and `apply_epiphany_state_update` own state-update document shape and mutation law while `codex-core` calls them for compatibility. Vendored `CodexThread::epiphany_launch_job` is now mostly revision check, persistence validation, and rollout/session writeback for the compatibility route. `epiphany-runtime-spine` advertises OpenAI adapter status/model-request/stream-event/receipt CultNet schemas and mutation contracts, so the native caller now has a real storage route instead of only JSON-RPC. MCP itself is correctly JSON at its protocol edge; the target is typed Epiphany intent/result/receipt wrappers around MCP, not replacing MCP JSON. The current OpenAI spine still pulls `codex-api` and a large transport dependency stack, so its next cut is dependency starvation after more live callers move. + summary: The Codex starvation pass has five typing receipts, eighteen processor cuts, a real physical extraction in `epiphany-codex-bridge`, a source-grounded Codex auth spine inventory, the native `epiphany-openai-adapter` document boundary, a buildable Codex auth/model wrapper in `epiphany-openai-codex-spine`, the first native runtime caller in `epiphany-openai-runtime`, native heartbeat launch planning/job opening in `epiphany-core`, native state-update contract/validation/application in `epiphany-core`, and the route-facing mutation service in `epiphany-codex-bridge`. The bridge owns Codex-facing Epiphany adapters for scene, jobs, context/planning/graph query, retrieval/indexing projection, result projection, runtime-spine result adaptation, launch/prompt doctrine, mutation document mechanics, mutation service update/promote/role-accept/reorient-accept/role-launch/reorient-launch/job-launch/job-interrupt application, live-state projection, pressure/pre-compaction rendering, freshness/reorientation projection, CRRC/coordinator/role-board projection, and acceptance/evidence signal helpers. Vendored app-server now retains only `epiphany_invalidation.rs` as a root Epiphany module because watcher lifecycle is still app-server machinery; `codex_message_processor.rs` still contains route dispatch, JSON-RPC response shaping, watcher registration/snapshotting, and notification emission. The processor is about 10,339 lines, `epiphany_mutation_routes.rs` is about 691 lines after the route-load/notification helper cut and index projection move, `epiphany_state_helpers.rs` is down to a 19-line rollout-state loader, and `codex_thread.rs` is about 1,425 lines after state-update law moved native. `epiphany-openai-adapter` defines CultCache `DatabaseEntry` request/event/receipt/auth-status documents with no Codex app-server or generic JSON dependency. `epiphany-openai-codex-spine` projects `AuthManager` / `CodexAuth` into typed `EpiphanyOpenAiAdapterStatus`, maps typed `EpiphanyOpenAiModelRequest` into Codex API `ResponsesApiRequest`, resolves auth/provider through keeper Codex crates, opens HTTP Responses streams through `codex-api`, maps deltas / completion into typed stream events and receipts, and no longer directly depends on `codex-app-server-protocol` just to name auth mode. `epiphany-openai-runtime` writes OpenAI status/request/stream-event/receipt records plus runtime sessions/jobs/results/events into `epiphany-core::runtime_spine_cache`, can emit the assistant text artifact for legacy result consumers, and is now the default executor for startup-only repo birth specialists; `codex exec` survives there only as explicit fallback. `epiphany-core::plan_runtime_spine_heartbeat_launch` validates launch contracts/conflicts and projects durable job bindings/runtime links; `epiphany-core::open_runtime_spine_heartbeat_job` owns the initialize-runtime/ensure-session/create-job sequence and now persists `EpiphanyRuntimeWorkerLaunchRequest` CultCache records keyed by runtime job id, with indexed kind/contract fields plus MessagePack-encoded typed launch documents instead of discarding work intent after queue receipt creation; `epiphany-core::EpiphanyStateUpdate`, `epiphany_state_update_validation_errors`, and `apply_epiphany_state_update` own state-update document shape and mutation law while `codex-core` calls them for compatibility. Vendored `CodexThread::epiphany_launch_job` is now mostly revision check, persistence validation, launch request handoff, and rollout/session writeback for the compatibility route. `epiphany-runtime-spine` advertises OpenAI adapter status/model-request/stream-event/receipt CultNet schemas and mutation contracts, so the native caller now has a real storage route instead of only JSON-RPC. MCP itself is correctly JSON at its protocol edge; the target is typed Epiphany intent/result/receipt wrappers around MCP, not replacing MCP JSON. The current OpenAI spine still pulls `codex-api` and a large transport dependency stack, so its next cut is dependency starvation after more live callers move. next_action: Move the remaining live model-turn callers, especially heartbeat/specialist execution, onto `epiphany-openai-runtime` or the same native CultNet contract, then shrink the surviving Codex dependency surface to credential refresh, provider/model routing, and the smallest OpenAI Responses call required for Codex subscription compatibility. diff --git a/vendor/codex/codex-rs/Cargo.lock b/vendor/codex/codex-rs/Cargo.lock index a83f3c90..82e72e85 100644 --- a/vendor/codex/codex-rs/Cargo.lock +++ b/vendor/codex/codex-rs/Cargo.lock @@ -5251,6 +5251,7 @@ dependencies = [ "ignore", "postgres", "reqwest", + "rmp-serde", "serde", "serde_json", "sha1", diff --git a/vendor/codex/codex-rs/core/src/codex_thread.rs b/vendor/codex/codex-rs/core/src/codex_thread.rs index 8106dc90..04b456b7 100644 --- a/vendor/codex/codex-rs/core/src/codex_thread.rs +++ b/vendor/codex/codex-rs/core/src/codex_thread.rs @@ -58,8 +58,8 @@ use codex_protocol::user_input::UserInput; use codex_utils_absolute_path::AbsolutePathBuf; use epiphany_core::EpiphanyStateUpdate; use epiphany_core::EpiphanyWorkerLaunchDocument; -use epiphany_core::RuntimeSpineHeartbeatLaunchPlanOptions; use epiphany_core::RuntimeSpineHeartbeatJobOptions; +use epiphany_core::RuntimeSpineHeartbeatLaunchPlanOptions; use epiphany_core::apply_epiphany_state_update; use epiphany_core::epiphany_state_update_validation_errors; use epiphany_core::open_runtime_spine_heartbeat_job; @@ -744,6 +744,9 @@ fn open_epiphany_runtime_spine_job( role: request.owner_role.clone(), binding_id: request.binding_id.clone(), authority_scope: request.authority_scope.clone(), + instruction: request.instruction.clone(), + launch_document: request.launch_document.clone(), + output_contract_id: request.output_contract_id.clone(), created_at: now, }, )