mirror of
https://github.com/openai/codex.git
synced 2026-11-13 14:46:14 +00:00
feat(app-server): list descendant threads by ancestor (#29591)
## Why `thread/list` can filter direct children with `parentThreadId`, but clients cannot request an entire spawned subtree. Discovering every descendant requires repeated client-side requests and gives up the database's existing filtering and pagination path. ## What changed Experimental clients can use `ancestorThreadId` to return strict descendants at any depth while `parentThreadId` retains its direct-child meaning. The filters are mutually exclusive, the ancestor is excluded, and every result preserves its immediate `parentThreadId` so callers can reconstruct the tree. ## How it works - **Explicit relationship:** Internal list parameters distinguish direct children from transitive descendants without changing the meaning of `parentThreadId`. - **Existing graph:** Persisted parent-child spawn edges remain the source of truth, so descendant lookup needs no schema migration or ancestry cache. - **Indexed traversal:** A recursive SQLite query starts from the parent-edge index, walks each generation, and applies thread filters, sorting, and cursor pagination in the same database request. - **Reconstructable results:** The response stays flat and normally ordered while carrying each descendant's immediate parent. ## Verification Ran 550 tests across the protocol, state, rollout, and thread-store crates, then reran the four focused state, store, and app-server descendant-listing tests after the final diff reduction. Scoped Clippy and formatting checks passed. Stable and experimental schema generation was checked; the stable fixtures remain unchanged while the experimental schema includes the new field.
This commit is contained in:
1 parent
3ccef20ef4
commit
8057603d0c
30 files changed
+494
-106
No files matched your search
@@ -1088,10 +1088,15 @@ pub struct ThreadListParams {
|
||||
/// Optional substring filter for the extracted thread title.
|
||||
#[ts(optional = nullable)]
|
||||
pub search_term: Option<String>,
|
||||
/// Optional direct parent thread filter.
|
||||
/// Optional direct parent thread filter. Mutually exclusive with `ancestorThreadId`.
|
||||
#[experimental("thread/list.parentThreadId")]
|
||||
#[ts(optional = nullable)]
|
||||
pub parent_thread_id: Option<String>,
|
||||
/// Optional ancestor thread filter. Returns spawned descendants at any depth, excluding the
|
||||
/// ancestor itself. Mutually exclusive with `parentThreadId`.
|
||||
#[experimental("thread/list.ancestorThreadId")]
|
||||
#[ts(optional = nullable)]
|
||||
pub ancestor_thread_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
|
||||
Reference in new issue
Block a user