This commit is contained in:
jif-oai
2026-05-18 15:32:07 +02:00
parent fd1bdda453
commit 4621cefbc6
3 changed files with 83 additions and 1 deletions

View File

@@ -148,6 +148,7 @@ impl ThreadGoalRequestProcessor {
thread.prepare_external_goal_mutation().await;
}
let should_set_thread_preview = objective.is_some();
let (goal, previous_status) = (if let Some(objective) = objective {
let existing_goal = state_db
.thread_goals()
@@ -221,6 +222,13 @@ impl ThreadGoalRequestProcessor {
.map(|goal| (goal, previous_status))
})
.map_err(|err| invalid_request(err.to_string()))?;
if should_set_thread_preview
&& let Err(err) = state_db
.set_thread_preview_if_empty(thread_id, goal.objective.as_str())
.await
{
warn!("failed to set empty thread preview from goal objective for {thread_id}: {err}");
}
let external_goal_set = ExternalGoalSet {
goal: goal.clone(),
previous_status,

View File

@@ -908,7 +908,7 @@ async fn thread_goal_set_edits_objective_without_resetting_usage() -> Result<()>
codex_home.path(),
"2025-01-05T12-00-00",
"2025-01-05T12:00:00Z",
"materialized thread",
"",
Some("mock_provider"),
/*git_info*/ None,
)?;
@@ -942,6 +942,11 @@ async fn thread_goal_set_edits_objective_without_resetting_usage() -> Result<()>
let state_db =
StateRuntime::init(codex_home.path().to_path_buf(), "mock_provider".into()).await?;
let thread_id = ThreadId::from_string(&thread_id)?;
let thread_metadata = state_db
.get_thread(thread_id)
.await?
.expect("thread metadata should exist");
assert_eq!(thread_metadata.preview.as_deref(), Some("keep polishing"));
let persisted_goal = state_db
.thread_goals()
.get_thread_goal(thread_id)
@@ -980,8 +985,13 @@ async fn thread_goal_set_edits_objective_without_resetting_usage() -> Result<()>
.get_thread_goal(thread_id)
.await?
.expect("goal should still exist");
let thread_metadata = state_db
.get_thread(thread_id)
.await?
.expect("thread metadata should still exist");
assert_eq!(persisted_goal.goal_id, updated_goal.goal_id);
assert_eq!(thread_metadata.preview.as_deref(), Some("keep polishing"));
assert_eq!(edit.goal.objective, "keep polishing with clearer wording");
assert_eq!(edit.goal.status, ThreadGoalStatus::BudgetLimited);
assert_eq!(edit.goal.token_budget, Some(40));

View File

@@ -51,6 +51,29 @@ WHERE threads.id = ?
Ok(row.and_then(|row| row.try_get("memory_mode").ok()))
}
pub async fn set_thread_preview_if_empty(
&self,
thread_id: ThreadId,
preview: &str,
) -> anyhow::Result<bool> {
let preview = preview.trim();
if preview.is_empty() {
return Ok(false);
}
let result = sqlx::query(
r#"
UPDATE threads
SET preview = ?
WHERE id = ? AND preview = ''
"#,
)
.bind(preview)
.bind(thread_id.to_string())
.execute(self.pool.as_ref())
.await?;
Ok(result.rows_affected() > 0)
}
/// Get dynamic tools for a thread, if present.
pub async fn get_dynamic_tools(
&self,
@@ -1569,6 +1592,47 @@ mod tests {
assert_eq!(persisted.preview.as_deref(), Some("migrated goal preview"));
}
#[tokio::test]
async fn set_thread_preview_if_empty_only_fills_blank_preview() {
let codex_home = unique_temp_dir();
let runtime = StateRuntime::init(codex_home.clone(), "test-provider".to_string())
.await
.expect("state db should initialize");
let thread_id =
ThreadId::from_string("00000000-0000-0000-0000-000000000460").expect("valid thread id");
let mut metadata = test_thread_metadata(&codex_home, thread_id, codex_home.clone());
metadata.first_user_message = None;
metadata.preview = None;
runtime
.upsert_thread(&metadata)
.await
.expect("initial upsert should succeed");
let empty_updated = runtime
.set_thread_preview_if_empty(thread_id, " ")
.await
.expect("empty preview update should succeed");
assert!(!empty_updated);
let goal_updated = runtime
.set_thread_preview_if_empty(thread_id, " goal preview ")
.await
.expect("goal preview update should succeed");
assert!(goal_updated);
let overwrite_updated = runtime
.set_thread_preview_if_empty(thread_id, "new preview")
.await
.expect("overwrite preview update should succeed");
assert!(!overwrite_updated);
let persisted = runtime
.get_thread(thread_id)
.await
.expect("thread should load")
.expect("thread should exist");
assert_eq!(persisted.preview.as_deref(), Some("goal preview"));
}
#[tokio::test]
async fn update_thread_git_info_preserves_newer_non_git_metadata() {
let codex_home = unique_temp_dir();