Skip to content
Open
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
b08b5d8
feat: add CI harness smoke test pipeline with automated result verifi…
omkargaikwad23 Sep 10, 2026
0d032bf
Merge branch 'main' into feat/ci-harness-smoke
omkargaikwad23 Sep 11, 2026
b977e23
Merge branch 'main' into feat/ci-harness-smoke
omkargaikwad23 Sep 11, 2026
f9f17b4
feat: centralize model configurations in .ci/ directory and update mo…
omkargaikwad23 Sep 11, 2026
f8082d5
chore: update gemini-cli version, improve CI build caching, and remov…
omkargaikwad23 Sep 11, 2026
9f478d0
chore: update EVAL_GCP_PROJECT_REGION to global in cloudbuild configu…
omkargaikwad23 Sep 11, 2026
8dbd976
chore: parameterize secret project ID and update Gemini cloud locatio…
omkargaikwad23 Sep 11, 2026
ffb7f7f
feat: add step to fetch service account key from Secret Manager and m…
omkargaikwad23 Sep 11, 2026
4a78c93
refactor: clarify cloudbuild steps and optimize volume mounts for ind…
omkargaikwad23 Sep 11, 2026
d65ff56
feat: capture and log probe process output and exit code in agy_cli e…
omkargaikwad23 Sep 11, 2026
b59399c
refactor: remove trajectory_matcher threshold gating and update CI ca…
omkargaikwad23 Sep 11, 2026
455462d
feat: update secret key name to be consistent with other key names
omkargaikwad23 Sep 11, 2026
9765893
ci: llm key name
omkargaikwad23 Sep 11, 2026
ec1a392
Change OpenAI API key secret version to latest
omkargaikwad23 Sep 11, 2026
b41f45e
Change OpenAI API key secret version to 2
omkargaikwad23 Sep 11, 2026
2c6ef86
refactor: remove inline comments from CI configuration and update clo…
omkargaikwad23 Sep 11, 2026
a5376cb
Merge branch 'main' into feat/ci-harness-smoke
omkargaikwad23 Sep 14, 2026
1d42c70
revert: drop agy_cli probe output logging
omkargaikwad23 Sep 14, 2026
e5043fa
fix: enforce non-zero trajectory_matcher scores and handle non-finite…
omkargaikwad23 Sep 14, 2026
7385d02
feat: add agy_cli model configuration and update run config path
omkargaikwad23 Sep 14, 2026
61f5d89
refactor: consolidate individual harness run configs into a single pa…
omkargaikwad23 Sep 14, 2026
d260e3b
Merge branch 'main' into feat/ci-harness-smoke
prernakakkar-google Sep 14, 2026
d0edc76
chore: update model versions and reduce max turns for smoke harness
omkargaikwad23 Sep 14, 2026
7f08d5d
Update vertex_region to 'global' in model config
omkargaikwad23 Sep 15, 2026
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
99 changes: 99 additions & 0 deletions .ci/harness.cloudbuild.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
steps:
- id: pull-cache
name: 'gcr.io/cloud-builders/docker'
entrypoint: 'bash'
args: ['-c', 'docker pull us-central1-docker.pkg.dev/$PROJECT_ID/evalbench/evalbench-harness-ci:cache || exit 0']

- id: build-image
name: 'gcr.io/cloud-builders/docker'
waitFor: ['pull-cache']
args: ['build',
'--cache-from', 'us-central1-docker.pkg.dev/$PROJECT_ID/evalbench/evalbench-harness-ci:cache',
'-t', 'evalbench-harness-ci',
'-t', 'us-central1-docker.pkg.dev/$PROJECT_ID/evalbench/evalbench-harness-ci:cache',
'-f', 'evalbench_service/Dockerfile', '.']

# Pushed here rather than via top-level `images:`, which only runs when the
# whole build succeeds -- the failing builds would never warm the cache.
- id: push-cache
name: 'gcr.io/cloud-builders/docker'
waitFor: ['build-image']
allowFailure: true
args: ['push', 'us-central1-docker.pkg.dev/$PROJECT_ID/evalbench/evalbench-harness-ci:cache']

- id: fetch-sa-key
name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
entrypoint: 'bash'
waitFor: ['-']
args:
- '-c'
- |
mkdir -p /etc/evalbench-sa-key
gcloud secrets versions access latest --secret="evalbench-sa-key" --project="$_EVAL_PROJECT" > /etc/evalbench-sa-key/key.json
volumes:
- name: 'sa_key_volume'
path: '/etc/evalbench-sa-key'

- id: agy-cli
name: 'evalbench-harness-ci'
dir: '/evalbench'
waitFor: ['build-image', 'fetch-sa-key']
allowFailure: true
entrypoint: 'bash'
args: ['-c', 'CI_HARNESS=agy_cli uv run --no-sync evalbench/evalbench.py --experiment_config=.ci/run_config.yaml']
env: &harness_env
- 'EVAL_GCP_PROJECT_ID=${_EVAL_PROJECT}'
- 'EVAL_GCP_PROJECT_REGION=global'
- 'CI_CSQL_INSTANCE=${_CI_CSQL_INSTANCE}'
- 'UV_CACHE_DIR=/tmp/uv-cache'
volumes:
- name: 'eval_results'
path: '/evalbench/results'
- name: 'sa_key_volume'
path: '/etc/evalbench-sa-key'

- id: claude-code
name: 'evalbench-harness-ci'
dir: '/evalbench'
waitFor: ['build-image']
allowFailure: true
entrypoint: 'bash'
args: ['-c', 'CI_HARNESS=claude_code uv run --no-sync evalbench/evalbench.py --experiment_config=.ci/run_config.yaml']
env: *harness_env
volumes: &results_volume
- name: 'eval_results'
path: '/evalbench/results'

- id: codex-cli
name: 'evalbench-harness-ci'
dir: '/evalbench'
waitFor: ['build-image']
allowFailure: true
entrypoint: 'bash'
args: ['-c', 'CI_HARNESS=codex_cli uv run --no-sync evalbench/evalbench.py --experiment_config=.ci/run_config.yaml']
env: *harness_env
volumes: *results_volume

- id: gemini-cli
name: 'evalbench-harness-ci'
dir: '/evalbench'
waitFor: ['build-image']
allowFailure: true
entrypoint: 'bash'
args: ['-c', 'CI_HARNESS=gemini_cli uv run --no-sync evalbench/evalbench.py --experiment_config=.ci/run_config.yaml']
env: *harness_env
volumes: *results_volume

- id: verify-harnesses
name: 'evalbench-harness-ci'
dir: '/evalbench'
waitFor: ['agy-cli', 'claude-code', 'codex-cli', 'gemini-cli']
args: ['uv', 'run', '--no-sync', 'python3', '.ci/verify_harness.py']
volumes: *results_volume

timeout: '3600s'

options:
logging: CLOUD_LOGGING_ONLY
# Sized for the four concurrent harness steps, not for the build.
machineType: 'E2_HIGHCPU_8'
31 changes: 31 additions & 0 deletions .ci/harness_smoke.evalset.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"scenarios": [
{
"id": "ci-csql-list-and-get",
"starting_prompt": "list all instances in project ${EVAL_GCP_PROJECT_ID}",
"conversation_plan": "The user wants to see every Cloud SQL instance in project ${EVAL_GCP_PROJECT_ID}, then check the health of one of them. Once the agent has listed the instances, the user asks for the current state of ${CI_CSQL_INSTANCE} and expects the agent to report whether it is RUNNABLE. The user accepts that answer and ends the conversation.",
"expected_trajectory": [
"cloud-sql__list_instances",
"cloud-sql__get_instance"
],
"env": {
"GOOGLE_CLOUD_PROJECT": "${EVAL_GCP_PROJECT_ID}"
},
"kind": "tools",
"max_turns": 3
Comment thread
omkargaikwad23 marked this conversation as resolved.
Outdated
},
{
"id": "ci-csql-get-instance-not-found",
"starting_prompt": "Get the details for the Cloud SQL instance named 'ci-missing-instance-do-not-create' in project '${EVAL_GCP_PROJECT_ID}'.",
"conversation_plan": "The user wants details for an instance that does not exist. The agent should call get_instance once, receive a not-found error, and report to the user that the instance could not be found. The user accepts that answer and ends the conversation. The user must not ask the agent to list instances, search for similar names, or otherwise recover.",
"expected_trajectory": [
"cloud-sql__get_instance"
],
"env": {
"GOOGLE_CLOUD_PROJECT": "${EVAL_GCP_PROJECT_ID}"
},
"kind": "tools",
"max_turns": 2
}
]
}
20 changes: 20 additions & 0 deletions .ci/model_configs/agy_cli_model.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
generator: agy_cli
# ADC does not authorize the Pro (High) tier.
model: "Gemini 3.1 Pro (Low)"
timeout: "20m"

env:
GOOGLE_CLOUD_PROJECT: !ENV ${EVAL_GCP_PROJECT_ID}
GOOGLE_CLOUD_LOCATION: "global"
GOOGLE_GENAI_USE_VERTEXAI: "true"

setup:
mcp_servers:
"cloud-sql":
httpUrl: "https://sqladmin.googleapis.com/mcp"
authProviderType: google_credentials
oauth:
scopes:
- https://www.googleapis.com/auth/cloud-platform
headers:
X-Goog-User-Project: !ENV ${EVAL_GCP_PROJECT_ID}
23 changes: 23 additions & 0 deletions .ci/model_configs/claude_code_model.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
claude_code_version: "@anthropic-ai/claude-code@2.1.85"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check against latest

generator: claude_code
model: "claude-opus-4-6"
Comment thread
omkargaikwad23 marked this conversation as resolved.
Outdated

use_vertex: true
vertex_project_id: !ENV ${EVAL_GCP_PROJECT_ID}
# Not us-central1: Vertex serves Claude from only a few regions.
vertex_region: "us-east5"

env:
GOOGLE_CLOUD_PROJECT: !ENV ${EVAL_GCP_PROJECT_ID}
GOOGLE_CLOUD_LOCATION: "us-central1"

setup:
mcp_servers:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should test for skills as well

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would be covered in followup CL (I have already added a note in PR description)

"cloud-sql":
httpUrl: "https://sqladmin.googleapis.com/mcp"
authProviderType: google_credentials
oauth:
scopes:
- https://www.googleapis.com/auth/cloud-platform
headers:
X-Goog-User-Project: !ENV ${EVAL_GCP_PROJECT_ID}
23 changes: 23 additions & 0 deletions .ci/model_configs/codex_cli_model.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
codex_cli_version: "@openai/codex@latest"
generator: codex_cli
model: "gpt-5.5"

openai_api_key_secret: !ENV projects/${EVAL_GCP_PROJECT_ID}/secrets/openai-api-key/versions/2

# Codex reports token counts but no cost; these rates turn them into cost_usd.
pricing:
input_per_million_usd: 1.25
cached_input_per_million_usd: 0.125
output_per_million_usd: 10.0

env:
GOOGLE_CLOUD_PROJECT: !ENV ${EVAL_GCP_PROJECT_ID}
GOOGLE_CLOUD_LOCATION: "us-central1"

setup:
mcp_servers:
"cloud-sql":
httpUrl: "https://sqladmin.googleapis.com/mcp"
authProviderType: google_credentials
headers:
X-Goog-User-Project: !ENV ${EVAL_GCP_PROJECT_ID}
19 changes: 19 additions & 0 deletions .ci/model_configs/gemini_cli_model.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
gemini_cli_version: "@google/gemini-cli@0.55.1"
Comment thread
omkargaikwad23 marked this conversation as resolved.
Outdated
generator: gemini_cli

env:
GOOGLE_CLOUD_PROJECT: !ENV ${EVAL_GCP_PROJECT_ID}
GOOGLE_CLOUD_LOCATION: "global"
GOOGLE_GENAI_USE_VERTEXAI: "true"
GEMINI_CLI_TRUST_WORKSPACE: "true"

setup:
mcp_servers:
"cloud-sql":
httpUrl: "https://sqladmin.googleapis.com/mcp"
authProviderType: google_credentials
oauth:
scopes:
- https://www.googleapis.com/auth/cloud-platform
headers:
X-Goog-User-Project: !ENV ${EVAL_GCP_PROJECT_ID}
28 changes: 28 additions & 0 deletions .ci/run_config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Shared by all four harnesses. CI_HARNESS selects which one runs, so every
# harness is scored identically and stays comparable.
dataset_config: .ci/harness_smoke.evalset.json
dataset_format: agent-format

orchestrator: agent
model_config: !ENV .ci/model_configs/${CI_HARNESS}_model.yaml
simulated_user_model_config: datasets/model_configs/gemini_3.1_pro_model.yaml

scorers:
trajectory_matcher: {}
turn_count: {}
agent_steps: {}
end_to_end_latency: {}
tool_call_latency: {}
token_consumption: {}
tokens_processed: {}
effective_billed_tokens: {}
goal_completion:
model_config: datasets/model_configs/gemini_3.1_pro_model.yaml
behavioral_metrics:
model_config: datasets/model_configs/gemini_3.1_pro_model.yaml
parameter_analysis:
model_config: datasets/model_configs/gemini_3.1_pro_model.yaml

reporting:
csv:
output_directory: !ENV results/ci/${CI_HARNESS}
Loading
Loading