mirror of
https://github.com/openai/codex.git
synced 2026-06-01 19:02:59 +00:00
V1
This commit is contained in:
@@ -109,6 +109,7 @@ use codex_git_tooling::GhostCommit;
|
||||
use codex_git_tooling::GitToolingError;
|
||||
use codex_git_tooling::create_ghost_commit;
|
||||
use codex_git_tooling::restore_ghost_commit;
|
||||
use codex_utils_readiness::ReadinessFlag;
|
||||
|
||||
const MAX_TRACKED_GHOST_COMMITS: usize = 20;
|
||||
|
||||
@@ -182,6 +183,7 @@ pub(crate) struct ChatWidgetInit {
|
||||
pub(crate) struct ChatWidget {
|
||||
app_event_tx: AppEventSender,
|
||||
codex_op_tx: UnboundedSender<Op>,
|
||||
turn_readiness: UnboundedSender<Arc<ReadinessFlag>>,
|
||||
bottom_pane: BottomPane,
|
||||
active_exec_cell: Option<ExecCell>,
|
||||
config: Config,
|
||||
@@ -772,12 +774,14 @@ impl ChatWidget {
|
||||
} = common;
|
||||
let mut rng = rand::rng();
|
||||
let placeholder = EXAMPLE_PROMPTS[rng.random_range(0..EXAMPLE_PROMPTS.len())].to_string();
|
||||
let codex_op_tx = spawn_agent(config.clone(), app_event_tx.clone(), conversation_manager);
|
||||
let agent_channels =
|
||||
spawn_agent(config.clone(), app_event_tx.clone(), conversation_manager);
|
||||
|
||||
Self {
|
||||
app_event_tx: app_event_tx.clone(),
|
||||
frame_requester: frame_requester.clone(),
|
||||
codex_op_tx,
|
||||
codex_op_tx: agent_channels.op_tx,
|
||||
turn_readiness: agent_channels.turn_readiness,
|
||||
bottom_pane: BottomPane::new(BottomPaneParams {
|
||||
frame_requester,
|
||||
app_event_tx,
|
||||
@@ -832,13 +836,14 @@ impl ChatWidget {
|
||||
let mut rng = rand::rng();
|
||||
let placeholder = EXAMPLE_PROMPTS[rng.random_range(0..EXAMPLE_PROMPTS.len())].to_string();
|
||||
|
||||
let codex_op_tx =
|
||||
let agent_channels =
|
||||
spawn_agent_from_existing(conversation, session_configured, app_event_tx.clone());
|
||||
|
||||
Self {
|
||||
app_event_tx: app_event_tx.clone(),
|
||||
frame_requester: frame_requester.clone(),
|
||||
codex_op_tx,
|
||||
codex_op_tx: agent_channels.op_tx,
|
||||
turn_readiness: agent_channels.turn_readiness,
|
||||
bottom_pane: BottomPane::new(BottomPaneParams {
|
||||
frame_requester,
|
||||
app_event_tx,
|
||||
@@ -1121,6 +1126,9 @@ impl ChatWidget {
|
||||
return;
|
||||
}
|
||||
|
||||
let readiness_flag = Arc::new(ReadinessFlag::new());
|
||||
agent::send_turn_readiness(&self.turn_readiness, Arc::clone(&readiness_flag));
|
||||
|
||||
self.capture_ghost_snapshot();
|
||||
|
||||
let mut items: Vec<InputItem> = Vec::new();
|
||||
|
||||
@@ -5,20 +5,58 @@ use codex_core::ConversationManager;
|
||||
use codex_core::NewConversation;
|
||||
use codex_core::config::Config;
|
||||
use codex_core::protocol::Op;
|
||||
use codex_utils_readiness::Readiness;
|
||||
use codex_utils_readiness::ReadinessFlag;
|
||||
use tokio::sync::mpsc::UnboundedReceiver;
|
||||
use tokio::sync::mpsc::UnboundedSender;
|
||||
use tokio::sync::mpsc::unbounded_channel;
|
||||
|
||||
use crate::app_event::AppEvent;
|
||||
use crate::app_event_sender::AppEventSender;
|
||||
|
||||
pub(crate) struct AgentChannels {
|
||||
pub(crate) op_tx: UnboundedSender<Op>,
|
||||
pub(crate) turn_readiness: UnboundedSender<Arc<ReadinessFlag>>,
|
||||
}
|
||||
fn mark_ready(flag: Arc<ReadinessFlag>) {
|
||||
tokio::spawn(async move {
|
||||
if let Ok(token) = flag.subscribe().await {
|
||||
let _ = flag.mark_ready(token).await;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn spawn_readiness_forwarder(
|
||||
mut rx: UnboundedReceiver<Arc<ReadinessFlag>>,
|
||||
sender: UnboundedSender<Arc<ReadinessFlag>>,
|
||||
) {
|
||||
tokio::spawn(async move {
|
||||
while let Some(flag) = rx.recv().await {
|
||||
if sender.send(Arc::clone(&flag)).is_err() {
|
||||
mark_ready(flag);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub(crate) fn send_turn_readiness(
|
||||
sender: &UnboundedSender<Arc<ReadinessFlag>>,
|
||||
flag: Arc<ReadinessFlag>,
|
||||
) {
|
||||
if sender.send(Arc::clone(&flag)).is_err() {
|
||||
mark_ready(flag);
|
||||
}
|
||||
}
|
||||
|
||||
/// Spawn the agent bootstrapper and op forwarding loop, returning the
|
||||
/// `UnboundedSender<Op>` used by the UI to submit operations.
|
||||
/// channels used by the UI to submit operations and register turn readiness.
|
||||
pub(crate) fn spawn_agent(
|
||||
config: Config,
|
||||
app_event_tx: AppEventSender,
|
||||
server: Arc<ConversationManager>,
|
||||
) -> UnboundedSender<Op> {
|
||||
) -> AgentChannels {
|
||||
let (codex_op_tx, mut codex_op_rx) = unbounded_channel::<Op>();
|
||||
let (turn_readiness_tx, turn_readiness_rx) = unbounded_channel::<Arc<ReadinessFlag>>();
|
||||
|
||||
let app_event_tx_clone = app_event_tx;
|
||||
tokio::spawn(async move {
|
||||
@@ -35,6 +73,9 @@ pub(crate) fn spawn_agent(
|
||||
}
|
||||
};
|
||||
|
||||
let readiness_sender = conversation.turn_readiness_sender();
|
||||
spawn_readiness_forwarder(turn_readiness_rx, readiness_sender);
|
||||
|
||||
// Forward the captured `SessionConfigured` event so it can be rendered in the UI.
|
||||
let ev = codex_core::protocol::Event {
|
||||
// The `id` does not matter for rendering, so we can use a fake value.
|
||||
@@ -58,7 +99,10 @@ pub(crate) fn spawn_agent(
|
||||
}
|
||||
});
|
||||
|
||||
codex_op_tx
|
||||
AgentChannels {
|
||||
op_tx: codex_op_tx,
|
||||
turn_readiness: turn_readiness_tx,
|
||||
}
|
||||
}
|
||||
|
||||
/// Spawn agent loops for an existing conversation (e.g., a forked conversation).
|
||||
@@ -68,8 +112,10 @@ pub(crate) fn spawn_agent_from_existing(
|
||||
conversation: std::sync::Arc<CodexConversation>,
|
||||
session_configured: codex_core::protocol::SessionConfiguredEvent,
|
||||
app_event_tx: AppEventSender,
|
||||
) -> UnboundedSender<Op> {
|
||||
) -> AgentChannels {
|
||||
let (codex_op_tx, mut codex_op_rx) = unbounded_channel::<Op>();
|
||||
let (turn_readiness_tx, turn_readiness_rx) = unbounded_channel::<Arc<ReadinessFlag>>();
|
||||
spawn_readiness_forwarder(turn_readiness_rx, conversation.turn_readiness_sender());
|
||||
|
||||
let app_event_tx_clone = app_event_tx;
|
||||
tokio::spawn(async move {
|
||||
@@ -95,5 +141,8 @@ pub(crate) fn spawn_agent_from_existing(
|
||||
}
|
||||
});
|
||||
|
||||
codex_op_tx
|
||||
AgentChannels {
|
||||
op_tx: codex_op_tx,
|
||||
turn_readiness: turn_readiness_tx,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ use codex_core::protocol::StreamErrorEvent;
|
||||
use codex_core::protocol::TaskCompleteEvent;
|
||||
use codex_core::protocol::TaskStartedEvent;
|
||||
use codex_protocol::mcp_protocol::ConversationId;
|
||||
use codex_utils_readiness::ReadinessFlag;
|
||||
use crossterm::event::KeyCode;
|
||||
use crossterm::event::KeyEvent;
|
||||
use crossterm::event::KeyModifiers;
|
||||
@@ -43,6 +44,7 @@ use std::fs::File;
|
||||
use std::io::BufRead;
|
||||
use std::io::BufReader;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use tempfile::NamedTempFile;
|
||||
use tokio::sync::mpsc::unbounded_channel;
|
||||
|
||||
@@ -310,9 +312,11 @@ fn make_chatwidget_manual() -> (
|
||||
disable_paste_burst: false,
|
||||
});
|
||||
let auth_manager = AuthManager::from_auth_for_testing(CodexAuth::from_api_key("test"));
|
||||
let (turn_readiness, _rx) = unbounded_channel::<Arc<ReadinessFlag>>();
|
||||
let widget = ChatWidget {
|
||||
app_event_tx,
|
||||
codex_op_tx: op_tx,
|
||||
turn_readiness,
|
||||
bottom_pane: bottom,
|
||||
active_exec_cell: None,
|
||||
config: cfg.clone(),
|
||||
|
||||
Reference in New Issue
Block a user