Upgrade Gemini and ACP (#1431)

* Upgrade Gemini and ACP

Upgrade ACP SDK version to the latest.
Upgrade Gemini-CLI to the latest working version.

* fmt
This commit is contained in:
Solomon
2025-12-04 16:13:59 +00:00
committed by GitHub
parent 8a91dba6e3
commit 2b11040d07
6 changed files with 54 additions and 72 deletions

15
Cargo.lock generated
View File

@@ -206,27 +206,26 @@ dependencies = [
[[package]]
name = "agent-client-protocol"
version = "0.4.7"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76133c067c37ae7a3641c3ad1ec88f36aac06cea5f9b3b49b5c29f18214f9101"
checksum = "3e639d6b544ad39f5b4e05802db5eb04e1518284eb05fda1839931003e0244c8"
dependencies = [
"agent-client-protocol-schema",
"anyhow",
"async-broadcast",
"async-trait",
"derive_more",
"futures",
"log",
"parking_lot",
"schemars 1.0.4",
"serde",
"serde_json",
]
[[package]]
name = "agent-client-protocol-schema"
version = "0.4.11"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61be4454304d7df1a5b44c4ae55e707ffe72eac4dfb1ef8762510ce8d8f6d924"
checksum = "f182f5e14bef8232b239719bd99166bb11e986c08fc211f28e392f880d3093ba"
dependencies = [
"anyhow",
"derive_more",
@@ -295,7 +294,7 @@ version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
dependencies = [
"windows-sys 0.60.2",
"windows-sys 0.61.2",
]
[[package]]
@@ -306,7 +305,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
dependencies = [
"anstyle",
"once_cell_polyfill",
"windows-sys 0.60.2",
"windows-sys 0.61.2",
]
[[package]]

View File

@@ -39,7 +39,7 @@ convert_case = "0.6"
sqlx = "0.8.6"
axum = { workspace = true }
shlex = "1.3.0"
agent-client-protocol = "0.4"
agent-client-protocol = "0.8"
codex-protocol = { git = "https://github.com/openai/codex.git", package = "codex-protocol", rev = "80d6a3868ef1414e0fb1c2e28a369f2ef4fa4dcc" }
codex-app-server-protocol = { git = "https://github.com/openai/codex.git", package = "codex-app-server-protocol", rev = "80d6a3868ef1414e0fb1c2e28a369f2ef4fa4dcc" }
codex-mcp-types = { git = "https://github.com/openai/codex.git", package = "mcp-types", rev = "80d6a3868ef1414e0fb1c2e28a369f2ef4fa4dcc" }

View File

@@ -50,26 +50,23 @@ impl acp::Client for AcpClient {
.or_else(|| args.options.first());
let outcome = if let Some(opt) = chosen_option {
debug!("Auto-approving permission with option: {}", opt.id);
acp::RequestPermissionOutcome::Selected {
option_id: opt.id.clone(),
}
debug!("Auto-approving permission with option: {}", opt.option_id);
acp::RequestPermissionOutcome::Selected(acp::SelectedPermissionOutcome::new(
opt.option_id.clone(),
))
} else {
warn!("No permission options available, cancelling");
acp::RequestPermissionOutcome::Cancelled
};
Ok(acp::RequestPermissionResponse {
outcome,
meta: None,
})
Ok(acp::RequestPermissionResponse::new(outcome))
}
async fn session_notification(&self, args: acp::SessionNotification) -> Result<(), acp::Error> {
// Convert to typed events
let event = match args.update {
acp::SessionUpdate::AgentMessageChunk { content } => Some(AcpEvent::Message(content)),
acp::SessionUpdate::AgentThoughtChunk { content } => Some(AcpEvent::Thought(content)),
acp::SessionUpdate::AgentMessageChunk(chunk) => Some(AcpEvent::Message(chunk.content)),
acp::SessionUpdate::AgentThoughtChunk(chunk) => Some(AcpEvent::Thought(chunk.content)),
acp::SessionUpdate::ToolCall(tc) => Some(AcpEvent::ToolCall(tc)),
acp::SessionUpdate::ToolCallUpdate(update) => Some(AcpEvent::ToolUpdate(update)),
acp::SessionUpdate::Plan(plan) => Some(AcpEvent::Plan(plan)),

View File

@@ -272,19 +272,7 @@ impl AcpAgentHarness {
// Initialize
let _ = conn
.initialize(proto::InitializeRequest {
protocol_version: proto::V1,
client_capabilities: proto::ClientCapabilities {
fs: proto::FileSystemCapability {
read_text_file: false,
write_text_file: false,
meta: None,
},
terminal: false,
meta: None,
},
meta: None,
})
.initialize(proto::InitializeRequest::new(proto::ProtocolVersion::V1))
.await;
// Handle session creation/forking
@@ -298,14 +286,13 @@ impl AcpAgentHarness {
let meta =
history.map(|h| serde_json::json!({ "history_jsonl": h }));
match conn
.new_session(proto::NewSessionRequest {
mcp_servers: vec![],
cwd: cwd.clone(),
meta,
})
.await
let mut req = proto::NewSessionRequest::new(cwd.clone());
if let Some(m) = meta
&& let Some(obj) = m.as_object()
{
req = req.meta(obj.clone());
}
match conn.new_session(req).await {
Ok(resp) => {
let resume_prompt = session_manager
.generate_resume_prompt(&new_ui_id, &prompt)
@@ -320,11 +307,7 @@ impl AcpAgentHarness {
} else {
// New session
match conn
.new_session(proto::NewSessionRequest {
mcp_servers: vec![],
cwd: cwd.clone(),
meta: None,
})
.new_session(proto::NewSessionRequest::new(cwd.clone()))
.await
{
Ok(resp) => {
@@ -364,15 +347,12 @@ impl AcpAgentHarness {
);
// Build prompt request
let req = proto::PromptRequest {
session_id: proto::SessionId(acp_session_id.clone().into()),
prompt: vec![proto::ContentBlock::Text(proto::TextContent {
annotations: None,
text: prompt_to_send,
meta: None,
})],
meta: None,
};
let req = proto::PromptRequest::new(
proto::SessionId::new(acp_session_id.clone()),
vec![proto::ContentBlock::Text(proto::TextContent::new(
prompt_to_send,
))],
);
// Send the prompt and await completion to obtain stop_reason
match conn.prompt(req).await {
@@ -403,10 +383,9 @@ impl AcpAgentHarness {
// Cancel session work
let _ = conn
.cancel(proto::CancelNotification {
session_id: proto::SessionId(acp_session_id.into()),
meta: None,
})
.cancel(proto::CancelNotification::new(proto::SessionId::new(
acp_session_id,
)))
.await;
// Cleanup

View File

@@ -183,7 +183,7 @@ pub fn normalize_logs(msg_store: Arc<MsgStore>, worktree_path: &Path) {
let mut update = update;
if update.fields.title.is_none() {
update.fields.title = tool_states
.get(&update.id.0.to_string())
.get(&update.tool_call_id.0.to_string())
.map(|s| s.title.clone())
.or_else(|| Some("".to_string()));
}
@@ -216,7 +216,7 @@ pub fn normalize_logs(msg_store: Arc<MsgStore>, worktree_path: &Path) {
) {
streaming.assistant_text = None;
streaming.thinking_text = None;
let id = tc.id.0.to_string();
let id = tc.tool_call_id.0.to_string();
let is_new = !tool_states.contains_key(&id);
let tool_data = tool_states.entry(id).or_default();
tool_data.extend(tc, worktree_path);
@@ -373,7 +373,9 @@ pub fn normalize_logs(msg_store: Arc<MsgStore>, worktree_path: &Path) {
agent_client_protocol::ToolKind::SwitchMode => ActionType::Other {
description: "switch_mode".to_string(),
},
agent_client_protocol::ToolKind::Other | agent_client_protocol::ToolKind::Move => {
agent_client_protocol::ToolKind::Other
| agent_client_protocol::ToolKind::Move
| _ => {
// Derive a friendlier tool name from the id if it looks like name-<digits>
let tool_name = extract_tool_name_from_id(tc.id.0.as_ref())
.unwrap_or_else(|| tc.title.clone());
@@ -411,7 +413,7 @@ pub fn normalize_logs(msg_store: Arc<MsgStore>, worktree_path: &Path) {
fn extract_file_changes(tc: &PartialToolCallData) -> Vec<FileChange> {
let mut changes = Vec::new();
for c in &tc.content {
if let agent_client_protocol::ToolCallContent::Diff { diff } = c {
if let agent_client_protocol::ToolCallContent::Diff(diff) = c {
let path = diff.path.to_string_lossy().to_string();
let rel = if !path.is_empty() {
path
@@ -497,8 +499,8 @@ pub fn normalize_logs(msg_store: Arc<MsgStore>, worktree_path: &Path) {
) -> Option<String> {
let mut out = String::new();
for c in content {
if let agent_client_protocol::ToolCallContent::Content { content } = c
&& let agent_client_protocol::ContentBlock::Text(t) = content
if let agent_client_protocol::ToolCallContent::Content(inner) = c
&& let agent_client_protocol::ContentBlock::Text(t) = &inner.content
{
out.push_str(&t.text);
if !out.ends_with('\n') {
@@ -515,6 +517,10 @@ pub fn normalize_logs(msg_store: Arc<MsgStore>, worktree_path: &Path) {
| agent_client_protocol::ToolCallStatus::InProgress => LogToolStatus::Created,
agent_client_protocol::ToolCallStatus::Completed => LogToolStatus::Success,
agent_client_protocol::ToolCallStatus::Failed => LogToolStatus::Failed,
_ => {
tracing::debug!("Unknown tool call status: {:?}", status);
LogToolStatus::Created
}
}
}
});
@@ -534,7 +540,7 @@ struct PartialToolCallData {
impl PartialToolCallData {
fn extend(&mut self, tc: &agent_client_protocol::ToolCall, worktree_path: &Path) {
self.id = tc.id.clone();
self.id = tc.tool_call_id.clone();
if tc.kind != Default::default() {
self.kind = tc.kind;
}
@@ -567,7 +573,7 @@ impl PartialToolCallData {
impl Default for PartialToolCallData {
fn default() -> Self {
Self {
id: agent_client_protocol::ToolCallId(Default::default()),
id: agent_client_protocol::ToolCallId::new(""),
index: 0,
kind: agent_client_protocol::ToolKind::default(),
title: String::new(),
@@ -623,16 +629,16 @@ impl TryFrom<SessionNotification> for AcpEvent {
fn try_from(notification: SessionNotification) -> Result<Self, ()> {
let event = match notification.update {
acp::SessionUpdate::AgentMessageChunk { content } => AcpEvent::Message(content),
acp::SessionUpdate::AgentThoughtChunk { content } => AcpEvent::Thought(content),
acp::SessionUpdate::AgentMessageChunk(chunk) => AcpEvent::Message(chunk.content),
acp::SessionUpdate::AgentThoughtChunk(chunk) => AcpEvent::Thought(chunk.content),
acp::SessionUpdate::ToolCall(tc) => AcpEvent::ToolCall(tc),
acp::SessionUpdate::ToolCallUpdate(update) => AcpEvent::ToolUpdate(update),
acp::SessionUpdate::Plan(plan) => AcpEvent::Plan(plan),
acp::SessionUpdate::AvailableCommandsUpdate { available_commands } => {
AcpEvent::AvailableCommands(available_commands)
acp::SessionUpdate::AvailableCommandsUpdate(update) => {
AcpEvent::AvailableCommands(update.available_commands)
}
acp::SessionUpdate::CurrentModeUpdate { current_mode_id } => {
AcpEvent::CurrentMode(current_mode_id)
acp::SessionUpdate::CurrentModeUpdate(update) => {
AcpEvent::CurrentMode(update.current_mode_id)
}
_ => return Err(()),
};

View File

@@ -29,7 +29,8 @@ pub struct Gemini {
impl Gemini {
fn build_command_builder(&self) -> CommandBuilder {
let mut builder = CommandBuilder::new("npx -y @google/gemini-cli@0.16.0");
let mut builder =
CommandBuilder::new("npx -y @google/gemini-cli@0.21.0-nightly.20251204.3da4fd5f7");
if let Some(model) = &self.model {
builder = builder.extend_params(["--model", model.as_str()]);