mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
Add goal TUI UX (5 / 5) (#18077)
Adds the TUI user experience for goals on top of the core runtime from PR 4. ## Why Users need a direct TUI control surface for long-running goals. The UI should make the current goal visible, support common goal actions without waiting for a model turn, and avoid confusing end-of-turn notifications while an active goal is immediately continuing. ## What changed - Added `/goal` summary rendering for the current goal, including active, paused, budget-limited, and complete states. - Added `/goal <objective>` creation/replacement through the app-server goal API rather than a model prompt. - Added `/goal clear`, `/goal pause`, and `/goal unpause` command variants. - Added a confirmation menu when the user enters a new goal while another goal already exists. - Updated `/goal` help and summary tip text so it reflects the supported command variants without advertising slash-command token budgets. - Added footer/statusline goal indicators, including elapsed time and token budget display when a budget exists from API/tool-created goals. - Consumes goal updated/cleared notifications so the TUI stays in sync with external app-server changes. - Suppresses end-of-turn desktop notifications only when a goal is still active and follow-up work is expected. - Preserves slash-command history behavior and avoids leaking queued `/goal` state into unrelated submissions. ## Verification - Added TUI unit and snapshot coverage for goal command availability, summary rendering, control commands, replacement menu behavior, status/footer display, notification handling, and command history.
This commit is contained in:
committed by
GitHub
Unverified
parent
4167628622
commit
f1c963d77e
@@ -43,6 +43,13 @@ use codex_app_server_protocol::ThreadCompactStartParams;
|
||||
use codex_app_server_protocol::ThreadCompactStartResponse;
|
||||
use codex_app_server_protocol::ThreadForkParams;
|
||||
use codex_app_server_protocol::ThreadForkResponse;
|
||||
use codex_app_server_protocol::ThreadGoalClearParams;
|
||||
use codex_app_server_protocol::ThreadGoalClearResponse;
|
||||
use codex_app_server_protocol::ThreadGoalGetParams;
|
||||
use codex_app_server_protocol::ThreadGoalGetResponse;
|
||||
use codex_app_server_protocol::ThreadGoalSetParams;
|
||||
use codex_app_server_protocol::ThreadGoalSetResponse;
|
||||
use codex_app_server_protocol::ThreadGoalStatus;
|
||||
use codex_app_server_protocol::ThreadInjectItemsParams;
|
||||
use codex_app_server_protocol::ThreadInjectItemsResponse;
|
||||
use codex_app_server_protocol::ThreadListParams;
|
||||
@@ -667,6 +674,60 @@ impl AppServerSession {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn thread_goal_get(
|
||||
&mut self,
|
||||
thread_id: ThreadId,
|
||||
) -> Result<ThreadGoalGetResponse> {
|
||||
let request_id = self.next_request_id();
|
||||
self.client
|
||||
.request_typed(ClientRequest::ThreadGoalGet {
|
||||
request_id,
|
||||
params: ThreadGoalGetParams {
|
||||
thread_id: thread_id.to_string(),
|
||||
},
|
||||
})
|
||||
.await
|
||||
.wrap_err("thread/goal/get failed in TUI")
|
||||
}
|
||||
|
||||
pub(crate) async fn thread_goal_set(
|
||||
&mut self,
|
||||
thread_id: ThreadId,
|
||||
objective: Option<String>,
|
||||
status: Option<ThreadGoalStatus>,
|
||||
token_budget: Option<Option<i64>>,
|
||||
) -> Result<ThreadGoalSetResponse> {
|
||||
let request_id = self.next_request_id();
|
||||
self.client
|
||||
.request_typed(ClientRequest::ThreadGoalSet {
|
||||
request_id,
|
||||
params: ThreadGoalSetParams {
|
||||
thread_id: thread_id.to_string(),
|
||||
objective,
|
||||
status,
|
||||
token_budget,
|
||||
},
|
||||
})
|
||||
.await
|
||||
.wrap_err("thread/goal/set failed in TUI")
|
||||
}
|
||||
|
||||
pub(crate) async fn thread_goal_clear(
|
||||
&mut self,
|
||||
thread_id: ThreadId,
|
||||
) -> Result<ThreadGoalClearResponse> {
|
||||
let request_id = self.next_request_id();
|
||||
self.client
|
||||
.request_typed(ClientRequest::ThreadGoalClear {
|
||||
request_id,
|
||||
params: ThreadGoalClearParams {
|
||||
thread_id: thread_id.to_string(),
|
||||
},
|
||||
})
|
||||
.await
|
||||
.wrap_err("thread/goal/clear failed in TUI")
|
||||
}
|
||||
|
||||
pub(crate) async fn logout_account(&mut self) -> Result<()> {
|
||||
let request_id = self.next_request_id();
|
||||
let _: LogoutAccountResponse = self
|
||||
|
||||
Reference in New Issue
Block a user