Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 16 additions & 19 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ name = "codex_acp"
path = "src/lib.rs"

[dependencies]
agent-client-protocol = { version = "=0.12.1", features = ["unstable"] }
agent-client-protocol = { version = "=0.14.0", features = ["unstable"] }
anyhow = "1"
clap = "4"
codex-apply-patch = { git = "https://github.com/openai/codex", tag = "rust-v0.137.0" }
Expand Down
115 changes: 74 additions & 41 deletions src/codex_agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ use acp::schema::{
LoadSessionRequest, LoadSessionResponse, LogoutCapabilities, LogoutRequest, LogoutResponse,
McpCapabilities, McpServer, McpServerHttp, McpServerStdio, NewSessionRequest,
NewSessionResponse, PromptCapabilities, PromptRequest, PromptResponse, ProtocolVersion,
SessionCapabilities, SessionCloseCapabilities, SessionId, SessionInfo, SessionListCapabilities,
ResumeSessionRequest, ResumeSessionResponse, SessionCapabilities, SessionCloseCapabilities,
SessionId, SessionInfo, SessionListCapabilities, SessionResumeCapabilities,
SetSessionConfigOptionRequest, SetSessionConfigOptionResponse, SetSessionModeRequest,
SetSessionModeResponse, SetSessionModelRequest, SetSessionModelResponse,
SetSessionModeResponse,
};
use acp::{Agent, Client, ConnectTo, ConnectionTo, Error};
use agent_client_protocol as acp;
Expand Down Expand Up @@ -187,6 +188,24 @@ impl CodexAgent {
},
acp::on_receive_request!(),
)
.on_receive_request(
{
let agent = agent.clone();
async move |request: ResumeSessionRequest,
responder,
cx: ConnectionTo<Client>| {
let agent = agent.clone();
let session_cx = cx.clone();
cx.spawn(async move {
responder.respond_with_result(
agent.resume_session(request, session_cx).await,
)
})?;
Ok(())
}
},
acp::on_receive_request!(),
)
.on_receive_request(
{
let agent = agent.clone();
Expand Down Expand Up @@ -261,21 +280,6 @@ impl CodexAgent {
},
acp::on_receive_request!(),
)
.on_receive_request(
{
let agent = agent.clone();
async move |request: SetSessionModelRequest,
responder,
cx: ConnectionTo<Client>| {
let agent = agent.clone();
cx.spawn(async move {
responder.respond_with_result(agent.set_session_model(request).await)
})?;
Ok(())
}
},
acp::on_receive_request!(),
)
.on_receive_request(
{
let agent = agent.clone();
Expand Down Expand Up @@ -447,7 +451,8 @@ impl CodexAgent {

agent_capabilities.session_capabilities = SessionCapabilities::new()
.close(SessionCloseCapabilities::new())
.list(SessionListCapabilities::new());
.list(SessionListCapabilities::new())
.resume(SessionResumeCapabilities::new());

let mut auth_methods = vec![
CodexAuthMethod::ChatGpt.into(),
Expand Down Expand Up @@ -590,7 +595,6 @@ impl CodexAgent {

Ok(NewSessionResponse::new(session_id)
.modes(load.modes)
.models(load.models)
.config_options(load.config_options))
}

Expand All @@ -610,6 +614,43 @@ impl CodexAgent {
..
} = request;

self.restore_session(session_id, cwd, mcp_servers, cx, true)
.await
}

async fn resume_session(
&self,
request: ResumeSessionRequest,
cx: ConnectionTo<Client>,
) -> Result<ResumeSessionResponse, Error> {
info!("Resuming session: {}", request.session_id);
// Check before sending if authentication was successful or not
self.check_auth().await?;

let ResumeSessionRequest {
session_id,
cwd,
mcp_servers,
..
} = request;

let load = self
.restore_session(session_id, cwd, mcp_servers, cx, false)
.await?;

Ok(ResumeSessionResponse::new()
.modes(load.modes)
.config_options(load.config_options))
}

async fn restore_session(
&self,
session_id: SessionId,
cwd: PathBuf,
mcp_servers: Vec<McpServer>,
cx: ConnectionTo<Client>,
replay_history: bool,
) -> Result<LoadSessionResponse, Error> {
let rollout_path = find_thread_path_by_id_str(
&self.config.codex_home,
session_id.0.as_ref(),
Expand All @@ -619,14 +660,18 @@ impl CodexAgent {
.map_err(|e| Error::internal_error().data(e.to_string()))?
.ok_or_else(|| Error::resource_not_found(None))?;

let history = RolloutRecorder::get_rollout_history(&rollout_path)
.await
.map_err(|e| Error::internal_error().data(e.to_string()))?;
let rollout_items = if replay_history {
let history = RolloutRecorder::get_rollout_history(&rollout_path)
.await
.map_err(|e| Error::internal_error().data(e.to_string()))?;

let rollout_items = match &history {
InitialHistory::Resumed(resumed) => resumed.history.clone(),
InitialHistory::Forked(items) => items.clone(),
InitialHistory::Cleared | InitialHistory::New => Vec::new(),
match &history {
InitialHistory::Resumed(resumed) => resumed.history.clone(),
InitialHistory::Forked(items) => items.clone(),
InitialHistory::Cleared | InitialHistory::New => Vec::new(),
}
} else {
Vec::new()
};

let config = self.build_session_config(&cwd, mcp_servers)?;
Expand Down Expand Up @@ -654,7 +699,9 @@ impl CodexAgent {
cx,
));

thread.replay_history(rollout_items).await?;
if replay_history {
thread.replay_history(rollout_items).await?;
}

let load = thread.load().await?;

Expand All @@ -666,7 +713,6 @@ impl CodexAgent {

Ok(LoadSessionResponse::new()
.modes(load.modes)
.models(load.models)
.config_options(load.config_options))
}

Expand Down Expand Up @@ -783,19 +829,6 @@ impl CodexAgent {
Ok(SetSessionModeResponse::default())
}

async fn set_session_model(
&self,
args: SetSessionModelRequest,
) -> Result<SetSessionModelResponse, Error> {
info!("Setting session model for session: {}", args.session_id);

self.get_thread(&args.session_id)?
.set_model(args.model_id)
.await?;

Ok(SetSessionModelResponse::default())
}

async fn set_session_config_option(
&self,
args: SetSessionConfigOptionRequest,
Expand Down
Loading
Loading