mirror of
https://github.com/openai/codex.git
synced 2026-05-30 07:50:17 +00:00
Fix goal update and add /goal edit command in TUI (#21954)
## Why Users have requested the ability to edit a goal's objective after a goal has been created. This PR exposes a new `/goal edit` command in the TUI to address this request. In the process of implementing this, I also noticed an existing bug in the goal runtime. When a goal's objective is updated through the `thread/goal/set` app server API, the goal runtime didn't emit a new steering prompt to tell the agent about the new objective. This PR also fixes this hole. ## What Changed - Adds `/goal edit` in the TUI, opening an edit box prefilled with the current goal objective. - Keeps active and paused goals in their current state, resets completed goals to active, keeps budget-limited goals budget-limited, and preserves the existing token budget. - Changes the existing `thread/goal/set` behavior so editing an objective preserves goal accounting instead of resetting it. The older reset-on-new-objective behavior was left over from before `thread/goal/clear`; clients that need to reset accounting can now clear the existing goal and create a new one. - Reuses the existing goal set API path; this does not add or change app-server protocol surface area. - Adds a dedicated goal runtime steering prompt when an externally persisted goal mutation changes the objective, so active turns receive the updated objective. ## Validation - Make sure `/goal edit` returns an error if no goal currently exists - Make sure `/goal edit` displays an edit box that can be optionally canceled with no side effects - Make sure that an edited goal results in a steer so the agent starts pursuing the new objective - Make sure the new objective is reflected in the goal if you use `/goal` to display the goal summary - Make sure that `/goal edit` doesn't reset the token budget, time/token accounting on the updated goal
This commit is contained in:
@@ -153,15 +153,13 @@ impl ThreadGoalRequestProcessor {
|
||||
.get_thread_goal(thread_id)
|
||||
.await
|
||||
.map_err(|err| invalid_request(err.to_string()))?;
|
||||
if let Some(goal) = existing_goal.as_ref().filter(|goal| {
|
||||
goal.objective == objective
|
||||
&& goal.status != codex_state::ThreadGoalStatus::Complete
|
||||
}) {
|
||||
let previous_status = ExternalGoalPreviousStatus::Existing(goal.status);
|
||||
if let Some(goal) = existing_goal.as_ref() {
|
||||
let previous_status = ExternalGoalPreviousStatus::from(goal);
|
||||
state_db
|
||||
.update_thread_goal(
|
||||
thread_id,
|
||||
codex_state::ThreadGoalUpdate {
|
||||
objective: Some(objective.to_string()),
|
||||
status,
|
||||
token_budget: params.token_budget,
|
||||
expected_goal_id: Some(goal.goal_id.clone()),
|
||||
@@ -198,11 +196,12 @@ impl ThreadGoalRequestProcessor {
|
||||
"cannot update goal for thread {thread_id}: no goal exists"
|
||||
)));
|
||||
};
|
||||
let previous_status = ExternalGoalPreviousStatus::Existing(existing_goal.status);
|
||||
let previous_status = ExternalGoalPreviousStatus::from(&existing_goal);
|
||||
state_db
|
||||
.update_thread_goal(
|
||||
thread_id,
|
||||
codex_state::ThreadGoalUpdate {
|
||||
objective: None,
|
||||
status,
|
||||
token_budget: params.token_budget,
|
||||
expected_goal_id: None,
|
||||
|
||||
Reference in New Issue
Block a user