Revert state DB injection and agent graph store (#21481)

## Why

Reverts #20689 to restore the previous optional state DB plumbing. The
conflict resolution keeps the newer installation ID and session/thread
identity changes that landed after #20689, while removing the mandatory
state DB and agent graph store dependency from ThreadManager
construction.

## What changed

- Restored `Option<StateDbHandle>` through app-server, MCP server,
prompt debug, and test entry points.
- Removed the `codex-core` dependency on `codex-agent-graph-store` and
reverted descendant lookup back to the existing state DB path when
available.
- Kept newer `installation_id` forwarding by passing it beside the
optional DB handle.
- Kept local thread-name updates working when the optional state DB
handle is absent.

## Validation

- `git diff --check`
- `cargo test -p codex-thread-store`
- `cargo test -p codex-state -p codex-rollout -p
codex-app-server-protocol`
- Attempted `env CARGO_INCREMENTAL=0 cargo test -p codex-core -p
codex-app-server -p codex-app-server-client -p codex-mcp-server -p
codex-thread-manager-sample -p codex-tui`; blocked locally by a rustc
ICE while compiling `v8 v146.4.0` with `rustc 1.93.0 (254b59607
2026-01-19)` on `aarch64-apple-darwin`.
This commit is contained in:
pakrym-oai
2026-05-06 22:48:29 -07:00
committed by GitHub
Unverified
parent 5bc33fe31f
commit a8488fec5e
54 changed files with 781 additions and 834 deletions
@@ -33,8 +33,8 @@ use codex_device_key::RemoteControlClientConnectionAudience;
use codex_device_key::RemoteControlClientConnectionSignPayload;
use codex_device_key::RemoteControlClientEnrollmentAudience;
use codex_device_key::RemoteControlClientEnrollmentSignPayload;
use codex_rollout::state_db::StateDbHandle;
use codex_state::DeviceKeyBindingRecord;
use codex_state::StateRuntime;
#[derive(Clone)]
pub(crate) struct DeviceKeyRequestProcessor {
@@ -43,7 +43,10 @@ pub(crate) struct DeviceKeyRequestProcessor {
}
impl DeviceKeyRequestProcessor {
pub(crate) fn new(outgoing: Arc<OutgoingMessageSender>, state_db: StateDbHandle) -> Self {
pub(crate) fn new(
outgoing: Arc<OutgoingMessageSender>,
state_db: Option<Arc<StateRuntime>>,
) -> Self {
Self {
outgoing,
store: DeviceKeyStore::new(Arc::new(StateDeviceKeyBindingStore::new(state_db))),
@@ -167,18 +170,25 @@ async fn sign_device_key(
}
struct StateDeviceKeyBindingStore {
state_db: StateDbHandle,
state_db: Option<Arc<StateRuntime>>,
}
impl StateDeviceKeyBindingStore {
fn new(state_db: StateDbHandle) -> Self {
fn new(state_db: Option<Arc<StateRuntime>>) -> Self {
Self { state_db }
}
async fn state_db(&self) -> Result<Arc<StateRuntime>, DeviceKeyError> {
self.state_db
.clone()
.ok_or_else(|| DeviceKeyError::Platform("sqlite state db unavailable".to_string()))
}
}
impl fmt::Debug for StateDeviceKeyBindingStore {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("StateDeviceKeyBindingStore")
.field("has_state_db", &self.state_db.is_some())
.finish_non_exhaustive()
}
}
@@ -186,7 +196,7 @@ impl fmt::Debug for StateDeviceKeyBindingStore {
#[async_trait]
impl DeviceKeyBindingStore for StateDeviceKeyBindingStore {
async fn get_binding(&self, key_id: &str) -> Result<Option<DeviceKeyBinding>, DeviceKeyError> {
let state_db = self.state_db.clone();
let state_db = self.state_db().await?;
state_db
.get_device_key_binding(key_id)
.await
@@ -204,7 +214,7 @@ impl DeviceKeyBindingStore for StateDeviceKeyBindingStore {
key_id: &str,
binding: &DeviceKeyBinding,
) -> Result<(), DeviceKeyError> {
let state_db = self.state_db.clone();
let state_db = self.state_db().await?;
state_db
.upsert_device_key_binding(&DeviceKeyBindingRecord {
key_id: key_id.to_string(),
@@ -7,7 +7,7 @@ pub(crate) struct ThreadGoalRequestProcessor {
outgoing: Arc<OutgoingMessageSender>,
config: Arc<Config>,
thread_state_manager: ThreadStateManager,
state_db: StateDbHandle,
state_db: Option<StateDbHandle>,
}
impl ThreadGoalRequestProcessor {
@@ -16,7 +16,7 @@ impl ThreadGoalRequestProcessor {
outgoing: Arc<OutgoingMessageSender>,
config: Arc<Config>,
thread_state_manager: ThreadStateManager,
state_db: StateDbHandle,
state_db: Option<StateDbHandle>,
) -> Self {
Self {
thread_manager,
@@ -72,6 +72,23 @@ impl ThreadGoalRequestProcessor {
}
}
pub(crate) async fn pending_resume_goal_state(
&self,
thread: &CodexThread,
) -> (bool, Option<StateDbHandle>) {
let emit_thread_goal_update = self.config.features.enabled(Feature::Goals);
let thread_goal_state_db = if emit_thread_goal_update {
if let Some(state_db) = thread.state_db() {
Some(state_db)
} else {
self.state_db.clone()
}
} else {
None
};
(emit_thread_goal_update, thread_goal_state_db)
}
async fn thread_goal_set_inner(
&self,
request_id: ConnectionRequestId,
@@ -93,7 +110,7 @@ impl ThreadGoalRequestProcessor {
None => find_thread_path_by_id_str(
&self.config.codex_home,
&thread_id.to_string(),
Some(self.state_db.as_ref()),
self.state_db.as_deref(),
)
.await
.map_err(|err| {
@@ -258,7 +275,7 @@ impl ThreadGoalRequestProcessor {
None => find_thread_path_by_id_str(
&self.config.codex_home,
&thread_id.to_string(),
Some(self.state_db.as_ref()),
self.state_db.as_deref(),
)
.await
.map_err(|err| {
@@ -322,7 +339,7 @@ impl ThreadGoalRequestProcessor {
find_thread_path_by_id_str(
&self.config.codex_home,
&thread_id.to_string(),
Some(self.state_db.as_ref()),
self.state_db.as_deref(),
)
.await
.map_err(|err| {
@@ -331,7 +348,9 @@ impl ThreadGoalRequestProcessor {
.ok_or_else(|| invalid_request(format!("thread not found: {thread_id}")))?;
}
Ok(self.state_db.clone())
self.state_db
.clone()
.ok_or_else(|| internal_error("sqlite state db unavailable for thread goals"))
}
async fn emit_thread_goal_snapshot(&self, thread_id: ThreadId) {
@@ -2671,10 +2671,10 @@ impl ThreadRequestProcessor {
)));
};
let emit_thread_goal_update = self.config.features.enabled(Feature::Goals);
let thread_goal_state_db = emit_thread_goal_update
.then(|| self.state_db.clone())
.flatten();
let (emit_thread_goal_update, thread_goal_state_db) = self
.thread_goal_processor
.pending_resume_goal_state(existing_thread.as_ref())
.await;
let command = crate::thread_state::ThreadListenerCommand::SendThreadResumeResponse(
Box::new(crate::thread_state::PendingThreadResumeRequest {