recursive-agent 0.6.0

A minimal, orthogonal, self-improving coding agent kernel in Rust
Documentation
name: "Context compaction e2e test"
description: |
  Verify that the context compaction feature works correctly:
    - Start server with a very low RECURSIVE_COMPACT_THRESHOLD (100 chars)
      so compaction fires after the first long response.
    - Send two messages in the same session.
    - The first response is long enough to exceed the threshold.
    - The second message must succeed — proving the agent is still functional
      after compaction and does not crash or return an error.

  The compactor is enabled via RECURSIVE_COMPACT_THRESHOLD env var.
sequential: true

setup:
  - name: "Kill any leftover server on port 9099"
    ignoreError: true
    exec:
      container: recursive-e2e
      command: |
        pkill -f 'http --addr 0.0.0.0:9099' 2>/dev/null || true
        sleep 1
        echo cleaned

  - name: "Reset state files"
    ignoreError: true
    exec:
      container: recursive-e2e
      command: rm -f /tmp/compact-result.txt /tmp/compact-http.log && echo reset

  - name: "Start HTTP server on port 9099 with low compaction threshold"
    exec:
      container: recursive-e2e
      command: |
        nohup env RECURSIVE_COMPACT_THRESHOLD=100 recursive \
          --api-base http://aimock:4010/v1 \
          --api-key mock-key -m mock-chat \
          http --addr 0.0.0.0:9099 \
          > /tmp/compact-http.log 2>&1 &
        sleep 2
        echo started

  - name: "Sanity: GET /health returns ok"
    exec:
      container: recursive-e2e
      command: curl -sf http://localhost:9099/health
    expect:
      exitCode: 0
      output:
        contains: "ok"

  - name: "Create a session and run two turns to trigger compaction"
    exec:
      container: recursive-e2e
      command: |
        # Create session
        SESSION=$(curl -sf -X POST http://localhost:9099/sessions | jq -r '.id')
        echo "session=$SESSION"

        # Turn 1: long response to exceed 100-char threshold
        RESP1=$(curl -sf -X POST http://localhost:9099/sessions/$SESSION/messages \
          -H 'Content-Type: application/json' \
          -d '{"message":"compaction-turn-1"}')
        echo "turn1_role=$(echo $RESP1 | jq -r '.role')"
        echo "turn1_ok=$(echo $RESP1 | jq -r '.content' | grep -c 'compaction' || echo 0)"

        # Turn 2: after compaction — must still work
        RESP2=$(curl -sf -X POST http://localhost:9099/sessions/$SESSION/messages \
          -H 'Content-Type: application/json' \
          -d '{"message":"compaction-turn-2"}')
        echo "turn2_role=$(echo $RESP2 | jq -r '.role')"
        echo "turn2_ok=$(echo $RESP2 | jq -r '.content' | grep -c 'Compaction' || echo 0)"

        # Save results
        printf "session=%s\nturn1_role=%s\nturn2_role=%s\n" \
          "$SESSION" \
          "$(echo $RESP1 | jq -r '.role')" \
          "$(echo $RESP2 | jq -r '.role')" \
          > /tmp/compact-result.txt
        cat /tmp/compact-result.txt
    expect:
      exitCode: 0
      output:
        contains:
          - "session="
          - "turn1_role=assistant"
          - "turn2_role=assistant"

cases:
  - name: "Turn 1 completes successfully (triggering compaction)"
    file:
      container: recursive-e2e
      path: /tmp/compact-result.txt
      exists: true
      contains: "turn1_role=assistant"

  - name: "Turn 2 completes successfully after compaction"
    file:
      container: recursive-e2e
      path: /tmp/compact-result.txt
      exists: true
      contains: "turn2_role=assistant"

teardown:
  - name: "Stop HTTP server on 9099 and clean up"
    ignoreError: true
    exec:
      container: recursive-e2e
      command: |
        pkill -f 'http --addr 0.0.0.0:9099' 2>/dev/null || true
        rm -f /tmp/compact-result.txt /tmp/compact-http.log
        echo stopped