mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
[2 of 2] Finish moving goal runtime to extension (#26548)
## Stack 1. [#26547](https://github.com/openai/codex/pull/26547) - [1 of 2] Align goal extension with core behavior 2. [#26548](https://github.com/openai/codex/pull/26548) - [2 of 2] Move goal runtime to extension ## Why This PR completes the switch of the goal behavior to the extension-backed runtime and removes the old core goal implementation. ## What Changed - Installs the goal extension for app-server `ThreadManager` sessions. - Routes app-server thread goal `get`, `set`, and `clear` through `GoalService`. - Uses thread-idle lifecycle emission after goal resume and snapshot ordering so the extension can decide whether to continue the goal. - Forwards extension goal updates through a FIFO async app-server notification path so backpressure does not drop them or reorder updates. - Keeps review turns from enabling goal runtime behavior. - Plans extension tools before dynamic tools so built-in goal tool names keep their old precedence when goals are enabled. - Removes the old core goal runtime, core goal tool handlers, and core goal tool specs. - Updates tests that were coupled to the core-owned goal runtime while leaving the legacy `<goal_context>` compatibility path in core for old threads. - Removes the stale cargo-shear ignore now that `codex-goal-extension` is used by the workspace. - Keeps realtime event matching exhaustive after removing the old goal-specific realtime text path. ## Validation - Ran manual `/goal` runs in TUI. Validated time accounting matched wall-clock time and goal lifecycle state transitions.
This commit is contained in:
@@ -244,12 +244,22 @@ pub(super) async fn ensure_listener_task_running(
|
||||
if thread_state.listener_matches(&conversation) {
|
||||
return Ok(());
|
||||
}
|
||||
thread_state.set_listener(
|
||||
let (listener_command_rx, listener_generation) = thread_state.set_listener(
|
||||
cancel_tx,
|
||||
&conversation,
|
||||
watch_registration,
|
||||
thread_settings_baseline,
|
||||
)
|
||||
);
|
||||
let Some(listener_command_tx) = thread_state.listener_command_tx() else {
|
||||
tracing::warn!(
|
||||
"thread listener command sender missing immediately after listener registration"
|
||||
);
|
||||
return Ok(());
|
||||
};
|
||||
listener_task_context
|
||||
.thread_state_manager
|
||||
.register_listener_command_tx(conversation_id, listener_command_tx);
|
||||
(listener_command_rx, listener_generation)
|
||||
};
|
||||
let ListenerTaskContext {
|
||||
outgoing,
|
||||
@@ -378,6 +388,7 @@ pub(super) async fn ensure_listener_task_running(
|
||||
|
||||
let mut thread_state = thread_state.lock().await;
|
||||
if thread_state.listener_generation == listener_generation {
|
||||
thread_state_manager.unregister_listener_command_tx(conversation_id);
|
||||
thread_state.clear_listener();
|
||||
}
|
||||
});
|
||||
@@ -471,12 +482,12 @@ pub(super) async fn handle_thread_listener_command(
|
||||
)
|
||||
.await;
|
||||
}
|
||||
ThreadListenerCommand::EmitThreadGoalUpdated { goal } => {
|
||||
ThreadListenerCommand::EmitThreadGoalUpdated { turn_id, goal } => {
|
||||
outgoing
|
||||
.send_server_notification(ServerNotification::ThreadGoalUpdated(
|
||||
ThreadGoalUpdatedNotification {
|
||||
thread_id: conversation_id.to_string(),
|
||||
turn_id: None,
|
||||
turn_id,
|
||||
goal,
|
||||
},
|
||||
))
|
||||
@@ -616,12 +627,6 @@ pub(super) async fn handle_pending_thread_resume_request(
|
||||
}
|
||||
}
|
||||
|
||||
if pending.emit_thread_goal_update
|
||||
&& let Err(err) = conversation.apply_goal_resume_runtime_effects().await
|
||||
{
|
||||
tracing::warn!("failed to apply goal resume runtime effects: {err}");
|
||||
}
|
||||
|
||||
let ThreadConfigSnapshot {
|
||||
model,
|
||||
model_provider_id,
|
||||
@@ -691,11 +696,9 @@ pub(super) async fn handle_pending_thread_resume_request(
|
||||
.replay_requests_to_connection_for_thread(connection_id, conversation_id)
|
||||
.await;
|
||||
// App-server owns resume response and snapshot ordering, so wait until
|
||||
// replay completes before letting core start goal continuation.
|
||||
if pending.emit_thread_goal_update
|
||||
&& let Err(err) = conversation.continue_active_goal_if_idle().await
|
||||
{
|
||||
tracing::warn!("failed to continue active goal after running-thread resume: {err}");
|
||||
// replay completes before letting extensions react to the idle thread.
|
||||
if pending.emit_thread_goal_update {
|
||||
conversation.emit_thread_idle_lifecycle_if_idle().await;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user