Files
codex/codex-rs/thread-store/src/store.rs
Owen Lin 0d0835dd53 feat(app-server, threadstore): Thread pagination APIs and ThreadStore contract (#21566)
## Why
The goal of this PR is to align on app-server and `ThreadStore` API
updates for paginating through large threads.


#### app-server
##### `thread/turns/list`
- Updates `thread/turns/list` to support `itemsView?: "notLoaded" |
"summary" | "full" | null`, defaulting to `summary`.
- Implements the current `thread/turns/list` behavior over the existing
persisted rollout-history fallback:
  - `notLoaded` returns turn envelopes with empty `items`.
- `summary` returns the first user message and final assistant message
when available.
  - `full` preserves the existing full item behavior.

Note that this method still uses the naive approach of loading the
entire rollout file, and returns just the filtered slice of the data.
Real pagination will come later by leveraging SQLite.

##### `thread/turns/items/list`
- Adds the experimental `thread/turns/items/list` protocol, schema,
dispatcher, and processor stub. The app-server currently returns
JSON-RPC `-32601` with `thread/turns/items/list is not supported yet`.

#### ThreadStore
- Adds the experimental `thread/turns/items/list` protocol, schema,
dispatcher, and processor stub. The app-server currently returns
JSON-RPC `-32601` with `thread/turns/items/list is not supported yet`.
- Adds `ThreadStore` contract types and stubbed methods for listing
thread turns and listing items within a turn.
- Adds a typed `StoredTurnStatus` and `StoredTurnError` to avoid baking
app-server API enums or lossy string status values into the store-facing
turn contract.
- Adds a typed `StoredTurnStatus` and `StoredTurnError` to avoid baking
app-server API enums or lossy string status values into the store-facing
turn contract.

This also sketches the storage abstraction we expect to need once turns
are indexed/stored. In particular, `notLoaded` is useful only if
ThreadStore can eventually list turn metadata without loading every
persisted item for each turn.

## Validation

- Added/updated protocol serialization coverage for the new request and
response shapes.
- Added app-server integration coverage for `thread/turns/list` default
summary behavior and all three `itemsView` modes.
- Added app-server integration coverage that `thread/turns/items/list`
returns the expected unsupported JSON-RPC error when experimental APIs
are enabled.
- Added thread-store coverage that the default trait methods return
`ThreadStoreError::Unsupported`.

No developers.openai.com documentation update is needed for this
internal experimental app-server API surface.
2026-05-07 15:44:43 -07:00

104 lines
3.9 KiB
Rust

use async_trait::async_trait;
use codex_protocol::ThreadId;
use std::any::Any;
use crate::AppendThreadItemsParams;
use crate::ArchiveThreadParams;
use crate::CreateThreadParams;
use crate::ItemPage;
use crate::ListItemsParams;
use crate::ListThreadsParams;
use crate::ListTurnsParams;
use crate::LoadThreadHistoryParams;
use crate::ReadThreadByRolloutPathParams;
use crate::ReadThreadParams;
use crate::ResumeThreadParams;
use crate::StoredThread;
use crate::StoredThreadHistory;
use crate::ThreadPage;
use crate::ThreadStoreError;
use crate::ThreadStoreResult;
use crate::TurnPage;
use crate::UpdateThreadMetadataParams;
/// Storage-neutral thread persistence boundary.
#[async_trait]
pub trait ThreadStore: Any + Send + Sync {
/// Return this store as [`Any`] for implementation-owned escape hatches.
fn as_any(&self) -> &dyn Any;
/// Creates a new live thread.
async fn create_thread(&self, params: CreateThreadParams) -> ThreadStoreResult<()>;
/// Reopens an existing thread for live appends.
async fn resume_thread(&self, params: ResumeThreadParams) -> ThreadStoreResult<()>;
/// Appends items to a live thread.
async fn append_items(&self, params: AppendThreadItemsParams) -> ThreadStoreResult<()>;
/// Materializes the thread if persistence is lazy, then persists all queued items.
async fn persist_thread(&self, thread_id: ThreadId) -> ThreadStoreResult<()>;
/// Flushes all queued items and returns once they are durable/readable.
async fn flush_thread(&self, thread_id: ThreadId) -> ThreadStoreResult<()>;
/// Flushes pending items and closes the live thread writer.
async fn shutdown_thread(&self, thread_id: ThreadId) -> ThreadStoreResult<()>;
/// Discards the live thread writer without forcing pending in-memory items to become durable.
///
/// Core calls this when session initialization fails after a live writer has been created.
/// Implementations should release any live writer resources for the thread while preserving
/// already-durable thread data.
async fn discard_thread(&self, thread_id: ThreadId) -> ThreadStoreResult<()>;
/// Loads persisted history for resume, fork, rollback, and memory jobs.
async fn load_history(
&self,
params: LoadThreadHistoryParams,
) -> ThreadStoreResult<StoredThreadHistory>;
/// Reads a thread summary and optionally its persisted history.
async fn read_thread(&self, params: ReadThreadParams) -> ThreadStoreResult<StoredThread>;
/// Reads a rollout-backed thread by path when the store supports path-addressed lookups.
///
/// Deprecated: new callers should use [`ThreadStore::read_thread`] instead.
async fn read_thread_by_rollout_path(
&self,
params: ReadThreadByRolloutPathParams,
) -> ThreadStoreResult<StoredThread>;
/// Lists stored threads matching the supplied filters.
async fn list_threads(&self, params: ListThreadsParams) -> ThreadStoreResult<ThreadPage>;
/// Lists turns within a stored thread.
async fn list_turns(&self, _params: ListTurnsParams) -> ThreadStoreResult<TurnPage> {
Err(ThreadStoreError::Unsupported {
operation: "list_turns",
})
}
/// Lists persisted items within a stored turn.
async fn list_items(&self, _params: ListItemsParams) -> ThreadStoreResult<ItemPage> {
Err(ThreadStoreError::Unsupported {
operation: "list_items",
})
}
/// Applies a mutable metadata patch and returns the updated thread.
async fn update_thread_metadata(
&self,
params: UpdateThreadMetadataParams,
) -> ThreadStoreResult<StoredThread>;
/// Archives a thread.
async fn archive_thread(&self, params: ArchiveThreadParams) -> ThreadStoreResult<()>;
/// Unarchives a thread and returns its updated metadata.
async fn unarchive_thread(
&self,
params: ArchiveThreadParams,
) -> ThreadStoreResult<StoredThread>;
}