refactor: unify response processing under AgentPipeline
#386
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Container | |
| on: | |
| merge_group: | |
| pull_request: | |
| paths: | |
| - ".dockerignore" | |
| - ".github/workflows/container.yml" | |
| - "Cargo.lock" | |
| - "Cargo.toml" | |
| - "Dockerfile" | |
| - "docker-entrypoint.sh" | |
| - "crates/**" | |
| - "!crates/**/tests/**" | |
| - "scripts/container-fixture-server.py" | |
| - "scripts/fixtures/vllm-response-single-nonstreaming.json" | |
| - "scripts/test-container-entrypoint.sh" | |
| push: | |
| branches: [main] | |
| paths: | |
| - ".dockerignore" | |
| - ".github/workflows/container.yml" | |
| - "Cargo.lock" | |
| - "Cargo.toml" | |
| - "Dockerfile" | |
| - "docker-entrypoint.sh" | |
| - "crates/**" | |
| - "!crates/**/tests/**" | |
| - "scripts/container-fixture-server.py" | |
| - "scripts/fixtures/vllm-response-single-nonstreaming.json" | |
| - "scripts/test-container-entrypoint.sh" | |
| permissions: | |
| contents: read | |
| jobs: | |
| build-and-smoke-test: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - name: Check out repository | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - name: Test container entrypoint | |
| run: scripts/test-container-entrypoint.sh | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@37fe631027851001ddb9b187196cc803df7f5f0e # v4.3.0 | |
| - name: Generate image metadata | |
| id: image-metadata | |
| run: echo "created=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> "$GITHUB_OUTPUT" | |
| - name: Build runtime image | |
| uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0 | |
| with: | |
| context: . | |
| load: true | |
| tags: agentic-api:test | |
| build-args: | | |
| OCI_BUILD_PIPELINE=${{ github.workflow }} | |
| OCI_BUILD_URL=${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} | |
| OCI_CREATED=${{ steps.image-metadata.outputs.created }} | |
| OCI_REVISION=${{ github.sha }} | |
| OCI_VERSION=${{ github.ref_name }} | |
| cache-from: type=gha,scope=agentic-api-container | |
| cache-to: type=gha,mode=max,scope=agentic-api-container,ignore-error=true | |
| - name: Verify runtime contents and identity | |
| run: | | |
| docker run --rm --entrypoint sh agentic-api:test -eu -c ' | |
| for command in cargo rustc python vllm; do | |
| ! command -v "$command" | |
| done | |
| test "$(id -u)" -ne 0 | |
| test "$(id -g)" -eq 0 | |
| test ! -w /usr/local/bin/agentic-server | |
| test ! -w /usr/local/bin/docker-entrypoint.sh | |
| ' | |
| container_id=$(docker create agentic-api:test) | |
| binary_copy=$(mktemp) | |
| cleanup_binary() { | |
| docker rm --force "$container_id" >/dev/null 2>&1 || true | |
| rm -f "$binary_copy" | |
| } | |
| trap cleanup_binary EXIT | |
| docker cp "$container_id:/usr/local/bin/agentic-server" "$binary_copy" | |
| binary_description=$(file "$binary_copy") | |
| echo "$binary_description" | |
| case "$binary_description" in | |
| *"not stripped"*) exit 1 ;; | |
| *"stripped"*) ;; | |
| *) echo "unable to verify that agentic-server is stripped" >&2; exit 1 ;; | |
| esac | |
| volume_dir=$(mktemp -d) | |
| cleanup_volume() { | |
| sudo rm -rf "$volume_dir" | |
| } | |
| trap 'cleanup_binary; cleanup_volume' EXIT | |
| sudo chgrp 0 "$volume_dir" | |
| chmod 2775 "$volume_dir" | |
| docker run --rm --user 12345:0 \ | |
| --volume "$volume_dir:/var/lib/agentic-api" \ | |
| --entrypoint sh agentic-api:test \ | |
| -eu -c 'touch /var/lib/agentic-api/write-check && test -w /var/lib/agentic-api/write-check' | |
| - name: Test Responses API end to end | |
| run: | | |
| python3 scripts/container-fixture-server.py \ | |
| --fixture scripts/fixtures/vllm-response-single-nonstreaming.json \ | |
| --port 18000 \ | |
| >/tmp/agentic-api-upstream.log 2>&1 & | |
| upstream_pid=$! | |
| volume=agentic-api-smoke-data | |
| upstream_response_id=$(jq --exit-status --raw-output \ | |
| '.id | select(type == "string" and length > 0)' \ | |
| scripts/fixtures/vllm-response-single-nonstreaming.json) | |
| cleanup() { | |
| docker logs agentic-api-smoke 2>/dev/null || true | |
| docker rm --force agentic-api-smoke >/dev/null 2>&1 || true | |
| docker volume rm "$volume" >/dev/null 2>&1 || true | |
| kill "$upstream_pid" 2>/dev/null || true | |
| } | |
| trap cleanup EXIT | |
| start_gateway() { | |
| docker run --detach --name agentic-api-smoke --network host --user "$1:0" \ | |
| --volume "$volume:/var/lib/agentic-api" \ | |
| --env LLM_API_BASE=http://127.0.0.1:18000 \ | |
| agentic-api:test | |
| } | |
| wait_until_ready() { | |
| for attempt in $(seq 1 30); do | |
| if curl --connect-timeout 1 --max-time 3 --fail --silent http://127.0.0.1:9000/health >/dev/null && \ | |
| curl --connect-timeout 1 --max-time 3 --fail --silent http://127.0.0.1:9000/ready >/dev/null; then | |
| return 0 | |
| fi | |
| echo "gateway not ready (attempt $attempt/30)" | |
| sleep 1 | |
| done | |
| return 1 | |
| } | |
| post_response() { | |
| jq --null-input --compact-output --arg previous_response_id "$1" ' | |
| { | |
| input: "Reply with exactly one word: HELLO", | |
| model: "gpt-4o", | |
| store: true, | |
| stream: false | |
| } + if $previous_response_id == "" then {} else { | |
| previous_response_id: $previous_response_id | |
| } end | |
| ' >/tmp/agentic-api-request.json | |
| curl --connect-timeout 2 --max-time 15 --fail --silent --show-error \ | |
| --header 'Content-Type: application/json' \ | |
| --data-binary @/tmp/agentic-api-request.json \ | |
| --output "$2" \ | |
| http://127.0.0.1:9000/v1/responses | |
| jq --exit-status --arg upstream_response_id "$upstream_response_id" ' | |
| .status == "completed" and | |
| (.id | startswith("resp_")) and | |
| .id != $upstream_response_id and | |
| .model == "gpt-4o" and | |
| .output[0].content[0].text == "HI" | |
| ' "$2" | |
| } | |
| docker volume create "$volume" | |
| start_gateway 12345 | |
| wait_until_ready | |
| post_response "" /tmp/agentic-api-response-1.json | |
| first_response_id=$(jq --exit-status --raw-output '.id' /tmp/agentic-api-response-1.json) | |
| docker exec agentic-api-smoke test -f /var/lib/agentic-api/agentic_api.db | |
| docker stop --timeout 10 agentic-api-smoke | |
| test "$(docker inspect --format '{{.State.ExitCode}}' agentic-api-smoke)" -eq 0 | |
| docker rm agentic-api-smoke | |
| start_gateway 23456 | |
| wait_until_ready | |
| post_response "$first_response_id" /tmp/agentic-api-response-2.json | |
| second_response_id=$(jq --exit-status --raw-output '.id' /tmp/agentic-api-response-2.json) | |
| post_response "$second_response_id" /tmp/agentic-api-response-3.json | |
| if docker logs agentic-api-smoke 2>&1 | grep --quiet 'persist failed'; then | |
| echo "SQLite persistence failed after arbitrary-UID rotation" >&2 | |
| exit 1 | |
| fi | |
| docker stop --timeout 10 agentic-api-smoke | |
| test "$(docker inspect --format '{{.State.ExitCode}}' agentic-api-smoke)" -eq 0 |