Files
codex/codex-rs/thread-store/src/remote/mod.rs
Tom 6e72f0dbfd [codex] Add remote thread store implementation (#17826)
- Add a "remote" thread store implementation
- Implement the remote thread store as a thin wrapper that makes grpc
calls to a configurable service endpoint
- Implement only the thread/list method to start
- Encode the grpc method/param shape as protobufs in the remote
implementation

A wart: the proto generation script is an "example" binary target. This
is an example target only because Cargo lets examples use
dev-dependencies, which keeps tonic-prost-build out of the normal
codex-thread-store dependency surface. A regular bin would either need
to add proto generation deps as normal runtime deps, or use a
feature-gated optional dep, which this repo’s manifest checks explicitly
reject.
2026-04-16 10:15:31 -07:00

113 lines
3.2 KiB
Rust

mod helpers;
mod list_threads;
use async_trait::async_trait;
use crate::AppendThreadItemsParams;
use crate::ArchiveThreadParams;
use crate::CreateThreadParams;
use crate::ListThreadsParams;
use crate::LoadThreadHistoryParams;
use crate::ReadThreadParams;
use crate::ResumeThreadRecorderParams;
use crate::SetThreadNameParams;
use crate::StoredThread;
use crate::StoredThreadHistory;
use crate::ThreadPage;
use crate::ThreadRecorder;
use crate::ThreadStore;
use crate::ThreadStoreError;
use crate::ThreadStoreResult;
use crate::UpdateThreadMetadataParams;
use proto::thread_store_client::ThreadStoreClient;
#[path = "proto/codex.thread_store.v1.rs"]
mod proto;
/// gRPC-backed [`ThreadStore`] implementation for deployments whose durable thread data lives
/// outside the app-server process.
#[derive(Clone, Debug)]
pub struct RemoteThreadStore {
endpoint: String,
}
impl RemoteThreadStore {
pub fn new(endpoint: impl Into<String>) -> Self {
Self {
endpoint: endpoint.into(),
}
}
async fn client(&self) -> ThreadStoreResult<ThreadStoreClient<tonic::transport::Channel>> {
ThreadStoreClient::connect(self.endpoint.clone())
.await
.map_err(|err| ThreadStoreError::Internal {
message: format!("failed to connect to remote thread store: {err}"),
})
}
}
#[async_trait]
impl ThreadStore for RemoteThreadStore {
async fn create_thread(
&self,
_params: CreateThreadParams,
) -> ThreadStoreResult<Box<dyn ThreadRecorder>> {
Err(not_implemented("create_thread"))
}
async fn resume_thread_recorder(
&self,
_params: ResumeThreadRecorderParams,
) -> ThreadStoreResult<Box<dyn ThreadRecorder>> {
Err(not_implemented("resume_thread_recorder"))
}
async fn append_items(&self, _params: AppendThreadItemsParams) -> ThreadStoreResult<()> {
Err(not_implemented("append_items"))
}
async fn load_history(
&self,
_params: LoadThreadHistoryParams,
) -> ThreadStoreResult<StoredThreadHistory> {
Err(not_implemented("load_history"))
}
async fn read_thread(&self, _params: ReadThreadParams) -> ThreadStoreResult<StoredThread> {
Err(not_implemented("read_thread"))
}
async fn list_threads(&self, params: ListThreadsParams) -> ThreadStoreResult<ThreadPage> {
list_threads::list_threads(self, params).await
}
async fn set_thread_name(&self, _params: SetThreadNameParams) -> ThreadStoreResult<()> {
Err(not_implemented("set_thread_name"))
}
async fn update_thread_metadata(
&self,
_params: UpdateThreadMetadataParams,
) -> ThreadStoreResult<StoredThread> {
Err(not_implemented("update_thread_metadata"))
}
async fn archive_thread(&self, _params: ArchiveThreadParams) -> ThreadStoreResult<()> {
Err(not_implemented("archive_thread"))
}
async fn unarchive_thread(
&self,
_params: ArchiveThreadParams,
) -> ThreadStoreResult<StoredThread> {
Err(not_implemented("unarchive_thread"))
}
}
fn not_implemented(method: &str) -> ThreadStoreError {
ThreadStoreError::Internal {
message: format!("remote thread store does not implement {method} yet"),
}
}