mirror of
https://github.com/openai/codex.git
synced 2026-06-01 19:02:59 +00:00
Support multiple cwd filters for thread list (#18502)
## Summary - Teach app-server `thread/list` to accept either a single `cwd` or an array of cwd filters, returning threads whose recorded session cwd matches any requested path - Add `useStateDbOnly` as an explicit opt-in fast path for callers that want to answer `thread/list` from SQLite without scanning JSONL rollout files - Preserve backwards compatibility: by default, `thread/list` still scans JSONL rollouts and repairs SQLite state - Wire the new cwd array and SQLite-only options through app-server, local/remote thread-store, rollout listing, generated TypeScript/schema fixtures, proto output, and docs ## Test Plan - `cargo test -p codex-app-server-protocol` - `cargo test -p codex-rollout` - `cargo test -p codex-thread-store` - `cargo test -p codex-app-server thread_list` - `just fmt` - `just fix -p codex-app-server-protocol -p codex-rollout -p codex-thread-store -p codex-app-server` - `cargo build -p codex-cli --bin codex`
This commit is contained in:
@@ -3703,15 +3703,27 @@ pub struct ThreadListParams {
|
||||
/// If false or null, only non-archived threads are returned.
|
||||
#[ts(optional = nullable)]
|
||||
pub archived: Option<bool>,
|
||||
/// Optional cwd filter; when set, only threads whose session cwd exactly
|
||||
/// matches this path are returned.
|
||||
#[ts(optional = nullable)]
|
||||
pub cwd: Option<String>,
|
||||
/// Optional cwd filter or filters; when set, only threads whose session cwd
|
||||
/// exactly matches one of these paths are returned.
|
||||
#[ts(optional = nullable, type = "string | Array<string> | null")]
|
||||
pub cwd: Option<ThreadListCwdFilter>,
|
||||
/// If true, return from the state DB without scanning JSONL rollouts to
|
||||
/// repair thread metadata. Omitted or false preserves scan-and-repair
|
||||
/// behavior.
|
||||
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
||||
pub use_state_db_only: bool,
|
||||
/// Optional substring filter for the extracted thread title.
|
||||
#[ts(optional = nullable)]
|
||||
pub search_term: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema)]
|
||||
#[serde(untagged)]
|
||||
pub enum ThreadListCwdFilter {
|
||||
One(String),
|
||||
Many(Vec<String>),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(rename_all = "camelCase", export_to = "v2/")]
|
||||
@@ -7294,6 +7306,46 @@ mod tests {
|
||||
absolute_path("readable")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn thread_list_params_accepts_single_cwd() {
|
||||
let params = serde_json::from_value::<ThreadListParams>(json!({
|
||||
"cwd": "/workspace",
|
||||
}))
|
||||
.expect("single cwd should deserialize");
|
||||
|
||||
assert_eq!(
|
||||
params.cwd,
|
||||
Some(ThreadListCwdFilter::One("/workspace".to_string()))
|
||||
);
|
||||
assert!(!params.use_state_db_only);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn thread_list_params_accepts_multiple_cwds() {
|
||||
let params = serde_json::from_value::<ThreadListParams>(json!({
|
||||
"cwd": ["/workspace", "/other-workspace"],
|
||||
}))
|
||||
.expect("cwd array should deserialize");
|
||||
|
||||
assert_eq!(
|
||||
params.cwd,
|
||||
Some(ThreadListCwdFilter::Many(vec![
|
||||
"/workspace".to_string(),
|
||||
"/other-workspace".to_string(),
|
||||
]))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn thread_list_params_accepts_state_db_only_flag() {
|
||||
let params = serde_json::from_value::<ThreadListParams>(json!({
|
||||
"useStateDbOnly": true,
|
||||
}))
|
||||
.expect("state db only flag should deserialize");
|
||||
|
||||
assert!(params.use_state_db_only);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn collab_agent_state_maps_interrupted_status() {
|
||||
assert_eq!(
|
||||
|
||||
Reference in New Issue
Block a user