mirror of
https://github.com/openai/codex.git
synced 2026-09-20 12:47:38 +00:00
## What changed Show a brief starfield in the empty composer when a new task starts with Astra or the user selects Astra through `/model` before entering ordinary prompt content. - Respect `tui.animations`, `tui.whimsy`, and true-color support; protect the placeholder and cursor and fade out by 15 seconds. - Preserve eligibility through recognized slash commands, but permanently dismiss it after ordinary draft content, attachments, or work. Carry draft eligibility through startup and disconnected editing. - Exclude resumed and forked tasks, and verify model-picker changes against the originating task and effective model when applied. - Hide the effect during overlays or focus loss without restarting its deadline or scheduling hidden animation frames. ## Testing Add regression tests and snapshots for task eligibility, model-picker transitions, draft and paste handling, history search, overlays, submissions, rendering protection, and animation expiry. GitOrigin-RevId: 832705543e9cae1d561125ece853a16c4eefe627
1609 lines
51 KiB
Rust
1609 lines
51 KiB
Rust
//! Application-level events used to coordinate UI actions.
|
|
//!
|
|
//! `AppEvent` is the internal message bus between UI components and the top-level `App` loop.
|
|
//! Widgets emit events to request actions that must be handled at the app layer (like opening
|
|
//! pickers, persisting configuration, or shutting down the agent), without needing direct access to
|
|
//! `App` internals.
|
|
//!
|
|
//! Exit is modelled explicitly via `AppEvent::Exit(ExitMode)` so callers can request shutdown-first
|
|
//! quits without reaching into the app loop or coupling to shutdown/exit sequencing.
|
|
|
|
use std::path::PathBuf;
|
|
use std::sync::Arc;
|
|
use std::sync::atomic::AtomicBool;
|
|
use tokio_util::sync::CancellationToken;
|
|
|
|
use crate::inline_visualization::InlineVisualizationContext;
|
|
use codex_app_server_protocol::AddCreditsNudgeCreditType;
|
|
use codex_app_server_protocol::AddCreditsNudgeEmailStatus;
|
|
use codex_app_server_protocol::ConsumeAccountRateLimitResetCreditResponse;
|
|
use codex_app_server_protocol::DynamicToolCallResponse;
|
|
use codex_app_server_protocol::GetAccountRateLimitsResponse;
|
|
use codex_app_server_protocol::MarketplaceAddResponse;
|
|
use codex_app_server_protocol::MarketplaceRemoveResponse;
|
|
use codex_app_server_protocol::MarketplaceUpgradeResponse;
|
|
use codex_app_server_protocol::McpServerStatus;
|
|
use codex_app_server_protocol::McpServerStatusDetail;
|
|
use codex_app_server_protocol::PluginInstallResponse;
|
|
use codex_app_server_protocol::PluginListResponse;
|
|
use codex_app_server_protocol::PluginMarketplaceEntry;
|
|
use codex_app_server_protocol::PluginReadParams;
|
|
use codex_app_server_protocol::PluginReadResponse;
|
|
use codex_app_server_protocol::PluginUninstallResponse;
|
|
use codex_app_server_protocol::RequestId as AppServerRequestId;
|
|
use codex_app_server_protocol::SkillsListResponse;
|
|
use codex_app_server_protocol::Thread;
|
|
use codex_app_server_protocol::ThreadGoalStatus;
|
|
use codex_app_server_protocol::ThreadItemsListResponse;
|
|
use codex_connectors::AppInfo;
|
|
use codex_file_search::FileMatch;
|
|
use codex_message_history::HistoryBatchCursor;
|
|
use codex_protocol::ThreadId;
|
|
use codex_protocol::openai_models::ModelPreset;
|
|
use codex_protocol::openai_models::ReasoningEffort;
|
|
use codex_utils_absolute_path::AbsolutePathBuf;
|
|
use codex_utils_approval_presets::ApprovalPreset;
|
|
use strum_macros::IntoStaticStr;
|
|
use uuid::Uuid;
|
|
|
|
use crate::app_command::AppCommand;
|
|
use crate::app_server_session::AppServerStartedThread;
|
|
use crate::bottom_pane::ApprovalRequest;
|
|
use crate::bottom_pane::StatusLineItem;
|
|
use crate::bottom_pane::TerminalTitleItem;
|
|
use crate::chatwidget::AstraModelPickerAction;
|
|
use crate::chatwidget::ConnectorScopeGeneration;
|
|
use crate::chatwidget::ThreadUsageOutcome;
|
|
use crate::chatwidget::UserMessage;
|
|
use crate::experimental_features::FeatureWriteResult;
|
|
use crate::goal_files::GoalDraft;
|
|
use codex_app_server_protocol::AskForApproval;
|
|
use codex_config::types::ApprovalsReviewer;
|
|
use codex_features::Feature;
|
|
use codex_plugin::PluginCapabilitySummary;
|
|
use codex_protocol::config_types::CollaborationModeMask;
|
|
use codex_protocol::models::ActivePermissionProfile;
|
|
use codex_realtime_webrtc::StartedRealtimeWebrtcSession;
|
|
|
|
use crate::history_cell::HistoryCell;
|
|
|
|
/// Confirmed server lifecycle operations available from the agents dashboard.
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
pub(crate) enum AgentsOverviewAction {
|
|
Archive,
|
|
Delete,
|
|
}
|
|
|
|
/// Whether a managed checkout starts fresh or preserves the current conversation.
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub(crate) enum ManagedWorktreeMode {
|
|
New,
|
|
Fork,
|
|
}
|
|
|
|
/// Checkout creation result returned from the blocking Git task to the TUI event loop.
|
|
/// Prepared checkout and destination configuration consumed on a fresh event-loop stack.
|
|
#[derive(Debug)]
|
|
pub(crate) struct ManagedWorktreeTransition {
|
|
pub(crate) source_thread_id: ThreadId,
|
|
pub(crate) source_cwd: AbsolutePathBuf,
|
|
pub(crate) manager: codex_worktree::WorktreeManager,
|
|
pub(crate) checkout: codex_worktree::ManagedWorktree,
|
|
pub(crate) config: Box<crate::legacy_core::config::Config>,
|
|
pub(crate) mode: ManagedWorktreeMode,
|
|
pub(crate) name: Option<String>,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub(crate) struct ManagedWorktreeCreated {
|
|
pub(crate) source_thread_id: ThreadId,
|
|
pub(crate) source_cwd: AbsolutePathBuf,
|
|
pub(crate) mode: ManagedWorktreeMode,
|
|
pub(crate) name: Option<String>,
|
|
pub(crate) result: Result<
|
|
(
|
|
codex_worktree::WorktreeManager,
|
|
codex_worktree::ManagedWorktree,
|
|
),
|
|
String,
|
|
>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub(crate) enum ThreadGoalSetMode {
|
|
ConfirmIfExists,
|
|
ReplaceExisting,
|
|
UpdateExisting {
|
|
status: ThreadGoalStatus,
|
|
token_budget: Option<i64>,
|
|
},
|
|
}
|
|
|
|
/// One absolute history offset returned by a batch lookup.
|
|
///
|
|
/// Malformed rows retain their offset with `entry` set to `None` so the composer can cache the gap
|
|
/// without shifting every older record.
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub(crate) struct HistoryBatchEntryResponse {
|
|
pub(crate) offset: usize,
|
|
pub(crate) entry: Option<String>,
|
|
}
|
|
|
|
/// Persistent-history data routed back to the thread that requested it.
|
|
///
|
|
/// Batch responses preserve absolute offsets and malformed-row gaps so the composer can cache the
|
|
/// data independently of whichever search query is active when the response arrives.
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub(crate) enum HistoryLookupResponse {
|
|
Entry {
|
|
offset: usize,
|
|
log_id: u64,
|
|
entry: Option<String>,
|
|
},
|
|
Batch {
|
|
cursor: HistoryBatchCursor,
|
|
log_id: u64,
|
|
entries: Vec<HistoryBatchEntryResponse>,
|
|
next_older_cursor: Option<HistoryBatchCursor>,
|
|
},
|
|
BatchError {
|
|
cursor: HistoryBatchCursor,
|
|
log_id: u64,
|
|
},
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub(crate) enum ConsolidationScrollbackReflow {
|
|
IfResizeReflowRan,
|
|
Required,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
#[cfg_attr(not(target_os = "windows"), allow(dead_code))]
|
|
pub(crate) enum WindowsSandboxEnableMode {
|
|
Elevated,
|
|
Legacy,
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
#[cfg_attr(not(target_os = "windows"), allow(dead_code))]
|
|
pub(crate) struct ConnectorsSnapshot {
|
|
pub(crate) connectors: Vec<AppInfo>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
pub(crate) enum PluginLocation {
|
|
Local { marketplace_path: AbsolutePathBuf },
|
|
Remote { marketplace_name: String },
|
|
}
|
|
|
|
impl PluginLocation {
|
|
pub(crate) fn into_request_params(self) -> (Option<AbsolutePathBuf>, Option<String>) {
|
|
match self {
|
|
PluginLocation::Local { marketplace_path } => (Some(marketplace_path), None),
|
|
PluginLocation::Remote { marketplace_name } => (None, Some(marketplace_name)),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
pub(crate) struct PluginRemoteSectionError {
|
|
pub(crate) section_id: String,
|
|
pub(crate) label: String,
|
|
pub(crate) message: String,
|
|
}
|
|
|
|
/// Distinguishes why a rate-limit refresh was requested so the completion
|
|
/// handler can route the result correctly.
|
|
///
|
|
/// A `StartupPrefetch` fires once, concurrently with the rest of TUI init, and
|
|
/// updates the cached snapshots and any available reset-credit notice (no
|
|
/// status card to finalize). A `StatusCommand` is tied to a specific `/status`
|
|
/// invocation and must call `finish_status_rate_limit_refresh` when done so the
|
|
/// card stops showing a "refreshing" state. A `UsageMenu` refreshes a cached
|
|
/// zero reset count so the disabled menu entry can become available without a
|
|
/// restart. A `ResetPicker` refreshes the rate limits and detailed reset-credit
|
|
/// rows before showing redemption choices.
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub(crate) enum RateLimitRefreshOrigin {
|
|
/// Eagerly fetched after bootstrap for `/status` data and reset availability.
|
|
StartupPrefetch { reset_hint_request_id: u64 },
|
|
/// User-initiated via `/status`; the `request_id` correlates with the
|
|
/// status card that should be updated when the fetch completes.
|
|
StatusCommand { request_id: u64 },
|
|
/// User reopened `/usage` while the cached reset-credit count was zero.
|
|
UsageMenu { request_id: u64 },
|
|
/// User opened the reset-credit picker.
|
|
ResetPicker { request_id: u64 },
|
|
/// Refresh requested after a reset credit was successfully consumed.
|
|
ResetConsume { request_id: u64 },
|
|
/// Refresh backend recovery after an inference limit error.
|
|
Recovery,
|
|
/// Background account usage read, scheduled more frequently near exhaustion.
|
|
Periodic,
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
pub(crate) enum KeymapEditIntent {
|
|
ReplaceAll,
|
|
AddAlternate,
|
|
ReplaceOne { old_key: String },
|
|
}
|
|
|
|
/// Number of key strokes recorded by one `/keymap` capture.
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub(crate) enum KeymapCaptureMode {
|
|
SingleKey,
|
|
Chord,
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
pub(crate) enum TranscriptExportDestination {
|
|
Clipboard,
|
|
File(PathBuf),
|
|
}
|
|
|
|
/// Deliver a generated title to its originating automatic rename or editable prompt.
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
pub(crate) enum ThreadTitleDestination {
|
|
/// Name the thread only if the user has not already named it.
|
|
Automatic,
|
|
/// Prefill only the still-active rename prompt with the matching request ID.
|
|
RenameSuggestion { request_id: Uuid },
|
|
}
|
|
|
|
/// Identifies the policy that initiated a recap request.
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub(crate) enum RecapTrigger {
|
|
Automatic,
|
|
Manual,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub(crate) struct AgentsOverviewThreadRefresh {
|
|
pub(crate) threads: std::collections::HashMap<ThreadId, Option<Thread>>,
|
|
pub(crate) last_messages: std::collections::HashMap<ThreadId, String>,
|
|
pub(crate) recent_seed_complete: bool,
|
|
}
|
|
|
|
#[allow(clippy::large_enum_variant)]
|
|
#[derive(Debug, IntoStaticStr)]
|
|
pub(crate) enum AppEvent {
|
|
OpenDaemonMenu,
|
|
ConfirmDaemonUpdate(crate::update_action::DaemonUpdateSource),
|
|
RunDaemonUpdate(crate::update_action::DaemonUpdateSource),
|
|
ReviewMisalignment(Arc<crate::chatwidget::MisalignmentReview>),
|
|
ContinueMisalignment(Arc<crate::chatwidget::MisalignmentReview>),
|
|
CloseMisalignmentReview,
|
|
/// Open the daemon-wide overview of recent and locally retained root sessions.
|
|
OpenAgentsOverview,
|
|
/// Update the daemon-wide overview after a background thread listing finishes.
|
|
AgentsOverviewThreadsLoaded {
|
|
request_id: Uuid,
|
|
result: Result<AgentsOverviewThreadRefresh, String>,
|
|
},
|
|
/// Switch to a root session selected from the shared dashboard.
|
|
SelectAgentsOverviewThread {
|
|
thread_id: ThreadId,
|
|
},
|
|
/// Open an empty session in the selected checkout.
|
|
NewAgentsOverviewSession {
|
|
cwd: Option<AbsolutePathBuf>,
|
|
},
|
|
/// Create an empty session in a worktree from the selected project's default branch.
|
|
NewAgentsOverviewWorktree {
|
|
cwd: Option<AbsolutePathBuf>,
|
|
},
|
|
AgentsOverviewWorktreeCreated(Result<crate::app::PendingWorktree, String>),
|
|
/// Rename a task directly from the shared dashboard.
|
|
RenameAgentsOverviewThread {
|
|
thread_id: ThreadId,
|
|
name: String,
|
|
},
|
|
/// Generate an editable title suggestion for the active rename prompt.
|
|
SuggestThreadName {
|
|
thread_id: ThreadId,
|
|
request_id: Uuid,
|
|
},
|
|
/// Register a hidden title-generation thread started in the background.
|
|
ThreadTitleStarted {
|
|
cancellation: CancellationToken,
|
|
thread_id: ThreadId,
|
|
destination: ThreadTitleDestination,
|
|
prompt: String,
|
|
effort: Option<ReasoningEffort>,
|
|
result: Result<String, String>,
|
|
},
|
|
/// Route a hidden title request to its automatic rename or editable prompt.
|
|
GeneratedThreadTitle {
|
|
cancellation: CancellationToken,
|
|
thread_id: ThreadId,
|
|
temporary_thread_id: ThreadId,
|
|
destination: ThreadTitleDestination,
|
|
result: Result<String, String>,
|
|
},
|
|
/// Interrupt a task directly from the shared dashboard.
|
|
StopAgentsOverviewThread {
|
|
thread_id: ThreadId,
|
|
},
|
|
/// Hide a dashboard row locally without stopping its task.
|
|
HideAgentsOverviewThread {
|
|
thread_id: ThreadId,
|
|
},
|
|
/// Confirm a server lifecycle action for the selected dashboard task.
|
|
ConfirmAgentsOverviewAction {
|
|
thread_id: ThreadId,
|
|
action: AgentsOverviewAction,
|
|
},
|
|
/// Execute a confirmed dashboard lifecycle action.
|
|
RunAgentsOverviewAction {
|
|
thread_id: ThreadId,
|
|
action: AgentsOverviewAction,
|
|
},
|
|
/// Start the shared app-server daemon without moving the current embedded session.
|
|
#[cfg(any(unix, windows))]
|
|
StartAgentsDaemon,
|
|
/// Report whether starting the shared app-server daemon succeeded.
|
|
#[cfg(any(unix, windows))]
|
|
AgentsDaemonStarted {
|
|
result: Result<(), String>,
|
|
},
|
|
/// Open the agent picker for switching active threads.
|
|
OpenAgentPicker,
|
|
/// Merge a completed root-scoped agent-picker refresh without blocking terminal input.
|
|
AgentPickerThreadsLoaded {
|
|
primary_thread_id: ThreadId,
|
|
request_id: Uuid,
|
|
result: Result<Vec<Thread>, String>,
|
|
},
|
|
/// Switch the active thread to the selected agent.
|
|
SelectAgentThread(ThreadId),
|
|
|
|
/// Fork the current thread into a transient side conversation.
|
|
StartSide {
|
|
parent_thread_id: ThreadId,
|
|
user_message: Option<UserMessage>,
|
|
},
|
|
|
|
/// Submit an op to the specified thread, regardless of current focus.
|
|
SubmitThreadOp {
|
|
thread_id: ThreadId,
|
|
op: AppCommand,
|
|
},
|
|
|
|
/// Confirm retrying a safety-buffered turn with the server-selected model.
|
|
ConfirmSafetyBufferedRetry {
|
|
thread_id: ThreadId,
|
|
turn_id: String,
|
|
model: String,
|
|
turn: AppCommand,
|
|
prompt: UserMessage,
|
|
},
|
|
|
|
/// Sign the challenge associated with an approved elicitation.
|
|
UserVerificationApproved {
|
|
thread_id: ThreadId,
|
|
server_name: String,
|
|
request_id: AppServerRequestId,
|
|
},
|
|
/// Return a controller-owned verification result, never a native provider handle.
|
|
UserVerificationFinished {
|
|
thread_id: ThreadId,
|
|
server_name: String,
|
|
request_id: AppServerRequestId,
|
|
attempt_id: Uuid,
|
|
result: Result<codex_app_server_protocol::UserVerificationProof, String>,
|
|
},
|
|
|
|
/// Interrupt, fork, and retry a safety-buffered turn with the server-selected model.
|
|
RetrySafetyBufferedTurn {
|
|
thread_id: ThreadId,
|
|
turn_id: String,
|
|
model: String,
|
|
turn: AppCommand,
|
|
prompt: UserMessage,
|
|
},
|
|
|
|
/// Deliver a synthetic history lookup response to a specific thread channel.
|
|
ThreadHistoryEntryResponse {
|
|
thread_id: ThreadId,
|
|
event: HistoryLookupResponse,
|
|
},
|
|
|
|
/// Refill terminal scrollback from older paginated history after its rows reflow.
|
|
RequestOlderScrollbackHistory {
|
|
thread_id: ThreadId,
|
|
},
|
|
|
|
/// One background-loaded page of older Ctrl+T transcript history.
|
|
OlderThreadHistoryLoaded {
|
|
thread_id: ThreadId,
|
|
cursor: String,
|
|
result: Result<ThreadItemsListResponse, String>,
|
|
},
|
|
|
|
/// Open the filename prompt for an on-demand Markdown transcript export.
|
|
OpenTranscriptExportFilePrompt,
|
|
|
|
/// Export all current-thread history to the selected destination.
|
|
ExportTranscript {
|
|
destination: TranscriptExportDestination,
|
|
},
|
|
|
|
/// Copy a picker selection while retaining its clipboard lease in the chat widget.
|
|
CopySelection {
|
|
text: Arc<str>,
|
|
label: String,
|
|
format: crate::clipboard_copy::CopyFormat,
|
|
},
|
|
|
|
/// Persist a submitted prompt in the cross-session message history.
|
|
AppendMessageHistoryEntry {
|
|
thread_id: ThreadId,
|
|
text: String,
|
|
},
|
|
|
|
/// Persist a branch discovered from an App git-action directive into thread metadata.
|
|
SyncThreadGitBranch {
|
|
thread_id: ThreadId,
|
|
branch: String,
|
|
cwd: PathBuf,
|
|
},
|
|
|
|
/// Fetch a persistent cross-session message history entry by offset.
|
|
LookupMessageHistoryEntry {
|
|
thread_id: ThreadId,
|
|
offset: usize,
|
|
log_id: u64,
|
|
},
|
|
|
|
/// Fetch a bounded batch of persistent history entries for reverse search.
|
|
LookupMessageHistoryBatch {
|
|
thread_id: ThreadId,
|
|
cursor: HistoryBatchCursor,
|
|
log_id: u64,
|
|
},
|
|
|
|
/// Start a new session, optionally assigning it a name.
|
|
NewSession {
|
|
name: Option<String>,
|
|
},
|
|
|
|
/// Create a managed checkout and start or fork a session into it.
|
|
StartManagedWorktree {
|
|
mode: ManagedWorktreeMode,
|
|
name: Option<String>,
|
|
},
|
|
/// Continue a checkout transition after synchronous Git work finishes off-loop.
|
|
ManagedWorktreeCreated(Box<ManagedWorktreeCreated>),
|
|
|
|
BrowseManagedWorktrees,
|
|
ManagedWorktreesLoaded {
|
|
request: crate::worktree_browser::Request,
|
|
result: Result<Vec<crate::worktree_browser::Entry>, String>,
|
|
},
|
|
ManagedWorktreeAction {
|
|
request: crate::worktree_browser::Request,
|
|
action: crate::worktree_browser::Action,
|
|
},
|
|
ShowManagedWorktreeActions {
|
|
request: crate::worktree_browser::Request,
|
|
entry: crate::worktree_browser::Entry,
|
|
},
|
|
ConfirmManagedWorktreeRemoval {
|
|
request: crate::worktree_browser::Request,
|
|
root: PathBuf,
|
|
},
|
|
RemoveManagedWorktree {
|
|
request: crate::worktree_browser::Request,
|
|
root: PathBuf,
|
|
},
|
|
ManagedWorktreeRemoved {
|
|
root: PathBuf,
|
|
result: Result<(), String>,
|
|
},
|
|
|
|
/// Change the working directory of the originating idle primary thread.
|
|
ChangeWorkingDirectory {
|
|
thread_id: ThreadId,
|
|
requested_cwd: PathBuf,
|
|
},
|
|
|
|
/// Result of the fresh startup thread that is attached after the input UI is live.
|
|
StartupThreadStarted {
|
|
result: color_eyre::Result<AppServerStartedThread>,
|
|
},
|
|
|
|
/// Register a dynamically created background thread before its first turn starts.
|
|
DynamicToolThreadStarted {
|
|
thread_id: ThreadId,
|
|
task_tools_available: bool,
|
|
registered: tokio::sync::oneshot::Sender<()>,
|
|
},
|
|
|
|
/// Return a completed client-owned dynamic tool call to app server.
|
|
DynamicToolCallCompleted {
|
|
request_id: AppServerRequestId,
|
|
response: DynamicToolCallResponse,
|
|
},
|
|
|
|
/// Register task tools inherited by a dynamically created thread.
|
|
TaskToolsAvailable {
|
|
thread_id: ThreadId,
|
|
},
|
|
|
|
/// Clear the terminal UI (screen + scrollback), start a fresh session, and keep the
|
|
/// previous chat resumable.
|
|
ClearUi {
|
|
name: Option<String>,
|
|
},
|
|
|
|
/// Clear history queued by the previous thread before the new thread's replay events.
|
|
ResetTranscriptForThreadSwitch,
|
|
|
|
/// Re-render the transcript using the selected scrollback rendering mode.
|
|
RawOutputModeChanged {
|
|
enabled: bool,
|
|
},
|
|
|
|
/// Clear the current context, start a fresh session, and submit an initial user message.
|
|
///
|
|
/// This is the Plan Mode handoff path: the previous thread remains resumable, but the model
|
|
/// sees only the explicit prompt carried in `text` once the new session is configured.
|
|
ClearUiAndSubmitUserMessage {
|
|
text: String,
|
|
},
|
|
|
|
/// Open the resume picker inside the running TUI session.
|
|
OpenResumePicker,
|
|
|
|
/// Open the Claude Code migration picker inside the running TUI session.
|
|
OpenExternalAgentConfigMigration,
|
|
|
|
/// Resume a thread by UUID or thread name inside the running TUI session.
|
|
ResumeSessionByIdOrName(String),
|
|
|
|
/// Archive the current active main thread and exit after it succeeds.
|
|
ArchiveCurrentThread,
|
|
|
|
/// Permanently delete the current active main thread and exit after it succeeds.
|
|
DeleteCurrentThread,
|
|
|
|
/// Fork the current session into a new thread, optionally assigning it a name.
|
|
ForkCurrentSession {
|
|
name: Option<String>,
|
|
},
|
|
|
|
/// Branch before a selected prompt and reopen it in the new thread's composer.
|
|
RevertSessionForPromptEdit {
|
|
thread_id: ThreadId,
|
|
nth_user_message: usize,
|
|
prompt: UserMessage,
|
|
},
|
|
FinishPromptRevert {
|
|
thread_id: ThreadId,
|
|
nth_user_message: usize,
|
|
},
|
|
|
|
/// Request to exit the application.
|
|
///
|
|
/// Use `ShutdownFirst` for user-initiated quits so core cleanup runs and the
|
|
/// UI exits only after `ShutdownComplete`. `Immediate` is a last-resort
|
|
/// escape hatch that skips shutdown and may drop in-flight work (e.g.,
|
|
/// background tasks, rollout flush, or child process cleanup).
|
|
Exit(ExitMode),
|
|
|
|
/// Apply a choice from the running-task exit menu to its originating thread.
|
|
RunningTaskExit {
|
|
action: RunningTaskExitAction,
|
|
thread_id: ThreadId,
|
|
},
|
|
|
|
/// Request app-server account logout, then exit after it succeeds.
|
|
Logout,
|
|
|
|
/// Request to exit the application due to a fatal error.
|
|
#[allow(dead_code)]
|
|
FatalExitRequest(String),
|
|
|
|
/// Forward a command to the Agent. Using an `AppEvent` for this avoids
|
|
/// bubbling channels through layers of widgets.
|
|
CodexOp(AppCommand),
|
|
|
|
/// A blocking image-preparation worker has finished; payload stays with its widget.
|
|
ImagesPrepared(Uuid),
|
|
|
|
/// Approve one retry of a recent auto-review denial selected in the TUI.
|
|
ApproveRecentAutoReviewDenial {
|
|
thread_id: ThreadId,
|
|
id: String,
|
|
},
|
|
|
|
/// Kick off an asynchronous file search for the given query (text after
|
|
/// the `@`). Previous searches may be cancelled by the app layer so there
|
|
/// is at most one in-flight search.
|
|
StartFileSearch(String),
|
|
|
|
/// Result of a completed asynchronous file search. The `query` echoes the
|
|
/// original search term so the UI can decide whether the results are
|
|
/// still relevant.
|
|
FileSearchResult {
|
|
query: String,
|
|
matches: Vec<FileMatch>,
|
|
},
|
|
|
|
/// Same-host task results for the active unified mention query.
|
|
TaskSearchResult {
|
|
thread_id: ThreadId,
|
|
query: String,
|
|
matches: Vec<crate::task_mentions::TaskMention>,
|
|
},
|
|
|
|
/// Refresh account rate limits in the background.
|
|
RefreshRateLimits {
|
|
origin: RateLimitRefreshOrigin,
|
|
},
|
|
|
|
/// Reconcile inherited account usage with an attached task before its queued input runs.
|
|
ApplyBackendBannerFallback {
|
|
thread_id: ThreadId,
|
|
},
|
|
|
|
/// Open the current thread goal summary/action menu.
|
|
OpenThreadGoalMenu {
|
|
thread_id: ThreadId,
|
|
},
|
|
|
|
/// Open an editor for the current thread goal objective.
|
|
OpenThreadGoalEditor {
|
|
thread_id: Option<ThreadId>,
|
|
},
|
|
|
|
/// Materialize and set or replace the current thread goal objective.
|
|
SetThreadGoalDraft {
|
|
thread_id: ThreadId,
|
|
draft: GoalDraft,
|
|
mode: ThreadGoalSetMode,
|
|
},
|
|
|
|
/// Pause or resume the current thread goal.
|
|
SetThreadGoalStatus {
|
|
thread_id: ThreadId,
|
|
status: ThreadGoalStatus,
|
|
},
|
|
|
|
/// Clear the current thread goal.
|
|
ClearThreadGoal {
|
|
thread_id: ThreadId,
|
|
},
|
|
|
|
/// Result of refreshing rate limits.
|
|
RateLimitsLoaded {
|
|
request_id: u64,
|
|
origin: RateLimitRefreshOrigin,
|
|
hard_stop_generation: u64,
|
|
result: Result<GetAccountRateLimitsResponse, String>,
|
|
},
|
|
|
|
/// Open the authenticated account analytics dashboard.
|
|
OpenAnalytics {
|
|
view: Option<crate::analytics::TokenActivityView>,
|
|
},
|
|
|
|
/// Open the reset-credit flow selected from the `/usage` menu.
|
|
OpenRateLimitResetCredits,
|
|
|
|
/// Confirm the reset credit selected from the reset-credit picker.
|
|
OpenRateLimitResetConfirmation {
|
|
picker_request_id: u64,
|
|
confirmation_gate: Arc<AtomicBool>,
|
|
credit_id: Option<String>,
|
|
reset_title: String,
|
|
reset_detail: Option<String>,
|
|
reset_description: String,
|
|
},
|
|
|
|
/// Consume one reset credit using a stable idempotency key.
|
|
ConsumeRateLimitResetCredit {
|
|
idempotency_key: String,
|
|
credit_id: Option<String>,
|
|
},
|
|
|
|
/// Result of consuming one reset credit.
|
|
RateLimitResetCreditConsumed {
|
|
request_id: u64,
|
|
idempotency_key: String,
|
|
credit_id: Option<String>,
|
|
result: Result<ConsumeAccountRateLimitResetCreditResponse, String>,
|
|
},
|
|
|
|
/// Fetch backend-estimated usage for the currently visible enterprise thread.
|
|
RefreshThreadUsage {
|
|
thread_id: ThreadId,
|
|
request_id: u64,
|
|
},
|
|
|
|
/// Result of fetching backend-estimated usage for a specific thread.
|
|
ThreadUsageLoaded {
|
|
thread_id: ThreadId,
|
|
request_id: u64,
|
|
result: Result<ThreadUsageOutcome, String>,
|
|
},
|
|
|
|
/// Result of fetching usage for the selected dashboard task.
|
|
AgentsOverviewUsageLoaded {
|
|
thread_id: ThreadId,
|
|
request_id: Uuid,
|
|
result: Result<ThreadUsageOutcome, String>,
|
|
},
|
|
|
|
/// Fetch workspace messages for the status-line headline item.
|
|
RefreshStatusLineWorkspaceHeadline {
|
|
request_id: u64,
|
|
},
|
|
|
|
/// Commit settled asynchronous usage output after active-output barriers clear.
|
|
CommitPendingUsageOutput,
|
|
|
|
/// Commit settled asynchronous usage output after stream shutdown.
|
|
CommitPendingUsageOutputAfterStreamShutdown,
|
|
|
|
/// Send a user-confirmed request to notify the workspace owner.
|
|
SendAddCreditsNudgeEmail {
|
|
credit_type: AddCreditsNudgeCreditType,
|
|
},
|
|
|
|
/// Result of notifying the workspace owner.
|
|
AddCreditsNudgeEmailFinished {
|
|
request_id: Uuid,
|
|
result: Result<AddCreditsNudgeEmailStatus, String>,
|
|
},
|
|
|
|
/// Result of prefetching connectors.
|
|
ConnectorsLoaded {
|
|
thread_id: Option<ThreadId>,
|
|
cwd: PathBuf,
|
|
generation: ConnectorScopeGeneration,
|
|
result: Result<ConnectorsSnapshot, String>,
|
|
is_final: bool,
|
|
},
|
|
|
|
/// Thread-scoped installed applications that may actually be mentioned.
|
|
InstalledConnectorMentionsLoaded {
|
|
thread_id: Option<ThreadId>,
|
|
cwd: PathBuf,
|
|
generation: ConnectorScopeGeneration,
|
|
result: Result<ConnectorsSnapshot, String>,
|
|
},
|
|
|
|
/// Result of computing a `/diff` command.
|
|
DiffResult(PathBuf, String),
|
|
|
|
/// Open the app link view in the bottom pane.
|
|
OpenAppLink {
|
|
app_id: String,
|
|
title: String,
|
|
description: Option<String>,
|
|
instructions: String,
|
|
url: String,
|
|
is_installed: bool,
|
|
is_enabled: bool,
|
|
},
|
|
|
|
/// Open the provided URL in the user's browser.
|
|
OpenUrlInBrowser {
|
|
url: String,
|
|
},
|
|
|
|
/// Open the current thread in Codex Desktop.
|
|
OpenDesktopThread {
|
|
thread_id: ThreadId,
|
|
},
|
|
|
|
/// Persist a pet selection and reload the ambient pet.
|
|
PetSelected {
|
|
pet_id: String,
|
|
},
|
|
|
|
/// Persist terminal pets as disabled and remove the ambient pet.
|
|
PetDisabled,
|
|
|
|
/// Start loading the side preview for the pet picker.
|
|
PetPreviewRequested {
|
|
pet_id: String,
|
|
},
|
|
|
|
/// Result of loading the side preview for the pet picker.
|
|
PetPreviewLoaded {
|
|
request_id: u64,
|
|
result: Result<crate::pets::AmbientPet, String>,
|
|
},
|
|
|
|
/// Result of loading the selected ambient pet before config persistence.
|
|
PetSelectionLoaded {
|
|
request_id: u64,
|
|
pet_id: String,
|
|
result: Result<Option<crate::pets::AmbientPet>, String>,
|
|
},
|
|
|
|
/// Result of restoring the configured ambient pet during startup.
|
|
ConfiguredPetLoaded {
|
|
pet_id: String,
|
|
result: Result<Option<crate::pets::AmbientPet>, String>,
|
|
},
|
|
|
|
/// Refresh app connector state and mention bindings.
|
|
RefreshConnectors {
|
|
force_refetch: bool,
|
|
},
|
|
|
|
/// Fetch apps only while the originating account, workspace, and thread remain current.
|
|
FetchConnectorsList {
|
|
force_refetch: bool,
|
|
generation: ConnectorScopeGeneration,
|
|
},
|
|
|
|
/// Refresh callable installed applications without loading the app directory.
|
|
FetchInstalledConnectorMentions {
|
|
force_refresh: bool,
|
|
generation: ConnectorScopeGeneration,
|
|
},
|
|
|
|
/// Fetch plugin marketplace state for the provided working directory.
|
|
FetchPluginsList {
|
|
cwd: PathBuf,
|
|
},
|
|
|
|
/// Fetch lifecycle hook inventory for the provided working directory.
|
|
FetchHooksList {
|
|
cwd: PathBuf,
|
|
},
|
|
|
|
/// Result of fetching plugin marketplace state.
|
|
PluginsLoaded {
|
|
cwd: PathBuf,
|
|
result: Result<PluginListResponse, String>,
|
|
},
|
|
|
|
/// Open the plugin list from an already cached response.
|
|
OpenPluginsList {
|
|
cwd: PathBuf,
|
|
response: PluginListResponse,
|
|
},
|
|
|
|
/// Result of explicitly fetching remote-backed plugin sections.
|
|
PluginRemoteSectionsLoaded {
|
|
cwd: PathBuf,
|
|
marketplaces: Vec<PluginMarketplaceEntry>,
|
|
section_errors: Vec<PluginRemoteSectionError>,
|
|
},
|
|
|
|
/// Result of fetching lifecycle hook inventory.
|
|
HooksLoaded {
|
|
cwd: PathBuf,
|
|
result: Result<codex_app_server_protocol::HooksListResponse, String>,
|
|
},
|
|
|
|
/// Open the prompt for adding a marketplace source.
|
|
OpenMarketplaceAddPrompt,
|
|
|
|
/// Replace the plugins popup with a marketplace-add loading state.
|
|
OpenMarketplaceAddLoading {
|
|
source: String,
|
|
},
|
|
|
|
/// Add a marketplace from the provided source.
|
|
FetchMarketplaceAdd {
|
|
cwd: PathBuf,
|
|
source: String,
|
|
},
|
|
|
|
/// Result of adding a marketplace.
|
|
MarketplaceAddLoaded {
|
|
cwd: PathBuf,
|
|
source: String,
|
|
result: Result<MarketplaceAddResponse, String>,
|
|
},
|
|
|
|
/// Open the confirmation prompt for removing a marketplace.
|
|
OpenMarketplaceRemoveConfirm {
|
|
marketplace_name: String,
|
|
marketplace_display_name: String,
|
|
},
|
|
|
|
/// Replace the plugins popup with a marketplace-remove loading state.
|
|
OpenMarketplaceRemoveLoading {
|
|
marketplace_display_name: String,
|
|
},
|
|
|
|
/// Remove a marketplace by name.
|
|
FetchMarketplaceRemove {
|
|
cwd: PathBuf,
|
|
marketplace_name: String,
|
|
marketplace_display_name: String,
|
|
},
|
|
|
|
/// Result of removing a marketplace.
|
|
MarketplaceRemoveLoaded {
|
|
cwd: PathBuf,
|
|
marketplace_name: String,
|
|
marketplace_display_name: String,
|
|
result: Result<MarketplaceRemoveResponse, String>,
|
|
},
|
|
|
|
/// Replace the plugins popup with a marketplace-upgrade loading state.
|
|
OpenMarketplaceUpgradeLoading {
|
|
marketplace_name: Option<String>,
|
|
},
|
|
|
|
/// Upgrade configured Git marketplaces.
|
|
FetchMarketplaceUpgrade {
|
|
cwd: PathBuf,
|
|
marketplace_name: Option<String>,
|
|
},
|
|
|
|
/// Result of upgrading configured Git marketplaces.
|
|
MarketplaceUpgradeLoaded {
|
|
cwd: PathBuf,
|
|
result: Result<MarketplaceUpgradeResponse, String>,
|
|
},
|
|
|
|
/// Replace the plugins popup with a plugin-detail loading state.
|
|
OpenPluginDetailLoading {
|
|
plugin_display_name: String,
|
|
},
|
|
|
|
/// Fetch detail for a specific plugin from a marketplace.
|
|
FetchPluginDetail {
|
|
cwd: PathBuf,
|
|
params: PluginReadParams,
|
|
},
|
|
|
|
/// Result of fetching plugin detail.
|
|
PluginDetailLoaded {
|
|
cwd: PathBuf,
|
|
result: Result<PluginReadResponse, String>,
|
|
},
|
|
|
|
/// Replace the plugins popup with an install loading state.
|
|
OpenPluginInstallLoading {
|
|
plugin_display_name: String,
|
|
},
|
|
|
|
/// Replace the plugins popup with an uninstall loading state.
|
|
OpenPluginUninstallLoading {
|
|
plugin_display_name: String,
|
|
},
|
|
|
|
/// Install a specific plugin from a marketplace.
|
|
FetchPluginInstall {
|
|
cwd: PathBuf,
|
|
location: PluginLocation,
|
|
plugin_name: String,
|
|
plugin_display_name: String,
|
|
},
|
|
|
|
/// Result of installing a plugin.
|
|
PluginInstallLoaded {
|
|
cwd: PathBuf,
|
|
location: PluginLocation,
|
|
plugin_name: String,
|
|
plugin_display_name: String,
|
|
result: Result<PluginInstallResponse, String>,
|
|
},
|
|
|
|
/// Uninstall a specific plugin by canonical plugin id.
|
|
FetchPluginUninstall {
|
|
cwd: PathBuf,
|
|
plugin_id: String,
|
|
plugin_display_name: String,
|
|
},
|
|
|
|
/// Result of uninstalling a plugin.
|
|
PluginUninstallLoaded {
|
|
cwd: PathBuf,
|
|
plugin_id: String,
|
|
plugin_display_name: String,
|
|
result: Result<PluginUninstallResponse, String>,
|
|
},
|
|
|
|
/// Enable or disable an installed plugin.
|
|
SetPluginEnabled {
|
|
cwd: PathBuf,
|
|
plugin_id: String,
|
|
enabled: bool,
|
|
},
|
|
|
|
/// Result of enabling or disabling a plugin.
|
|
PluginEnabledSet {
|
|
cwd: PathBuf,
|
|
plugin_id: String,
|
|
enabled: bool,
|
|
result: Result<(), String>,
|
|
},
|
|
|
|
/// Refresh plugin mention bindings from the current config.
|
|
RefreshPluginMentions,
|
|
|
|
/// Result of refreshing plugin mention bindings.
|
|
PluginMentionsLoaded {
|
|
cwd: PathBuf,
|
|
plugins: Option<Vec<PluginCapabilitySummary>>,
|
|
},
|
|
|
|
/// Advance the post-install plugin app-auth flow.
|
|
PluginInstallAuthAdvance {
|
|
refresh_connectors: bool,
|
|
},
|
|
|
|
/// Abandon the post-install plugin app-auth flow.
|
|
PluginInstallAuthAbandon,
|
|
|
|
/// Fetch MCP inventory via app-server RPCs and render it into history.
|
|
FetchMcpInventory {
|
|
detail: McpServerStatusDetail,
|
|
thread_id: Option<ThreadId>,
|
|
},
|
|
|
|
/// Result of fetching MCP inventory via app-server RPCs.
|
|
McpInventoryLoaded {
|
|
result: Result<Vec<McpServerStatus>, String>,
|
|
detail: McpServerStatusDetail,
|
|
thread_id: Option<ThreadId>,
|
|
},
|
|
|
|
/// Result of the startup skills refresh that runs after the first frame is scheduled.
|
|
///
|
|
/// This event is startup-only. Interactive skills refreshes are handled synchronously through the app
|
|
/// command path because those callers expect the visible skill state to be current when their command
|
|
/// completes.
|
|
SkillsListLoaded {
|
|
cwd: PathBuf,
|
|
result: Result<SkillsListResponse, String>,
|
|
},
|
|
|
|
/// Begin buffering initial resume replay rows before they are written to scrollback.
|
|
BeginInitialHistoryReplayBuffer,
|
|
|
|
/// Begin buffering thread-switch replay cells so the final scrollback write can reuse the
|
|
/// resize-reflow tail renderer.
|
|
BeginThreadSwitchHistoryReplayBuffer,
|
|
|
|
InsertHistoryCell(Box<dyn HistoryCell>),
|
|
|
|
/// Move visible completed voice captions into history in one app event.
|
|
CommitRealtimeTranscriptHistory,
|
|
|
|
/// Finish buffering initial resume replay after all replay events have been queued.
|
|
EndInitialHistoryReplayBuffer,
|
|
|
|
/// Replace the contiguous run of streaming `AgentMessageCell`s at the end of
|
|
/// the transcript with a single `AgentMarkdownCell` that stores the raw
|
|
/// markdown source and re-renders from it on resize.
|
|
///
|
|
/// Emitted by `ChatWidget::flush_answer_stream_with_separator` after stream
|
|
/// finalization. The `App` handler walks backward through `transcript_cells`
|
|
/// to find the `AgentMessageCell` run and splices in the consolidated cell.
|
|
/// The `cwd` keeps local file-link display stable across the final re-render.
|
|
/// `scrollback_reflow` lets table-tail finalization force the already-emitted
|
|
/// terminal scrollback to be rebuilt from the consolidated source-backed cell.
|
|
/// `deferred_history_cell` lets callers add the final stream tail to the
|
|
/// transcript without first writing its provisional render to scrollback.
|
|
ConsolidateAgentMessage {
|
|
source: String,
|
|
cwd: PathBuf,
|
|
inline_visualization_context: Option<InlineVisualizationContext>,
|
|
scrollback_reflow: ConsolidationScrollbackReflow,
|
|
deferred_history_cell: Option<Box<dyn HistoryCell>>,
|
|
},
|
|
|
|
/// Replace the contiguous run of streaming `ProposedPlanStreamCell`s at the
|
|
/// end of the transcript with a single source-backed `ProposedPlanCell`.
|
|
///
|
|
/// Emitted by `ChatWidget::on_plan_item_completed` after plan stream
|
|
/// finalization.
|
|
ConsolidateProposedPlan(String),
|
|
|
|
StartCommitAnimation,
|
|
StopCommitAnimation,
|
|
|
|
/// Update the current reasoning effort in the running app and widget.
|
|
UpdateReasoningEffort(Option<ReasoningEffort>),
|
|
|
|
/// Change Reserve effort only on the task that opened the picker, without saving defaults.
|
|
UpdateLunaReserveReasoning {
|
|
thread_id: ThreadId,
|
|
effort: Option<ReasoningEffort>,
|
|
},
|
|
|
|
/// Update the current model slug in the running app and widget.
|
|
UpdateModel(String),
|
|
|
|
/// Apply a final Astra picker action and offer the flourish only if it changed the model on
|
|
/// its original task. Automatic model updates do not use this event.
|
|
AstraSelectedFromModelPicker {
|
|
thread_id: ThreadId,
|
|
model: String,
|
|
action: AstraModelPickerAction,
|
|
},
|
|
|
|
/// Result of creating a TUI-owned WebRTC offer for an active thread.
|
|
RealtimeWebrtcOfferCreated {
|
|
thread_id: ThreadId,
|
|
attempt_id: u64,
|
|
result: Result<StartedRealtimeWebrtcSession, String>,
|
|
},
|
|
|
|
/// Result of establishing the WebRTC connection for an active voice attempt.
|
|
RealtimeWebrtcConnected {
|
|
thread_id: ThreadId,
|
|
attempt_id: u64,
|
|
result: Result<(), codex_realtime_webrtc::ConnectionError>,
|
|
},
|
|
|
|
/// Stop voice on its original thread after its chat widget is replaced.
|
|
StopRealtimeConversation {
|
|
thread_id: ThreadId,
|
|
},
|
|
|
|
/// Finish a settings selection after its preceding update events have been applied.
|
|
SettingsSelectionClosed,
|
|
/// Run after any nested settings events emitted while handling the close event.
|
|
SettingsSelectionSettled,
|
|
|
|
/// Persist the selected model and reasoning effort to the appropriate config.
|
|
PersistModelSelection {
|
|
model: String,
|
|
effort: Option<ReasoningEffort>,
|
|
},
|
|
|
|
/// Apply a model and effort only to the active session, preserving saved defaults.
|
|
SelectSessionModel {
|
|
model: String,
|
|
effort: Option<ReasoningEffort>,
|
|
},
|
|
|
|
/// Show the cyber auto-review notice after the model selection confirmation.
|
|
CyberModelAutoReviewNotice,
|
|
|
|
/// Read the owning server preference before showing the voice picker.
|
|
OpenRealtimeSettings,
|
|
|
|
/// Save the voice for subsequent conversations through the app server.
|
|
PersistRealtimeVoiceSelection {
|
|
voice: codex_protocol::protocol::RealtimeVoice,
|
|
},
|
|
|
|
/// Persist the selected service tier to the appropriate config.
|
|
PersistServiceTierSelection {
|
|
service_tier: Option<String>,
|
|
},
|
|
|
|
/// Fetch the current catalog even when cached models produce no picker.
|
|
FetchModels {
|
|
request_id: uuid::Uuid,
|
|
},
|
|
ModelsLoaded {
|
|
request_id: uuid::Uuid,
|
|
result: Result<Vec<ModelPreset>, String>,
|
|
},
|
|
|
|
FetchPermissionProfiles {
|
|
request_id: uuid::Uuid,
|
|
thread_cwd: Option<PathBuf>,
|
|
},
|
|
PermissionProfilesLoaded {
|
|
request_id: uuid::Uuid,
|
|
result: Result<crate::permission_discovery::PermissionDiscovery, String>,
|
|
},
|
|
|
|
/// Open the reasoning selection popup after picking a model.
|
|
OpenReasoningPopup {
|
|
model: ModelPreset,
|
|
},
|
|
|
|
/// Open the explicit Max/Ultra reasoning selection popup for a model.
|
|
OpenAdvancedReasoningPopup {
|
|
model: ModelPreset,
|
|
},
|
|
|
|
/// Apply an advanced reasoning effort to the active conversation without changing defaults.
|
|
ApplyAdvancedReasoning {
|
|
model: String,
|
|
effort: ReasoningEffort,
|
|
},
|
|
|
|
/// Open the Plan-mode reasoning scope prompt for the selected model/effort.
|
|
OpenPlanReasoningScopePrompt {
|
|
model: String,
|
|
effort: Option<ReasoningEffort>,
|
|
},
|
|
|
|
/// Open the full model picker (non-auto models).
|
|
OpenAllModelsPopup,
|
|
|
|
/// Open the confirmation prompt before enabling full access mode.
|
|
OpenFullAccessConfirmation {
|
|
preset: ApprovalPreset,
|
|
return_to_permissions: bool,
|
|
profile_selection: Option<PermissionProfileSelection>,
|
|
},
|
|
|
|
/// Apply a permission shortcut only while its originating thread is displayed.
|
|
ApplyPermissionShortcut {
|
|
thread_id: ThreadId,
|
|
selection: PermissionProfileSelection,
|
|
},
|
|
|
|
/// Refresh server-owned Windows state after selecting a thread or project.
|
|
#[cfg_attr(not(target_os = "windows"), allow(dead_code))]
|
|
RefreshWindowsSandbox {
|
|
thread_id: ThreadId,
|
|
},
|
|
|
|
/// Prompt to enable the Windows sandbox feature before using Agent mode.
|
|
#[cfg_attr(not(target_os = "windows"), allow(dead_code))]
|
|
OpenWindowsSandboxEnablePrompt {
|
|
preset: ApprovalPreset,
|
|
profile_selection: Option<PermissionProfileSelection>,
|
|
},
|
|
|
|
/// Open the Windows sandbox fallback prompt after declining or failing elevation.
|
|
#[cfg_attr(not(target_os = "windows"), allow(dead_code))]
|
|
OpenWindowsSandboxFallbackPrompt {
|
|
preset: ApprovalPreset,
|
|
profile_selection: Option<PermissionProfileSelection>,
|
|
},
|
|
|
|
/// Begin the elevated Windows sandbox setup flow.
|
|
#[cfg_attr(not(target_os = "windows"), allow(dead_code))]
|
|
BeginWindowsSandboxElevatedSetup {
|
|
preset: ApprovalPreset,
|
|
profile_selection: Option<PermissionProfileSelection>,
|
|
},
|
|
|
|
/// Begin the non-elevated Windows sandbox setup flow.
|
|
#[cfg_attr(not(target_os = "windows"), allow(dead_code))]
|
|
BeginWindowsSandboxLegacySetup {
|
|
preset: ApprovalPreset,
|
|
profile_selection: Option<PermissionProfileSelection>,
|
|
},
|
|
|
|
/// Enable the Windows sandbox feature and switch to Agent mode.
|
|
#[cfg_attr(not(target_os = "windows"), allow(dead_code))]
|
|
EnableWindowsSandboxForAgentMode {
|
|
preset: ApprovalPreset,
|
|
mode: WindowsSandboxEnableMode,
|
|
profile_selection: Option<PermissionProfileSelection>,
|
|
},
|
|
|
|
/// Update the Windows sandbox feature mode without changing approval presets.
|
|
#[cfg_attr(not(target_os = "windows"), allow(dead_code))]
|
|
|
|
/// Update the current approval policy in the running app and widget.
|
|
UpdateAskForApprovalPolicy(AskForApproval),
|
|
|
|
/// Update the current built-in active permission profile in the running app and widget.
|
|
UpdateActivePermissionProfile(ActivePermissionProfile),
|
|
|
|
/// Select a named permission profile, optionally applying built-in mode settings too.
|
|
SelectPermissionProfile(PermissionProfileSelection),
|
|
|
|
/// Update the current approvals reviewer in the running app and widget.
|
|
UpdateApprovalsReviewer(ApprovalsReviewer),
|
|
|
|
/// Discover experimental features for the requesting popup only.
|
|
FetchExperimentalFeatures {
|
|
thread_id: ThreadId,
|
|
response_tx: tokio::sync::oneshot::Sender<
|
|
Result<Vec<codex_app_server_protocol::ExperimentalFeature>, String>,
|
|
>,
|
|
},
|
|
|
|
/// Update feature flags and persist them to the top-level config.
|
|
UpdateFeatureFlags {
|
|
updates: Vec<(Feature, bool)>,
|
|
},
|
|
|
|
/// Save generic menu controls without changing running-task settings.
|
|
SaveExperimentalFeatures {
|
|
thread_id: ThreadId,
|
|
updates: Vec<(String, bool)>,
|
|
response_tx: tokio::sync::oneshot::Sender<Result<FeatureWriteResult, String>>,
|
|
},
|
|
|
|
/// Save an enable prompt on the app server without changing the current thread.
|
|
EnableFeatureForNewThreads(Feature),
|
|
|
|
/// Update memory settings and persist them to config.toml.
|
|
UpdateMemorySettings {
|
|
use_memories: bool,
|
|
generate_memories: bool,
|
|
},
|
|
|
|
/// Clear all persisted local memory artifacts via the app-server.
|
|
ResetMemories,
|
|
|
|
/// Update whether the rate limit switch prompt has been acknowledged for the session.
|
|
UpdateRateLimitSwitchPromptHidden(bool),
|
|
|
|
/// Update the Plan-mode-specific reasoning effort in memory.
|
|
UpdatePlanModeReasoningEffort(Option<ReasoningEffort>),
|
|
|
|
/// Persist the acknowledgement flag for the rate limit switch prompt.
|
|
PersistRateLimitSwitchPromptHidden,
|
|
|
|
/// Persist the Plan-mode-specific reasoning effort.
|
|
PersistPlanModeReasoningEffort(Option<ReasoningEffort>),
|
|
|
|
/// Persist the acknowledgement flag for the model migration prompt.
|
|
PersistModelMigrationPromptAcknowledged {
|
|
from_model: String,
|
|
to_model: String,
|
|
},
|
|
|
|
/// Re-open the approval presets popup.
|
|
OpenApprovalsPopup,
|
|
|
|
/// Open the skills list popup.
|
|
OpenSkillsList,
|
|
|
|
/// Open the skills enable/disable picker.
|
|
OpenManageSkillsPopup,
|
|
|
|
/// Enable or disable a skill by path.
|
|
SetSkillEnabled {
|
|
path: AbsolutePathBuf,
|
|
enabled: bool,
|
|
},
|
|
|
|
/// Enable or disable an app by connector ID.
|
|
SetAppEnabled {
|
|
id: String,
|
|
enabled: bool,
|
|
},
|
|
|
|
/// Enable or disable a hook by stable hook key.
|
|
SetHookEnabled {
|
|
key: String,
|
|
enabled: bool,
|
|
},
|
|
|
|
/// Trust the current definition for a hook by stable hook key.
|
|
TrustHook {
|
|
key: String,
|
|
current_hash: String,
|
|
},
|
|
|
|
/// Trust the current definitions for one or more hooks by stable hook key.
|
|
TrustHooks {
|
|
updates: Vec<crate::hooks_rpc::HookTrustUpdate>,
|
|
},
|
|
|
|
/// Result of persisting hook enabled state.
|
|
HookEnabledSet {
|
|
key: String,
|
|
enabled: bool,
|
|
result: Result<(), String>,
|
|
},
|
|
|
|
/// Result of persisting hook trust state.
|
|
HookTrusted {
|
|
result: Result<(), String>,
|
|
},
|
|
|
|
/// Notify that the manage skills popup was closed.
|
|
ManageSkillsClosed,
|
|
|
|
/// Re-open the permissions presets popup.
|
|
OpenPermissionsPopup,
|
|
|
|
/// Open the branch picker option from the review popup.
|
|
OpenReviewBranchPicker(PathBuf),
|
|
|
|
/// Open the commit picker option from the review popup.
|
|
OpenReviewCommitPicker(PathBuf),
|
|
|
|
/// Open the custom prompt option from the review popup.
|
|
OpenReviewCustomPrompt,
|
|
|
|
/// Submit a user message with an explicit collaboration mask.
|
|
SubmitUserMessageWithMode {
|
|
text: String,
|
|
collaboration_mode: CollaborationModeMask,
|
|
},
|
|
|
|
/// Open the approval popup.
|
|
FullScreenApprovalRequest(ApprovalRequest),
|
|
|
|
/// Inspect the complete verification request without deciding it.
|
|
FullScreenUserVerificationRequest(
|
|
crate::bottom_pane::user_verification::UserVerificationRequest,
|
|
),
|
|
|
|
/// Open the feedback note entry overlay after the user selects a category.
|
|
OpenFeedbackNote {
|
|
category: FeedbackCategory,
|
|
include_logs: bool,
|
|
},
|
|
|
|
/// Open the upload consent popup for feedback after selecting a category.
|
|
OpenFeedbackConsent {
|
|
category: FeedbackCategory,
|
|
},
|
|
|
|
/// Submit feedback for the current thread via the app-server feedback RPC.
|
|
SubmitFeedback {
|
|
category: FeedbackCategory,
|
|
reason: Option<String>,
|
|
turn_id: Option<String>,
|
|
include_logs: bool,
|
|
},
|
|
|
|
/// Result of a feedback upload request initiated by the TUI.
|
|
FeedbackSubmitted {
|
|
origin_thread_id: Option<ThreadId>,
|
|
category: FeedbackCategory,
|
|
include_logs: bool,
|
|
result: Result<String, String>,
|
|
},
|
|
|
|
/// Launch the external editor after a normal draw has completed.
|
|
LaunchExternalEditor,
|
|
|
|
/// Async update of the current git branch for status line rendering.
|
|
StatusLineBranchUpdated {
|
|
cwd: PathBuf,
|
|
branch: Option<String>,
|
|
},
|
|
/// Async update of Git summary fields for status line rendering.
|
|
StatusLineGitSummaryUpdated {
|
|
cwd: PathBuf,
|
|
summary: crate::chatwidget::StatusLineGitSummary,
|
|
},
|
|
/// Async update of the workspace notification headline for status line rendering.
|
|
StatusLineWorkspaceHeadlineUpdated {
|
|
request_id: u64,
|
|
result: Result<crate::workspace_messages::WorkspaceHeadlineFetchResult, String>,
|
|
},
|
|
/// Apply a user-confirmed status-line item ordering/selection.
|
|
StatusLineSetup {
|
|
items: Vec<StatusLineItem>,
|
|
use_theme_colors: bool,
|
|
},
|
|
/// Dismiss the status-line setup UI without changing config.
|
|
StatusLineSetupCancelled,
|
|
|
|
/// Apply a user-confirmed terminal-title item ordering/selection.
|
|
TerminalTitleSetup {
|
|
items: Vec<TerminalTitleItem>,
|
|
},
|
|
/// Apply a temporary terminal-title preview while the setup UI is open.
|
|
TerminalTitleSetupPreview {
|
|
items: Vec<TerminalTitleItem>,
|
|
},
|
|
/// Dismiss the terminal-title setup UI without changing config.
|
|
TerminalTitleSetupCancelled,
|
|
|
|
/// Apply a user-confirmed syntax theme selection.
|
|
SyntaxThemeSelected {
|
|
name: String,
|
|
},
|
|
|
|
/// Runtime syntax theme preview changed; refresh theme-derived UI colors.
|
|
SyntaxThemePreviewed,
|
|
|
|
/// Open set/remove actions for the selected keymap action.
|
|
OpenKeymapActionMenu {
|
|
context: String,
|
|
action: String,
|
|
},
|
|
|
|
/// Open binding selection before replacing one binding for an action.
|
|
OpenKeymapReplaceBindingMenu {
|
|
context: String,
|
|
action: String,
|
|
},
|
|
|
|
/// Open key capture for the selected keymap action.
|
|
OpenKeymapCapture {
|
|
context: String,
|
|
action: String,
|
|
intent: KeymapEditIntent,
|
|
capture_mode: KeymapCaptureMode,
|
|
},
|
|
|
|
/// Open the keymap keypress inspector.
|
|
OpenKeymapDebug,
|
|
|
|
/// Apply a captured key to the selected keymap action.
|
|
KeymapCaptured {
|
|
context: String,
|
|
action: String,
|
|
key: String,
|
|
intent: KeymapEditIntent,
|
|
},
|
|
|
|
/// Remove the custom root binding for the selected keymap action.
|
|
KeymapCleared {
|
|
context: String,
|
|
action: String,
|
|
},
|
|
|
|
/// Generate a recap for the displayed idle thread at the user's request.
|
|
GenerateRecap {
|
|
thread_id: ThreadId,
|
|
},
|
|
|
|
/// Recheck whether an unfocused thread is ready for an automatic recap.
|
|
CheckRecap {
|
|
thread_id: ThreadId,
|
|
},
|
|
|
|
/// Deliver the result of starting a recap's temporary thread.
|
|
RecapStarted {
|
|
thread_id: ThreadId,
|
|
request_id: Uuid,
|
|
trigger: RecapTrigger,
|
|
completed_turn_count: usize,
|
|
turn_revision: usize,
|
|
history: String,
|
|
result: Result<String, String>,
|
|
},
|
|
|
|
/// Deliver the generated recap from a temporary structured turn.
|
|
RecapGenerated {
|
|
thread_id: ThreadId,
|
|
request_id: Uuid,
|
|
trigger: RecapTrigger,
|
|
temporary_thread_id: ThreadId,
|
|
completed_turn_count: usize,
|
|
turn_revision: usize,
|
|
result: Result<String, String>,
|
|
},
|
|
}
|
|
|
|
/// Named profile selection to apply after any required UI guardrails complete.
|
|
#[derive(Debug, Clone)]
|
|
pub(crate) struct PermissionProfileSelection {
|
|
pub profile_id: String,
|
|
pub approval_policy: Option<AskForApproval>,
|
|
pub approvals_reviewer: Option<ApprovalsReviewer>,
|
|
pub display_label: String,
|
|
}
|
|
|
|
/// The exit strategy requested by the UI layer.
|
|
///
|
|
/// Most user-initiated exits should use `ShutdownFirst` so core cleanup runs and the UI exits only
|
|
/// after core acknowledges completion. `Immediate` is an escape hatch for cases where shutdown has
|
|
/// already completed (or is being bypassed) and the UI loop should terminate right away.
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub(crate) enum ExitMode {
|
|
/// Shutdown core and exit after completion.
|
|
ShutdownFirst,
|
|
/// Unsubscribe and exit after the current turn was successfully interrupted.
|
|
ShutdownAfterInterrupt,
|
|
/// Exit the UI loop immediately without waiting for shutdown.
|
|
///
|
|
/// This skips `Op::Shutdown`, so any in-flight work may be dropped and
|
|
/// cleanup that normally runs before `ShutdownComplete` can be missed.
|
|
Immediate,
|
|
}
|
|
|
|
/// Choice made when leaving a daemon-backed task that is still running.
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub(crate) enum RunningTaskExitAction {
|
|
CancelTask,
|
|
RunInBackground,
|
|
Exit,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub(crate) enum FeedbackCategory {
|
|
BadResult,
|
|
GoodResult,
|
|
Bug,
|
|
SafetyCheck,
|
|
Other,
|
|
}
|