Use replace

Agus Zubiaga created

Change summary

.github/workflows/agent_servers_e2e.yml | 118 +++++++++++++++++++++++++++
crates/agent_servers/src/claude.rs      |  10 +
crates/agent_servers/src/e2e_tests.rs   |   7 
3 files changed, 127 insertions(+), 8 deletions(-)

Detailed changes

.github/workflows/agent_servers_e2e.yml 🔗

@@ -0,0 +1,118 @@
+name: Agent Servers E2E Tests
+
+on:
+  schedule:
+    # Run once a day at 2:00 AM UTC
+    - cron: "0 2 * * *"
+
+  push:
+    branches:
+      - main
+      - "v[0-9]+.[0-9]+.x"
+    paths:
+      - "crates/agent_servers/**"
+      - "crates/acp_thread/**"
+      - ".github/workflows/agent_servers_e2e.yml"
+
+  pull_request:
+    branches:
+      - "**"
+    paths:
+      - "crates/agent_servers/**"
+      - "crates/acp_thread/**"
+      - ".github/workflows/agent_servers_e2e.yml"
+
+  workflow_dispatch:
+
+concurrency:
+  group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.ref_name == 'main' && github.sha || 'anysha' }}
+  cancel-in-progress: true
+
+env:
+  CARGO_TERM_COLOR: always
+  CARGO_INCREMENTAL: 0
+  RUST_BACKTRACE: 1
+  ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
+  GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
+
+jobs:
+  e2e-tests:
+    name: Run Agent Servers E2E Tests
+    if: github.repository_owner == 'zed-industries'
+    timeout-minutes: 60
+    runs-on:
+      - buildjet-16vcpu-ubuntu-2204
+
+    steps:
+      - name: Checkout repo
+        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
+        with:
+          clean: false
+
+      - name: Checkout gemini-cli repo
+        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
+        with:
+          repository: zed-industries/gemini-cli
+          ref: migrate-acp
+          path: gemini-cli
+          clean: false
+
+      - name: Install Rust
+        shell: bash -euxo pipefail {0}
+        run: |
+          cargo install cargo-nextest --locked
+
+      - name: Install Node
+        uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
+        with:
+          node-version: "18"
+
+      - name: Install Claude Code CLI
+        shell: bash -euxo pipefail {0}
+        run: |
+          npm install -g @anthropic-ai/claude-code
+          # Verify installation
+          which claude || echo "Claude CLI not found in PATH"
+          # Skip authentication if API key is not set (tests may use mock)
+          if [ -n "$ANTHROPIC_API_KEY" ]; then
+            echo "Anthropic API key is configured"
+          fi
+
+      - name: Install and setup Gemini CLI
+        shell: bash -euxo pipefail {0}
+        run: |
+          # Install globally for potential fallback
+          npm install -g @google/gemini-cli
+
+          # Also install dependencies for local gemini-cli repo
+          cd gemini-cli/packages/cli
+          npm install
+          cd -
+
+          # Verify installations
+          which gemini || echo "Gemini CLI not found in PATH"
+          # Skip authentication if API key is not set (tests may use mock)
+          if [ -n "$GEMINI_API_KEY" ]; then
+            echo "Gemini API key is configured"
+          fi
+
+      - name: Limit target directory size
+        shell: bash -euxo pipefail {0}
+        run: script/clear-target-dir-if-larger-than 100
+
+      - name: Run E2E tests
+        shell: bash -euxo pipefail {0}
+        run: |
+          cargo nextest run \
+            --package agent_servers \
+            --features e2e \
+            --no-fail-fast
+
+      - name: Upload test results
+        if: failure()
+        uses: actions/upload-artifact@v4
+        with:
+          name: test-results
+          path: |
+            target/nextest/default/*.xml
+          retention-days: 7

crates/agent_servers/src/claude.rs 🔗

@@ -263,7 +263,7 @@ impl AgentConnection for ClaudeAgentConnection {
         let cancellation_state = session.cancellation_state.clone();
         cx.foreground_executor().spawn(async move {
             let result = rx.await??;
-            *cancellation_state.borrow_mut() = CancellationState::None;
+            cancellation_state.replace(CancellationState::None);
             Ok(result)
         })
     }
@@ -277,9 +277,11 @@ impl AgentConnection for ClaudeAgentConnection {
 
         let request_id = new_request_id();
 
-        *session.cancellation_state.borrow_mut() = CancellationState::Requested {
-            request_id: request_id.clone(),
-        };
+        session
+            .cancellation_state
+            .replace(CancellationState::Requested {
+                request_id: request_id.clone(),
+            });
 
         session
             .outgoing_tx

crates/agent_servers/src/e2e_tests.rs 🔗

@@ -246,7 +246,7 @@ pub async fn test_cancel(server: impl AgentServer + 'static, cx: &mut TestAppCon
 
     let project = Project::test(fs, [path!("/private/tmp").as_ref()], cx).await;
     let thread = new_test_thread(server, project.clone(), "/private/tmp", cx).await;
-    let full_turn = thread.update(cx, |thread, cx| {
+    let _ = thread.update(cx, |thread, cx| {
         thread.send_raw(
             r#"Run exactly `touch hello.txt && echo "Hello, world!" | tee hello.txt` in the terminal."#,
             cx,
@@ -285,9 +285,8 @@ pub async fn test_cancel(server: impl AgentServer + 'static, cx: &mut TestAppCon
         id.clone()
     });
 
-    let _ = thread.update(cx, |thread, cx| thread.cancel(cx));
-    full_turn.await.unwrap();
-    thread.read_with(cx, |thread, _| {
+    thread.update(cx, |thread, cx| thread.cancel(cx)).await;
+    thread.read_with(cx, |thread, _cx| {
         let AgentThreadEntry::ToolCall(ToolCall {
             status: ToolCallStatus::Canceled,
             ..