mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
[codex] Remove unused event messages (#20511)
## Why Several legacy `EventMsg` variants were still emitted or mapped even though clients either ignored them or had moved to item/lifecycle events. `Op::Undo` had also degraded to an unavailable shim, so this removes that dead task path instead of preserving a command that cannot do useful work. `McpStartupComplete`, `WebSearchBegin`, and `ImageGenerationBegin` are intentionally kept because useful consumers still depend on them: MCP startup completion drives readiness behavior, and the begin events let app-server/core consumers surface in-progress web-search and image-generation items before the final payload arrives. ## What Changed - Removed weak legacy event variants and payloads from `codex-protocol`, including legacy agent deltas, background events, and undo lifecycle events. - Kept/restored `EventMsg::McpStartupComplete`, `EventMsg::WebSearchBegin`, and `EventMsg::ImageGenerationBegin` with serializer and emission coverage. - Updated core, rollout, MCP server, app-server thread history, review/delegate filtering, and tests to rely on the useful replacement events that remain. - Removed `Op::Undo`, `UndoTask`, the undo test module, and stale TUI slash-command comments. - Stopped agent job/background progress and compaction retry notices from emitting `BackgroundEvent` payloads. ## Verification - `cargo check -p codex-protocol -p codex-app-server-protocol -p codex-core -p codex-rollout -p codex-rollout-trace -p codex-mcp-server` - `cargo test -p codex-protocol -p codex-app-server-protocol -p codex-rollout -p codex-rollout-trace -p codex-mcp-server` - `cargo test -p codex-core --test all suite::items` - `just fix -p codex-protocol -p codex-app-server-protocol -p codex-core -p codex-rollout -p codex-rollout-trace -p codex-mcp-server` - Earlier coverage on this PR also included `codex-mcp`, `codex-tui`, core library tests, MCP/plugin/delegate/review/agent job tests, and MCP startup TUI tests.
This commit is contained in:
committed by
GitHub
Unverified
parent
bb60b78c46
commit
f50c02d7bc
@@ -217,7 +217,6 @@ impl ThreadHistoryBuilder {
|
||||
EventMsg::Error(payload) => self.handle_error(payload),
|
||||
EventMsg::TokenCount(_) => {}
|
||||
EventMsg::ThreadRolledBack(payload) => self.handle_thread_rollback(payload),
|
||||
EventMsg::UndoCompleted(_) => {}
|
||||
EventMsg::TurnAborted(payload) => self.handle_turn_aborted(payload),
|
||||
EventMsg::TurnStarted(payload) => self.handle_turn_started(payload),
|
||||
EventMsg::TurnComplete(payload) => self.handle_turn_complete(payload),
|
||||
|
||||
@@ -262,11 +262,6 @@ async fn forward_events(
|
||||
Err(_) => break,
|
||||
};
|
||||
match event {
|
||||
// ignore all legacy delta events
|
||||
Event {
|
||||
id: _,
|
||||
msg: EventMsg::AgentMessageDelta(_) | EventMsg::AgentReasoningDelta(_),
|
||||
} => {}
|
||||
Event {
|
||||
id: _,
|
||||
msg: EventMsg::TokenCount(_),
|
||||
|
||||
@@ -165,8 +165,6 @@ async fn run_compact_task_inner_impl(
|
||||
turn_context.truncation_policy,
|
||||
);
|
||||
|
||||
let mut truncated_count = 0usize;
|
||||
|
||||
let max_retries = turn_context.provider.info().stream_max_retries();
|
||||
let mut retries = 0;
|
||||
let mut client_session = sess.services.model_client.new_session();
|
||||
@@ -198,15 +196,6 @@ async fn run_compact_task_inner_impl(
|
||||
|
||||
match attempt_result {
|
||||
Ok(()) => {
|
||||
if truncated_count > 0 {
|
||||
sess.notify_background_event(
|
||||
turn_context.as_ref(),
|
||||
format!(
|
||||
"Trimmed {truncated_count} older thread item(s) before compacting so the prompt fits the model context window."
|
||||
),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
break;
|
||||
}
|
||||
Err(CodexErr::Interrupted) => {
|
||||
@@ -219,7 +208,6 @@ async fn run_compact_task_inner_impl(
|
||||
"Context window exceeded while compacting; removing oldest history item. Error: {e}"
|
||||
);
|
||||
history.remove_first_item();
|
||||
truncated_count += 1;
|
||||
retries = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -136,14 +136,6 @@ pub(crate) async fn maybe_install_mcp_dependencies(
|
||||
}
|
||||
};
|
||||
|
||||
sess.notify_background_event(
|
||||
turn_context,
|
||||
format!(
|
||||
"Authenticating MCP {name}... Follow instructions in your browser if prompted."
|
||||
),
|
||||
)
|
||||
.await;
|
||||
|
||||
let resolved_scopes = resolve_oauth_scopes(
|
||||
/*explicit_scopes*/ None,
|
||||
server_config.scopes.clone(),
|
||||
@@ -164,14 +156,6 @@ pub(crate) async fn maybe_install_mcp_dependencies(
|
||||
|
||||
if let Err(err) = first_attempt {
|
||||
if should_retry_without_scopes(&resolved_scopes, &err) {
|
||||
sess.notify_background_event(
|
||||
turn_context,
|
||||
format!(
|
||||
"Retrying MCP {name} authentication without scopes after provider rejection."
|
||||
),
|
||||
)
|
||||
.await;
|
||||
|
||||
if let Err(err) = perform_oauth_login(
|
||||
&name,
|
||||
&oauth_config.url,
|
||||
|
||||
@@ -27,7 +27,6 @@ use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
|
||||
use crate::review_prompts::resolve_review_request;
|
||||
use crate::tasks::CompactTask;
|
||||
use crate::tasks::UndoTask;
|
||||
use crate::tasks::UserShellCommandMode;
|
||||
use crate::tasks::UserShellCommandTask;
|
||||
use crate::tasks::execute_user_shell_command;
|
||||
@@ -649,12 +648,6 @@ pub async fn list_skills(sess: &Session, sub_id: String, cwds: Vec<PathBuf>, for
|
||||
sess.send_event_raw(event).await;
|
||||
}
|
||||
|
||||
pub async fn undo(sess: &Arc<Session>, sub_id: String) {
|
||||
let turn_context = sess.new_default_turn_with_sub_id(sub_id).await;
|
||||
sess.spawn_task(turn_context, Vec::new(), UndoTask::new())
|
||||
.await;
|
||||
}
|
||||
|
||||
pub async fn compact(sess: &Arc<Session>, sub_id: String) {
|
||||
let turn_context = sess.new_default_turn_with_sub_id(sub_id).await;
|
||||
|
||||
@@ -1118,10 +1111,6 @@ pub(super) async fn submission_loop(
|
||||
list_skills(&sess, sub.id.clone(), cwds, force_reload).await;
|
||||
false
|
||||
}
|
||||
Op::Undo => {
|
||||
undo(&sess, sub.id.clone()).await;
|
||||
false
|
||||
}
|
||||
Op::Compact => {
|
||||
compact(&sess, sub.id.clone()).await;
|
||||
false
|
||||
|
||||
@@ -318,7 +318,6 @@ use codex_protocol::models::ResponseItem;
|
||||
use codex_protocol::openai_models::ReasoningEffort as ReasoningEffortConfig;
|
||||
use codex_protocol::protocol::ApplyPatchApprovalRequestEvent;
|
||||
use codex_protocol::protocol::AskForApproval;
|
||||
use codex_protocol::protocol::BackgroundEventEvent;
|
||||
use codex_protocol::protocol::CodexErrorInfo;
|
||||
use codex_protocol::protocol::CompactedItem;
|
||||
use codex_protocol::protocol::DeprecationNoticeEvent;
|
||||
@@ -2938,17 +2937,6 @@ impl Session {
|
||||
self.ensure_rollout_materialized().await;
|
||||
}
|
||||
|
||||
pub(crate) async fn notify_background_event(
|
||||
&self,
|
||||
turn_context: &TurnContext,
|
||||
message: impl Into<String>,
|
||||
) {
|
||||
let event = EventMsg::BackgroundEvent(BackgroundEventEvent {
|
||||
message: message.into(),
|
||||
});
|
||||
self.send_event(turn_context, event).await;
|
||||
}
|
||||
|
||||
pub(crate) async fn notify_stream_error(
|
||||
&self,
|
||||
turn_context: &TurnContext,
|
||||
|
||||
@@ -336,7 +336,7 @@ pub(crate) async fn run_turn(
|
||||
record_additional_contexts(&sess, &turn_context, additional_contexts).await;
|
||||
if !input.is_empty() {
|
||||
// Track the previous-turn baseline from the regular user-turn path only so
|
||||
// standalone tasks (compact/shell/review/undo) cannot suppress future
|
||||
// standalone tasks (compact/shell/review) cannot suppress future
|
||||
// model/realtime injections.
|
||||
sess.set_previous_turn_settings(Some(PreviousTurnSettings {
|
||||
model: turn_context.model_info.slug.clone(),
|
||||
@@ -1443,11 +1443,8 @@ pub(super) fn realtime_text_for_event(msg: &EventMsg) -> Option<String> {
|
||||
| EventMsg::TurnComplete(_)
|
||||
| EventMsg::TokenCount(_)
|
||||
| EventMsg::UserMessage(_)
|
||||
| EventMsg::AgentMessageDelta(_)
|
||||
| EventMsg::AgentReasoning(_)
|
||||
| EventMsg::AgentReasoningDelta(_)
|
||||
| EventMsg::AgentReasoningRawContent(_)
|
||||
| EventMsg::AgentReasoningRawContentDelta(_)
|
||||
| EventMsg::AgentReasoningSectionBreak(_)
|
||||
| EventMsg::SessionConfigured(_)
|
||||
| EventMsg::ThreadNameUpdated(_)
|
||||
@@ -1477,9 +1474,6 @@ pub(super) fn realtime_text_for_event(msg: &EventMsg) -> Option<String> {
|
||||
| EventMsg::ElicitationRequest(_)
|
||||
| EventMsg::ApplyPatchApprovalRequest(_)
|
||||
| EventMsg::DeprecationNotice(_)
|
||||
| EventMsg::BackgroundEvent(_)
|
||||
| EventMsg::UndoStarted(_)
|
||||
| EventMsg::UndoCompleted(_)
|
||||
| EventMsg::StreamError(_)
|
||||
| EventMsg::TurnDiff(_)
|
||||
| EventMsg::GetHistoryEntryResponse(_)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
mod compact;
|
||||
mod regular;
|
||||
mod review;
|
||||
mod undo;
|
||||
mod user_shell;
|
||||
|
||||
use std::sync::Arc;
|
||||
@@ -57,7 +56,6 @@ use codex_protocol::models::ContentItem;
|
||||
pub(crate) use compact::CompactTask;
|
||||
pub(crate) use regular::RegularTask;
|
||||
pub(crate) use review::ReviewTask;
|
||||
pub(crate) use undo::UndoTask;
|
||||
pub(crate) use user_shell::UserShellCommandMode;
|
||||
pub(crate) use user_shell::UserShellCommandTask;
|
||||
pub(crate) use user_shell::execute_user_shell_command;
|
||||
|
||||
@@ -6,7 +6,6 @@ use codex_protocol::items::TurnItem;
|
||||
use codex_protocol::models::ContentItem;
|
||||
use codex_protocol::models::ResponseItem;
|
||||
use codex_protocol::protocol::AgentMessageContentDeltaEvent;
|
||||
use codex_protocol::protocol::AgentMessageDeltaEvent;
|
||||
use codex_protocol::protocol::AskForApproval;
|
||||
use codex_protocol::protocol::Event;
|
||||
use codex_protocol::protocol::EventMsg;
|
||||
@@ -162,7 +161,6 @@ async fn process_review_events(
|
||||
item: TurnItem::AgentMessage(_),
|
||||
..
|
||||
})
|
||||
| EventMsg::AgentMessageDelta(AgentMessageDeltaEvent { .. })
|
||||
| EventMsg::AgentMessageContentDelta(AgentMessageContentDeltaEvent { .. }) => {}
|
||||
EventMsg::TurnComplete(task_complete) => {
|
||||
// Parse review output from the last agent message (if present).
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::session::turn_context::TurnContext;
|
||||
use crate::state::TaskKind;
|
||||
use crate::tasks::SessionTask;
|
||||
use crate::tasks::SessionTaskContext;
|
||||
use codex_protocol::protocol::EventMsg;
|
||||
use codex_protocol::protocol::UndoCompletedEvent;
|
||||
use codex_protocol::protocol::UndoStartedEvent;
|
||||
use codex_protocol::user_input::UserInput;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
|
||||
pub(crate) struct UndoTask;
|
||||
|
||||
impl UndoTask {
|
||||
pub(crate) fn new() -> Self {
|
||||
Self
|
||||
}
|
||||
}
|
||||
|
||||
impl SessionTask for UndoTask {
|
||||
fn kind(&self) -> TaskKind {
|
||||
TaskKind::Regular
|
||||
}
|
||||
|
||||
fn span_name(&self) -> &'static str {
|
||||
"session_task.undo"
|
||||
}
|
||||
|
||||
async fn run(
|
||||
self: Arc<Self>,
|
||||
session: Arc<SessionTaskContext>,
|
||||
ctx: Arc<TurnContext>,
|
||||
_input: Vec<UserInput>,
|
||||
cancellation_token: CancellationToken,
|
||||
) -> Option<String> {
|
||||
session
|
||||
.session
|
||||
.services
|
||||
.session_telemetry
|
||||
.counter("codex.task.undo", /*inc*/ 1, &[]);
|
||||
let sess = session.clone_session();
|
||||
sess.send_event(
|
||||
ctx.as_ref(),
|
||||
EventMsg::UndoStarted(UndoStartedEvent {
|
||||
message: Some("Undo in progress...".to_string()),
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
|
||||
if cancellation_token.is_cancelled() {
|
||||
sess.send_event(
|
||||
ctx.as_ref(),
|
||||
EventMsg::UndoCompleted(UndoCompletedEvent {
|
||||
success: false,
|
||||
message: Some("Undo cancelled.".to_string()),
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
return None;
|
||||
}
|
||||
|
||||
let completed = UndoCompletedEvent {
|
||||
success: false,
|
||||
message: Some("Undo is no longer available.".to_string()),
|
||||
};
|
||||
|
||||
sess.send_event(ctx.as_ref(), EventMsg::UndoCompleted(completed))
|
||||
.await;
|
||||
None
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,6 @@ pub struct BatchJobHandler;
|
||||
const DEFAULT_AGENT_JOB_CONCURRENCY: usize = 16;
|
||||
const MAX_AGENT_JOB_CONCURRENCY: usize = 64;
|
||||
const STATUS_POLL_INTERVAL: Duration = Duration::from_millis(250);
|
||||
const PROGRESS_EMIT_INTERVAL: Duration = Duration::from_secs(1);
|
||||
const DEFAULT_AGENT_JOB_ITEM_TIMEOUT: Duration = Duration::from_secs(60 * 30);
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
@@ -83,17 +82,6 @@ struct AgentJobFailureSummary {
|
||||
last_error: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
struct AgentJobProgressUpdate {
|
||||
job_id: String,
|
||||
total_items: usize,
|
||||
pending_items: usize,
|
||||
running_items: usize,
|
||||
completed_items: usize,
|
||||
failed_items: usize,
|
||||
eta_seconds: Option<u64>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
struct ReportAgentJobResultToolResult {
|
||||
accepted: bool,
|
||||
@@ -112,73 +100,6 @@ struct ActiveJobItem {
|
||||
status_rx: Option<Receiver<AgentStatus>>,
|
||||
}
|
||||
|
||||
struct JobProgressEmitter {
|
||||
started_at: Instant,
|
||||
last_emit_at: Instant,
|
||||
last_processed: usize,
|
||||
last_failed: usize,
|
||||
}
|
||||
|
||||
impl JobProgressEmitter {
|
||||
fn new() -> Self {
|
||||
let now = Instant::now();
|
||||
let last_emit_at = now.checked_sub(PROGRESS_EMIT_INTERVAL).unwrap_or(now);
|
||||
Self {
|
||||
started_at: now,
|
||||
last_emit_at,
|
||||
last_processed: 0,
|
||||
last_failed: 0,
|
||||
}
|
||||
}
|
||||
|
||||
async fn maybe_emit(
|
||||
&mut self,
|
||||
session: &Session,
|
||||
turn: &TurnContext,
|
||||
job_id: &str,
|
||||
progress: &codex_state::AgentJobProgress,
|
||||
force: bool,
|
||||
) -> anyhow::Result<()> {
|
||||
let processed = progress.completed_items + progress.failed_items;
|
||||
let should_emit = force
|
||||
|| processed != self.last_processed
|
||||
|| progress.failed_items != self.last_failed
|
||||
|| self.last_emit_at.elapsed() >= PROGRESS_EMIT_INTERVAL;
|
||||
if !should_emit {
|
||||
return Ok(());
|
||||
}
|
||||
let elapsed = self.started_at.elapsed().as_secs_f64();
|
||||
let eta_seconds = if processed > 0 && elapsed > 0.0 {
|
||||
let remaining = progress.total_items.saturating_sub(processed) as f64;
|
||||
let rate = processed as f64 / elapsed;
|
||||
if rate > 0.0 {
|
||||
Some((remaining / rate).round() as u64)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let update = AgentJobProgressUpdate {
|
||||
job_id: job_id.to_string(),
|
||||
total_items: progress.total_items,
|
||||
pending_items: progress.pending_items,
|
||||
running_items: progress.running_items,
|
||||
completed_items: progress.completed_items,
|
||||
failed_items: progress.failed_items,
|
||||
eta_seconds,
|
||||
};
|
||||
let payload = serde_json::to_string(&update)?;
|
||||
session
|
||||
.notify_background_event(turn, format!("agent_job_progress:{payload}"))
|
||||
.await;
|
||||
self.last_emit_at = Instant::now();
|
||||
self.last_processed = processed;
|
||||
self.last_failed = progress.failed_items;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl ToolHandler for BatchJobHandler {
|
||||
type Output = FunctionToolOutput;
|
||||
|
||||
@@ -358,12 +279,6 @@ mod spawn_agents_on_csv {
|
||||
"failed to transition agent job {job_id} to running: {err}"
|
||||
))
|
||||
})?;
|
||||
let max_threads = turn.config.agent_max_threads;
|
||||
let effective_concurrency = options.max_concurrency;
|
||||
let message = format!(
|
||||
"agent job concurrency: job_id={job_id} requested={requested_concurrency:?} max_threads={max_threads:?} effective={effective_concurrency}"
|
||||
);
|
||||
let _ = session.notify_background_event(&turn, message).await;
|
||||
if let Err(err) = run_agent_job_loop(
|
||||
session.clone(),
|
||||
turn.clone(),
|
||||
@@ -584,7 +499,6 @@ async fn run_agent_job_loop(
|
||||
.ok_or_else(|| anyhow::anyhow!("agent job {job_id} was not found"))?;
|
||||
let runtime_timeout = job_runtime_timeout(&job);
|
||||
let mut active_items: HashMap<ThreadId, ActiveJobItem> = HashMap::new();
|
||||
let mut progress_emitter = JobProgressEmitter::new();
|
||||
recover_running_items(
|
||||
session.clone(),
|
||||
db.clone(),
|
||||
@@ -593,16 +507,6 @@ async fn run_agent_job_loop(
|
||||
runtime_timeout,
|
||||
)
|
||||
.await?;
|
||||
let initial_progress = db.get_agent_job_progress(job_id.as_str()).await?;
|
||||
progress_emitter
|
||||
.maybe_emit(
|
||||
&session,
|
||||
&turn,
|
||||
job_id.as_str(),
|
||||
&initial_progress,
|
||||
/*force*/ true,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let mut cancel_requested = db.is_agent_job_cancelled(job_id.as_str()).await?;
|
||||
loop {
|
||||
@@ -610,12 +514,6 @@ async fn run_agent_job_loop(
|
||||
|
||||
if !cancel_requested && db.is_agent_job_cancelled(job_id.as_str()).await? {
|
||||
cancel_requested = true;
|
||||
let _ = session
|
||||
.notify_background_event(
|
||||
&turn,
|
||||
format!("agent job {job_id} cancellation requested; stopping new workers"),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
if !cancel_requested && active_items.len() < options.max_concurrency {
|
||||
@@ -749,20 +647,9 @@ async fn run_agent_job_loop(
|
||||
)
|
||||
.await?;
|
||||
active_items.remove(&thread_id);
|
||||
let progress = db.get_agent_job_progress(job_id.as_str()).await?;
|
||||
progress_emitter
|
||||
.maybe_emit(
|
||||
&session,
|
||||
&turn,
|
||||
job_id.as_str(),
|
||||
&progress,
|
||||
/*force*/ false,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
|
||||
let progress = db.get_agent_job_progress(job_id.as_str()).await?;
|
||||
if let Err(err) = export_job_csv_snapshot(db.clone(), &job).await {
|
||||
let message = format!("auto-export failed: {err}");
|
||||
db.mark_agent_job_failed(job_id.as_str(), message.as_str())
|
||||
@@ -771,37 +658,9 @@ async fn run_agent_job_loop(
|
||||
}
|
||||
let cancelled = cancel_requested || db.is_agent_job_cancelled(job_id.as_str()).await?;
|
||||
if cancelled {
|
||||
let pending_items = progress.pending_items;
|
||||
let message =
|
||||
format!("agent job {job_id} cancelled with {pending_items} unprocessed items");
|
||||
let _ = session.notify_background_event(&turn, message).await;
|
||||
progress_emitter
|
||||
.maybe_emit(
|
||||
&session,
|
||||
&turn,
|
||||
job_id.as_str(),
|
||||
&progress,
|
||||
/*force*/ true,
|
||||
)
|
||||
.await?;
|
||||
return Ok(());
|
||||
}
|
||||
if progress.failed_items > 0 {
|
||||
let failed_items = progress.failed_items;
|
||||
let message = format!("agent job completed with {failed_items} failed items");
|
||||
let _ = session.notify_background_event(&turn, message).await;
|
||||
}
|
||||
db.mark_agent_job_completed(job_id.as_str()).await?;
|
||||
let progress = db.get_agent_job_progress(job_id.as_str()).await?;
|
||||
progress_emitter
|
||||
.maybe_emit(
|
||||
&session,
|
||||
&turn,
|
||||
job_id.as_str(),
|
||||
&progress,
|
||||
/*force*/ true,
|
||||
)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -229,21 +229,15 @@ async fn codex_delegate_ignores_legacy_deltas() {
|
||||
.expect("submit review");
|
||||
|
||||
let mut reasoning_delta_count = 0;
|
||||
let mut legacy_reasoning_delta_count = 0;
|
||||
|
||||
loop {
|
||||
let ev = wait_for_event(&test.codex, |_| true).await;
|
||||
match ev {
|
||||
EventMsg::ReasoningContentDelta(_) => reasoning_delta_count += 1,
|
||||
EventMsg::AgentReasoningDelta(_) => legacy_reasoning_delta_count += 1,
|
||||
EventMsg::TurnComplete(_) => break,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(reasoning_delta_count, 1, "expected one new reasoning delta");
|
||||
assert_eq!(
|
||||
legacy_reasoning_delta_count, 1,
|
||||
"expected one legacy reasoning delta"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2149,16 +2149,6 @@ async fn manual_compact_retries_after_context_window_error() {
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
|
||||
codex.submit(Op::Compact).await.unwrap();
|
||||
let EventMsg::BackgroundEvent(event) =
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::BackgroundEvent(_))).await
|
||||
else {
|
||||
panic!("expected background event after compact retry");
|
||||
};
|
||||
assert!(
|
||||
event.message.contains("Trimmed 1 older thread item"),
|
||||
"background event should mention trimmed item count: {}",
|
||||
event.message
|
||||
);
|
||||
let warning_event = wait_for_event(&codex, |ev| matches!(ev, EventMsg::Warning(_))).await;
|
||||
let EventMsg::Warning(WarningEvent { message }) = warning_event else {
|
||||
panic!("expected warning event after compact retry");
|
||||
|
||||
@@ -503,11 +503,6 @@ async fn agent_message_content_delta_has_item_metadata() -> anyhow::Result<()> {
|
||||
_ => None,
|
||||
})
|
||||
.await;
|
||||
let legacy_delta = wait_for_event_match(&codex, |ev| match ev {
|
||||
EventMsg::AgentMessageDelta(event) => Some(event.clone()),
|
||||
_ => None,
|
||||
})
|
||||
.await;
|
||||
let completed_item = wait_for_event_match(&codex, |ev| match ev {
|
||||
EventMsg::ItemCompleted(ItemCompletedEvent {
|
||||
item: TurnItem::AgentMessage(item),
|
||||
@@ -522,7 +517,6 @@ async fn agent_message_content_delta_has_item_metadata() -> anyhow::Result<()> {
|
||||
assert_eq!(delta_event.turn_id, started_turn_id);
|
||||
assert_eq!(delta_event.item_id, started_item.id);
|
||||
assert_eq!(delta_event.delta, "streamed response");
|
||||
assert_eq!(legacy_delta.delta, "streamed response");
|
||||
assert_eq!(completed_item.id, started_item.id);
|
||||
|
||||
Ok(())
|
||||
@@ -1091,15 +1085,8 @@ async fn reasoning_content_delta_has_item_metadata() -> anyhow::Result<()> {
|
||||
_ => None,
|
||||
})
|
||||
.await;
|
||||
let legacy_delta = wait_for_event_match(&codex, |ev| match ev {
|
||||
EventMsg::AgentReasoningDelta(event) => Some(event.clone()),
|
||||
_ => None,
|
||||
})
|
||||
.await;
|
||||
|
||||
assert_eq!(delta_event.item_id, reasoning_item.id);
|
||||
assert_eq!(delta_event.delta, "step one");
|
||||
assert_eq!(legacy_delta.delta, "step one");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1152,15 +1139,8 @@ async fn reasoning_raw_content_delta_respects_flag() -> anyhow::Result<()> {
|
||||
_ => None,
|
||||
})
|
||||
.await;
|
||||
let legacy_delta = wait_for_event_match(&codex, |ev| match ev {
|
||||
EventMsg::AgentReasoningRawContentDelta(event) => Some(event.clone()),
|
||||
_ => None,
|
||||
})
|
||||
.await;
|
||||
|
||||
assert_eq!(delta_event.item_id, reasoning_item.id);
|
||||
assert_eq!(delta_event.delta, "raw detail");
|
||||
assert_eq!(legacy_delta.delta, "raw detail");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -102,7 +102,6 @@ mod tool_suggest;
|
||||
mod tools;
|
||||
mod truncation;
|
||||
mod turn_state;
|
||||
mod undo;
|
||||
mod unified_exec;
|
||||
mod unstable_features_warning;
|
||||
mod user_notification;
|
||||
|
||||
@@ -233,7 +233,6 @@ async fn review_op_with_plain_text_emits_review_fallback() {
|
||||
|
||||
/// Ensure review flow suppresses assistant-specific streaming/completion events:
|
||||
/// - AgentMessageContentDelta
|
||||
/// - AgentMessageDelta (legacy)
|
||||
/// - ItemCompleted for TurnItem::AgentMessage
|
||||
// Windows CI only: bump to 4 workers to prevent SSE/event starvation and test timeouts.
|
||||
#[cfg_attr(windows, tokio::test(flavor = "multi_thread", worker_threads = 4))]
|
||||
@@ -290,9 +289,6 @@ async fn review_filters_agent_message_related_events() {
|
||||
EventMsg::AgentMessageContentDelta(_) => {
|
||||
panic!("unexpected AgentMessageContentDelta surfaced during review")
|
||||
}
|
||||
EventMsg::AgentMessageDelta(_) => {
|
||||
panic!("unexpected AgentMessageDelta surfaced during review")
|
||||
}
|
||||
_ => false,
|
||||
})
|
||||
.await;
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
#![cfg(not(target_os = "windows"))]
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::Result;
|
||||
use codex_core::CodexThread;
|
||||
use codex_protocol::protocol::EventMsg;
|
||||
use codex_protocol::protocol::Op;
|
||||
use codex_protocol::protocol::UndoCompletedEvent;
|
||||
use core_test_support::test_codex::TestCodexHarness;
|
||||
use core_test_support::test_codex::test_codex;
|
||||
use core_test_support::wait_for_event_match;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
async fn undo_harness() -> Result<TestCodexHarness> {
|
||||
TestCodexHarness::with_builder(test_codex().with_model("gpt-5.4")).await
|
||||
}
|
||||
|
||||
async fn invoke_undo(codex: &Arc<CodexThread>) -> Result<UndoCompletedEvent> {
|
||||
codex.submit(Op::Undo).await?;
|
||||
let event = wait_for_event_match(codex, |msg| match msg {
|
||||
EventMsg::UndoCompleted(done) => Some(done.clone()),
|
||||
_ => None,
|
||||
})
|
||||
.await;
|
||||
Ok(event)
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn undo_reports_feature_removal() -> Result<()> {
|
||||
let harness = undo_harness().await?;
|
||||
let codex = Arc::clone(&harness.test().codex);
|
||||
|
||||
let event = invoke_undo(&codex).await?;
|
||||
|
||||
assert!(!event.success, "expected undo to fail");
|
||||
assert_eq!(
|
||||
event.message.as_deref(),
|
||||
Some("Undo is no longer available.")
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -328,12 +328,6 @@ async fn run_codex_tool_session_inner(
|
||||
EventMsg::ThreadGoalUpdated(_) => {
|
||||
// Ignore thread goal metadata updates in MCP tool runner.
|
||||
}
|
||||
EventMsg::AgentMessageDelta(_) => {
|
||||
// TODO: think how we want to support this in the MCP
|
||||
}
|
||||
EventMsg::AgentReasoningDelta(_) => {
|
||||
// TODO: think how we want to support this in the MCP
|
||||
}
|
||||
EventMsg::McpStartupUpdate(_) | EventMsg::McpStartupComplete(_) => {
|
||||
// Ignored in MCP tool runner.
|
||||
}
|
||||
@@ -341,7 +335,6 @@ async fn run_codex_tool_session_inner(
|
||||
// TODO: think how we want to support this in the MCP
|
||||
}
|
||||
EventMsg::AgentReasoningRawContent(_)
|
||||
| EventMsg::AgentReasoningRawContentDelta(_)
|
||||
| EventMsg::TurnStarted(_)
|
||||
| EventMsg::TokenCount(_)
|
||||
| EventMsg::AgentReasoning(_)
|
||||
@@ -355,7 +348,6 @@ async fn run_codex_tool_session_inner(
|
||||
| EventMsg::TerminalInteraction(_)
|
||||
| EventMsg::ExecCommandOutputDelta(_)
|
||||
| EventMsg::ExecCommandEnd(_)
|
||||
| EventMsg::BackgroundEvent(_)
|
||||
| EventMsg::StreamError(_)
|
||||
| EventMsg::PatchApplyBegin(_)
|
||||
| EventMsg::PatchApplyUpdated(_)
|
||||
@@ -381,8 +373,6 @@ async fn run_codex_tool_session_inner(
|
||||
| EventMsg::ReasoningContentDelta(_)
|
||||
| EventMsg::ReasoningRawContentDelta(_)
|
||||
| EventMsg::SkillsUpdateAvailable
|
||||
| EventMsg::UndoStarted(_)
|
||||
| EventMsg::UndoCompleted(_)
|
||||
| EventMsg::ExitedReviewMode(_)
|
||||
| EventMsg::RequestUserInput(_)
|
||||
| EventMsg::RequestPermissions(_)
|
||||
|
||||
@@ -777,12 +777,6 @@ pub enum Op {
|
||||
/// model.
|
||||
SetThreadMemoryMode { mode: ThreadMemoryMode },
|
||||
|
||||
/// Legacy request to undo a turn.
|
||||
///
|
||||
/// The op is still accepted for compatibility, but ghost snapshots are no
|
||||
/// longer produced so the request reports unavailable.
|
||||
Undo,
|
||||
|
||||
/// Request Codex to drop the last N user turns from in-memory context.
|
||||
///
|
||||
/// This does not attempt to revert local filesystem changes. Clients are
|
||||
@@ -911,7 +905,6 @@ impl Op {
|
||||
Self::Compact => "compact",
|
||||
Self::SetThreadName { .. } => "set_thread_name",
|
||||
Self::SetThreadMemoryMode { .. } => "set_thread_memory_mode",
|
||||
Self::Undo => "undo",
|
||||
Self::ThreadRollback { .. } => "thread_rollback",
|
||||
Self::Review { .. } => "review",
|
||||
Self::ApproveGuardianDeniedAction { .. } => "approve_guardian_denied_action",
|
||||
@@ -1368,20 +1361,12 @@ pub enum EventMsg {
|
||||
/// User/system input message (what was sent to the model)
|
||||
UserMessage(UserMessageEvent),
|
||||
|
||||
/// Agent text output delta message
|
||||
AgentMessageDelta(AgentMessageDeltaEvent),
|
||||
|
||||
/// Reasoning event from agent.
|
||||
AgentReasoning(AgentReasoningEvent),
|
||||
|
||||
/// Agent reasoning delta event from agent.
|
||||
AgentReasoningDelta(AgentReasoningDeltaEvent),
|
||||
|
||||
/// Raw chain-of-thought from agent.
|
||||
AgentReasoningRawContent(AgentReasoningRawContentEvent),
|
||||
|
||||
/// Agent reasoning content delta event from agent.
|
||||
AgentReasoningRawContentDelta(AgentReasoningRawContentDeltaEvent),
|
||||
/// Signaled when the model begins a new reasoning summary section (e.g., a new titled block).
|
||||
AgentReasoningSectionBreak(AgentReasoningSectionBreakEvent),
|
||||
|
||||
@@ -1447,12 +1432,6 @@ pub enum EventMsg {
|
||||
/// deprecated and should be phased out.
|
||||
DeprecationNotice(DeprecationNoticeEvent),
|
||||
|
||||
BackgroundEvent(BackgroundEventEvent),
|
||||
|
||||
UndoStarted(UndoStartedEvent),
|
||||
|
||||
UndoCompleted(UndoCompletedEvent),
|
||||
|
||||
/// Notification that a model stream experienced an error or disconnect
|
||||
/// and the system is handling it (e.g., retrying with backoff).
|
||||
StreamError(StreamErrorEvent),
|
||||
@@ -1894,9 +1873,7 @@ pub struct AgentMessageContentDeltaEvent {
|
||||
|
||||
impl HasLegacyEvent for AgentMessageContentDeltaEvent {
|
||||
fn as_legacy_events(&self, _: bool) -> Vec<EventMsg> {
|
||||
vec![EventMsg::AgentMessageDelta(AgentMessageDeltaEvent {
|
||||
delta: self.delta.clone(),
|
||||
})]
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1921,9 +1898,7 @@ pub struct ReasoningContentDeltaEvent {
|
||||
|
||||
impl HasLegacyEvent for ReasoningContentDeltaEvent {
|
||||
fn as_legacy_events(&self, _: bool) -> Vec<EventMsg> {
|
||||
vec![EventMsg::AgentReasoningDelta(AgentReasoningDeltaEvent {
|
||||
delta: self.delta.clone(),
|
||||
})]
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1940,11 +1915,7 @@ pub struct ReasoningRawContentDeltaEvent {
|
||||
|
||||
impl HasLegacyEvent for ReasoningRawContentDeltaEvent {
|
||||
fn as_legacy_events(&self, _: bool) -> Vec<EventMsg> {
|
||||
vec![EventMsg::AgentReasoningRawContentDelta(
|
||||
AgentReasoningRawContentDeltaEvent {
|
||||
delta: self.delta.clone(),
|
||||
},
|
||||
)]
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2309,11 +2280,6 @@ pub struct UserMessageEvent {
|
||||
pub text_elements: Vec<crate::user_input::TextElement>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)]
|
||||
pub struct AgentMessageDeltaEvent {
|
||||
pub delta: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)]
|
||||
pub struct AgentReasoningEvent {
|
||||
pub text: String,
|
||||
@@ -2324,11 +2290,6 @@ pub struct AgentReasoningRawContentEvent {
|
||||
pub text: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)]
|
||||
pub struct AgentReasoningRawContentDeltaEvent {
|
||||
pub delta: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)]
|
||||
pub struct AgentReasoningSectionBreakEvent {
|
||||
// load with default value so it's backward compatible with the old format.
|
||||
@@ -2338,11 +2299,6 @@ pub struct AgentReasoningSectionBreakEvent {
|
||||
pub summary_index: i64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)]
|
||||
pub struct AgentReasoningDeltaEvent {
|
||||
pub delta: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS, PartialEq)]
|
||||
pub struct McpInvocation {
|
||||
/// Name of the MCP server as defined in the config.
|
||||
@@ -3188,11 +3144,6 @@ pub struct TerminalInteractionEvent {
|
||||
pub stdin: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)]
|
||||
pub struct BackgroundEventEvent {
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)]
|
||||
pub struct DeprecationNoticeEvent {
|
||||
/// Concise summary of what is deprecated.
|
||||
@@ -3202,19 +3153,6 @@ pub struct DeprecationNoticeEvent {
|
||||
pub details: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)]
|
||||
pub struct UndoStartedEvent {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub message: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)]
|
||||
pub struct UndoCompletedEvent {
|
||||
pub success: bool,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub message: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)]
|
||||
pub struct ThreadRolledBackEvent {
|
||||
/// Number of user turns that were removed from context.
|
||||
|
||||
@@ -232,11 +232,8 @@ pub(crate) fn tool_runtime_trace_event(event: &EventMsg) -> Option<ToolRuntimeTr
|
||||
| EventMsg::TokenCount(_)
|
||||
| EventMsg::AgentMessage(_)
|
||||
| EventMsg::UserMessage(_)
|
||||
| EventMsg::AgentMessageDelta(_)
|
||||
| EventMsg::AgentReasoning(_)
|
||||
| EventMsg::AgentReasoningDelta(_)
|
||||
| EventMsg::AgentReasoningRawContent(_)
|
||||
| EventMsg::AgentReasoningRawContentDelta(_)
|
||||
| EventMsg::AgentReasoningSectionBreak(_)
|
||||
| EventMsg::SessionConfigured(_)
|
||||
| EventMsg::ThreadNameUpdated(_)
|
||||
@@ -260,9 +257,6 @@ pub(crate) fn tool_runtime_trace_event(event: &EventMsg) -> Option<ToolRuntimeTr
|
||||
| EventMsg::ApplyPatchApprovalRequest(_)
|
||||
| EventMsg::GuardianAssessment(_)
|
||||
| EventMsg::DeprecationNotice(_)
|
||||
| EventMsg::BackgroundEvent(_)
|
||||
| EventMsg::UndoStarted(_)
|
||||
| EventMsg::UndoCompleted(_)
|
||||
| EventMsg::StreamError(_)
|
||||
| EventMsg::PatchApplyUpdated(_)
|
||||
| EventMsg::TurnDiff(_)
|
||||
@@ -312,11 +306,8 @@ pub(crate) fn wrapped_protocol_event_type(event: &EventMsg) -> Option<&'static s
|
||||
| EventMsg::TokenCount(_)
|
||||
| EventMsg::AgentMessage(_)
|
||||
| EventMsg::UserMessage(_)
|
||||
| EventMsg::AgentMessageDelta(_)
|
||||
| EventMsg::AgentReasoning(_)
|
||||
| EventMsg::AgentReasoningDelta(_)
|
||||
| EventMsg::AgentReasoningRawContent(_)
|
||||
| EventMsg::AgentReasoningRawContentDelta(_)
|
||||
| EventMsg::AgentReasoningSectionBreak(_)
|
||||
| EventMsg::ThreadGoalUpdated(_)
|
||||
| EventMsg::McpStartupUpdate(_)
|
||||
@@ -341,9 +332,6 @@ pub(crate) fn wrapped_protocol_event_type(event: &EventMsg) -> Option<&'static s
|
||||
| EventMsg::ApplyPatchApprovalRequest(_)
|
||||
| EventMsg::GuardianAssessment(_)
|
||||
| EventMsg::DeprecationNotice(_)
|
||||
| EventMsg::BackgroundEvent(_)
|
||||
| EventMsg::UndoStarted(_)
|
||||
| EventMsg::UndoCompleted(_)
|
||||
| EventMsg::StreamError(_)
|
||||
| EventMsg::PatchApplyBegin(_)
|
||||
| EventMsg::PatchApplyUpdated(_)
|
||||
|
||||
@@ -101,7 +101,6 @@ fn event_msg_persistence_mode(ev: &EventMsg) -> Option<EventPersistenceMode> {
|
||||
| EventMsg::EnteredReviewMode(_)
|
||||
| EventMsg::ExitedReviewMode(_)
|
||||
| EventMsg::ThreadRolledBack(_)
|
||||
| EventMsg::UndoCompleted(_)
|
||||
| EventMsg::TurnAborted(_)
|
||||
| EventMsg::TurnStarted(_)
|
||||
| EventMsg::TurnComplete(_)
|
||||
@@ -137,15 +136,11 @@ fn event_msg_persistence_mode(ev: &EventMsg) -> Option<EventPersistenceMode> {
|
||||
| EventMsg::RealtimeConversationClosed(_)
|
||||
| EventMsg::ModelReroute(_)
|
||||
| EventMsg::ModelVerification(_)
|
||||
| EventMsg::AgentMessageDelta(_)
|
||||
| EventMsg::AgentReasoningDelta(_)
|
||||
| EventMsg::AgentReasoningRawContentDelta(_)
|
||||
| EventMsg::AgentReasoningSectionBreak(_)
|
||||
| EventMsg::RawResponseItem(_)
|
||||
| EventMsg::SessionConfigured(_)
|
||||
| EventMsg::ThreadGoalUpdated(_)
|
||||
| EventMsg::McpToolCallBegin(_)
|
||||
| EventMsg::WebSearchBegin(_)
|
||||
| EventMsg::ExecCommandBegin(_)
|
||||
| EventMsg::TerminalInteraction(_)
|
||||
| EventMsg::ExecCommandOutputDelta(_)
|
||||
@@ -154,18 +149,17 @@ fn event_msg_persistence_mode(ev: &EventMsg) -> Option<EventPersistenceMode> {
|
||||
| EventMsg::RequestUserInput(_)
|
||||
| EventMsg::ElicitationRequest(_)
|
||||
| EventMsg::ApplyPatchApprovalRequest(_)
|
||||
| EventMsg::BackgroundEvent(_)
|
||||
| EventMsg::StreamError(_)
|
||||
| EventMsg::PatchApplyBegin(_)
|
||||
| EventMsg::PatchApplyUpdated(_)
|
||||
| EventMsg::TurnDiff(_)
|
||||
| EventMsg::GetHistoryEntryResponse(_)
|
||||
| EventMsg::UndoStarted(_)
|
||||
| EventMsg::McpListToolsResponse(_)
|
||||
| EventMsg::RealtimeConversationListVoicesResponse(_)
|
||||
| EventMsg::McpStartupUpdate(_)
|
||||
| EventMsg::McpStartupComplete(_)
|
||||
| EventMsg::ListSkillsResponse(_)
|
||||
| EventMsg::WebSearchBegin(_)
|
||||
| EventMsg::PlanUpdate(_)
|
||||
| EventMsg::ShutdownComplete
|
||||
| EventMsg::DeprecationNotice(_)
|
||||
@@ -176,12 +170,12 @@ fn event_msg_persistence_mode(ev: &EventMsg) -> Option<EventPersistenceMode> {
|
||||
| EventMsg::PlanDelta(_)
|
||||
| EventMsg::ReasoningContentDelta(_)
|
||||
| EventMsg::ReasoningRawContentDelta(_)
|
||||
| EventMsg::ImageGenerationBegin(_)
|
||||
| EventMsg::SkillsUpdateAvailable
|
||||
| EventMsg::CollabAgentSpawnBegin(_)
|
||||
| EventMsg::CollabAgentInteractionBegin(_)
|
||||
| EventMsg::CollabWaitingBegin(_)
|
||||
| EventMsg::CollabCloseBegin(_)
|
||||
| EventMsg::CollabResumeBegin(_)
|
||||
| EventMsg::ImageGenerationBegin(_) => None,
|
||||
| EventMsg::CollabResumeBegin(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -319,9 +319,6 @@ impl ChatWidget {
|
||||
SlashCommand::Logout => {
|
||||
self.app_event_tx.send(AppEvent::Logout);
|
||||
}
|
||||
// SlashCommand::Undo => {
|
||||
// self.app_event_tx.send(AppEvent::CodexOp(Op::Undo));
|
||||
// }
|
||||
SlashCommand::Copy => {
|
||||
self.copy_last_agent_markdown();
|
||||
}
|
||||
|
||||
@@ -40,7 +40,6 @@ pub enum SlashCommand {
|
||||
Collab,
|
||||
Agent,
|
||||
Side,
|
||||
// Undo,
|
||||
Copy,
|
||||
Diff,
|
||||
Mention,
|
||||
@@ -87,7 +86,6 @@ impl SlashCommand {
|
||||
SlashCommand::Resume => "resume a saved chat",
|
||||
SlashCommand::Clear => "clear the terminal and start a new chat",
|
||||
SlashCommand::Fork => "fork the current chat",
|
||||
// SlashCommand::Undo => "ask Codex to undo a turn",
|
||||
SlashCommand::Quit | SlashCommand::Exit => "exit Codex",
|
||||
SlashCommand::Copy => "copy last response as markdown",
|
||||
SlashCommand::Diff => "show git diff (including untracked files)",
|
||||
@@ -173,7 +171,6 @@ impl SlashCommand {
|
||||
| SlashCommand::Fork
|
||||
| SlashCommand::Init
|
||||
| SlashCommand::Compact
|
||||
// | SlashCommand::Undo
|
||||
| SlashCommand::Model
|
||||
| SlashCommand::Fast
|
||||
| SlashCommand::Personality
|
||||
|
||||
Reference in New Issue
Block a user