2025-10-18 17:35:29 -04:00
#!/bin/bash
2025-12-19 15:02:06 +11:00
# Test providers with optional code_execution mode
# Usage:
# ./test_providers.sh # Normal mode (direct tool calls)
# ./test_providers.sh --code-exec # Code execution mode (JS batching)
2026-01-28 13:30:26 -05:00
#
# Environment variables:
# SKIP_PROVIDERS Comma-separated list of providers to skip (e.g., "tetrate,xai")
# SKIP_BUILD Skip the cargo build step if set
2025-12-19 15:02:06 +11:00
CODE_EXEC_MODE = false
for arg in " $@ " ; do
case $arg in
--code-exec)
CODE_EXEC_MODE = true
; ;
esac
done
2026-01-22 16:10:41 -08:00
# Flaky models that are allowed to fail without failing the entire test run.
# These are typically preview/experimental models with inconsistent tool-calling behavior.
# Failures are still reported but don't block PRs.
ALLOWED_FAILURES = (
"google:gemini-3-pro-preview"
"openrouter:nvidia/nemotron-3-nano-30b-a3b"
)
2025-10-18 17:35:29 -04:00
if [ -f .env ] ; then
export $( grep -v '^#' .env | xargs)
fi
2025-10-21 16:39:58 +11:00
if [ -z " $SKIP_BUILD " ] ; then
echo "Building goose..."
cargo build --release --bin goose
echo ""
else
echo "Skipping build (SKIP_BUILD is set)..."
echo ""
fi
2025-10-18 17:35:29 -04:00
SCRIPT_DIR = $( pwd )
2025-12-31 09:48:05 +11:00
# Format: "provider -> model1|model2|model3"
2026-02-03 11:21:59 -05:00
# Base providers that are always tested (with appropriate env vars)
2025-10-18 17:35:29 -04:00
PROVIDERS = (
2025-12-31 09:48:05 +11:00
"openrouter -> google/gemini-2.5-pro|anthropic/claude-sonnet-4.5|qwen/qwen3-coder:exacto|z-ai/glm-4.6:exacto|nvidia/nemotron-3-nano-30b-a3b"
"xai -> grok-3"
"openai -> gpt-4o|gpt-4o-mini|gpt-3.5-turbo|gpt-5"
"anthropic -> claude-sonnet-4-5-20250929|claude-opus-4-1-20250805"
"google -> gemini-2.5-pro|gemini-2.5-flash|gemini-3-pro-preview|gemini-3-flash-preview"
"tetrate -> claude-sonnet-4-20250514"
2025-10-18 17:35:29 -04:00
)
2026-02-03 11:21:59 -05:00
# Conditionally add providers based on environment variables
# Databricks: requires DATABRICKS_HOST and DATABRICKS_TOKEN
if [ -n " $DATABRICKS_HOST " ] && [ -n " $DATABRICKS_TOKEN " ] ; then
2025-10-21 16:39:58 +11:00
echo "✓ Including Databricks tests"
2025-12-31 09:48:05 +11:00
PROVIDERS += ( "databricks -> databricks-claude-sonnet-4|gemini-2-5-flash|gpt-4o" )
2026-02-03 11:21:59 -05:00
else
echo "⚠️ Skipping Databricks tests (DATABRICKS_HOST and DATABRICKS_TOKEN required)"
fi
# Azure OpenAI: requires AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_DEPLOYMENT_NAME
if [ -n " $AZURE_OPENAI_ENDPOINT " ] && [ -n " $AZURE_OPENAI_DEPLOYMENT_NAME " ] ; then
echo "✓ Including Azure OpenAI tests"
PROVIDERS += ( " azure_openai -> ${ AZURE_OPENAI_DEPLOYMENT_NAME } " )
else
echo "⚠️ Skipping Azure OpenAI tests (AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_DEPLOYMENT_NAME required)"
fi
# AWS Bedrock: requires AWS credentials (profile or keys) and AWS_REGION
if [ -n " $AWS_REGION " ] && { [ -n " $AWS_PROFILE " ] || [ -n " $AWS_ACCESS_KEY_ID " ] ; } ; then
echo "✓ Including AWS Bedrock tests"
PROVIDERS += ( "aws_bedrock -> us.anthropic.claude-sonnet-4-5-20250929-v1:0" )
else
echo "⚠️ Skipping AWS Bedrock tests (AWS_REGION and AWS_PROFILE or AWS credentials required)"
fi
# GCP Vertex AI: requires GCP_PROJECT_ID
if [ -n " $GCP_PROJECT_ID " ] ; then
echo "✓ Including GCP Vertex AI tests"
PROVIDERS += ( "gcp_vertex_ai -> gemini-2.5-pro" )
else
echo "⚠️ Skipping GCP Vertex AI tests (GCP_PROJECT_ID required)"
fi
# Snowflake: requires SNOWFLAKE_HOST and SNOWFLAKE_TOKEN
if [ -n " $SNOWFLAKE_HOST " ] && [ -n " $SNOWFLAKE_TOKEN " ] ; then
echo "✓ Including Snowflake tests"
PROVIDERS += ( "snowflake -> claude-sonnet-4-5" )
else
echo "⚠️ Skipping Snowflake tests (SNOWFLAKE_HOST and SNOWFLAKE_TOKEN required)"
fi
# Venice: requires VENICE_API_KEY
if [ -n " $VENICE_API_KEY " ] ; then
echo "✓ Including Venice tests"
PROVIDERS += ( "venice -> llama-3.3-70b" )
else
echo "⚠️ Skipping Venice tests (VENICE_API_KEY required)"
fi
# LiteLLM: requires LITELLM_API_KEY (and optionally LITELLM_HOST)
if [ -n " $LITELLM_API_KEY " ] ; then
echo "✓ Including LiteLLM tests"
PROVIDERS += ( "litellm -> gpt-4o-mini" )
else
echo "⚠️ Skipping LiteLLM tests (LITELLM_API_KEY required)"
fi
# Ollama: requires OLLAMA_HOST (or uses default localhost:11434)
if [ -n " $OLLAMA_HOST " ] || command -v ollama & > /dev/null; then
echo "✓ Including Ollama tests"
PROVIDERS += ( "ollama -> qwen3" )
else
echo "⚠️ Skipping Ollama tests (OLLAMA_HOST required or ollama must be installed)"
fi
# SageMaker TGI: requires AWS credentials and SAGEMAKER_ENDPOINT_NAME
if [ -n " $SAGEMAKER_ENDPOINT_NAME " ] && [ -n " $AWS_REGION " ] ; then
echo "✓ Including SageMaker TGI tests"
PROVIDERS += ( "sagemaker_tgi -> sagemaker-tgi-endpoint" )
else
echo "⚠️ Skipping SageMaker TGI tests (SAGEMAKER_ENDPOINT_NAME and AWS_REGION required)"
fi
# GitHub Copilot: requires OAuth setup (check for cached token)
if [ -n " $GITHUB_COPILOT_TOKEN " ] || [ -f " $HOME /.config/goose/github_copilot_token.json " ] ; then
echo "✓ Including GitHub Copilot tests"
PROVIDERS += ( "github_copilot -> gpt-4.1" )
else
echo "⚠️ Skipping GitHub Copilot tests (OAuth setup required - run 'goose configure' first)"
2025-10-21 16:39:58 +11:00
fi
2026-02-03 11:21:59 -05:00
# ChatGPT Codex: requires OAuth setup
if [ -n " $CHATGPT_CODEX_TOKEN " ] || [ -f " $HOME /.config/goose/chatgpt_codex_token.json " ] ; then
echo "✓ Including ChatGPT Codex tests"
PROVIDERS += ( "chatgpt_codex -> gpt-5.1-codex" )
else
echo "⚠️ Skipping ChatGPT Codex tests (OAuth setup required - run 'goose configure' first)"
fi
# CLI-based providers (require the CLI tool to be installed)
# Claude Code CLI: requires 'claude' CLI tool
if command -v claude & > /dev/null; then
echo "✓ Including Claude Code CLI tests"
PROVIDERS += ( "claude-code -> claude-sonnet-4-20250514" )
else
echo "⚠️ Skipping Claude Code CLI tests ('claude' CLI tool required)"
fi
# Codex CLI: requires 'codex' CLI tool
if command -v codex & > /dev/null; then
echo "✓ Including Codex CLI tests"
PROVIDERS += ( "codex -> gpt-5.2-codex" )
else
echo "⚠️ Skipping Codex CLI tests ('codex' CLI tool required)"
fi
# Gemini CLI: requires 'gemini' CLI tool
if command -v gemini & > /dev/null; then
echo "✓ Including Gemini CLI tests"
PROVIDERS += ( "gemini-cli -> gemini-2.5-pro" )
else
echo "⚠️ Skipping Gemini CLI tests ('gemini' CLI tool required)"
fi
# Cursor Agent: requires 'cursor-agent' CLI tool
if command -v cursor-agent & > /dev/null; then
echo "✓ Including Cursor Agent tests"
PROVIDERS += ( "cursor-agent -> auto" )
else
echo "⚠️ Skipping Cursor Agent tests ('cursor-agent' CLI tool required)"
fi
echo ""
2025-12-19 15:02:06 +11:00
# Configure mode-specific settings
if [ " $CODE_EXEC_MODE " = true ] ; then
echo "Mode: code_execution (JS batching)"
BUILTINS = "developer,code_execution"
2025-12-22 10:42:20 -05:00
# Match code_execution tool usage:
2026-02-03 12:15:49 -05:00
# - "execute | code_execution" or "get_function_details | code_execution" (fallback format)
# - "tool call | execute" or "tool calls | execute" (new format with tool_graph)
SUCCESS_PATTERN = "(execute \| code_execution)|(get_function_details \| code_execution)|(tool calls? \| execute)"
2025-12-19 15:02:06 +11:00
SUCCESS_MSG = "code_execution tool called"
FAILURE_MSG = "no code_execution tools called"
else
echo "Mode: normal (direct tool calls)"
BUILTINS = "developer,autovisualiser,computercontroller,tutorial,todo,extensionmanager"
SUCCESS_PATTERN = "shell \| developer"
SUCCESS_MSG = "developer tool called"
FAILURE_MSG = "no developer tools called"
fi
echo ""
2026-01-22 16:10:41 -08:00
is_allowed_failure( ) {
local provider = " $1 "
local model = " $2 "
local key = " ${ provider } : ${ model } "
for allowed in " ${ ALLOWED_FAILURES [@] } " ; do
if [ " $allowed " = " $key " ] ; then
return 0
fi
done
return 1
}
2026-01-28 13:30:26 -05:00
should_skip_provider( ) {
local provider = " $1 "
if [ -z " $SKIP_PROVIDERS " ] ; then
return 1
fi
IFS = ',' read -ra SKIP_LIST <<< " $SKIP_PROVIDERS "
for skip in " ${ SKIP_LIST [@] } " ; do
# Trim whitespace
skip = $( echo " $skip " | xargs)
if [ " $skip " = " $provider " ] ; then
return 0
fi
done
return 1
}
2026-02-03 11:21:59 -05:00
# Create temp directory for results
RESULTS_DIR = $( mktemp -d)
trap " rm -rf $RESULTS_DIR " EXIT
# Maximum parallel jobs (default: number of CPU cores, or override with MAX_PARALLEL)
MAX_PARALLEL = ${ MAX_PARALLEL :- $( sysctl -n hw.ncpu 2>/dev/null || nproc 2>/dev/null || echo 8) }
echo " Running tests with up to $MAX_PARALLEL parallel jobs "
echo ""
# Function to run a single test
run_test( ) {
local provider = " $1 "
local model = " $2 "
local result_file = " $3 "
local output_file = " $4 "
2025-10-18 17:35:29 -04:00
2026-02-03 11:21:59 -05:00
local testdir = $( mktemp -d)
echo "hello" > " $testdir /hello.txt "
# Run the test and capture output
(
export GOOSE_PROVIDER = " $provider "
export GOOSE_MODEL = " $model "
cd " $testdir " && " $SCRIPT_DIR /target/release/goose " run --text "Immediately use the shell tool to run 'ls'. Do not ask for confirmation." --with-builtin " $BUILTINS " 2>& 1
) > " $output_file " 2>& 1
# Check result
if grep -qE " $SUCCESS_PATTERN " " $output_file " ; then
echo "success" > " $result_file "
else
echo "failure" > " $result_file "
fi
rm -rf " $testdir "
}
# Build list of all provider/model combinations
JOBS = ( )
job_index = 0
2025-10-18 17:35:29 -04:00
for provider_config in " ${ PROVIDERS [@] } " ; do
2025-12-31 09:48:05 +11:00
PROVIDER = " ${ provider_config %% -> * } "
MODELS_STR = " ${ provider_config #* -> } "
2026-01-28 13:30:26 -05:00
# Skip provider if it's in SKIP_PROVIDERS
if should_skip_provider " $PROVIDER " ; then
echo " ⊘ Skipping provider: ${ PROVIDER } (SKIP_PROVIDERS) "
continue
fi
2025-12-31 09:48:05 +11:00
IFS = '|' read -ra MODELS <<< " $MODELS_STR "
for MODEL in " ${ MODELS [@] } " ; do
2026-02-03 11:21:59 -05:00
JOBS += ( " $PROVIDER | $MODEL | $job_index " )
( ( job_index++) )
done
done
total_jobs = ${# JOBS [@] }
echo " Starting $total_jobs tests... "
echo ""
# Run first test sequentially if any jobs exist
if [ $total_jobs -gt 0 ] ; then
echo "Running first test sequentially..."
first_job = " ${ JOBS [0] } "
IFS = '|' read -r provider model idx <<< " $first_job "
result_file = " $RESULTS_DIR /result_ $idx "
output_file = " $RESULTS_DIR /output_ $idx "
meta_file = " $RESULTS_DIR /meta_ $idx "
echo " $provider | $model " > " $meta_file "
# Run first test and wait for it to complete
run_test " $provider " " $model " " $result_file " " $output_file "
echo "First test completed."
echo ""
fi
# Run remaining tests in parallel
if [ $total_jobs -gt 1 ] ; then
echo "Running remaining tests in parallel..."
running_jobs = 0
for ( ( i = 1; i<$total_jobs ; i++) ) ; do
job = " ${ JOBS [ $i ] } "
IFS = '|' read -r provider model idx <<< " $job "
result_file = " $RESULTS_DIR /result_ $idx "
output_file = " $RESULTS_DIR /output_ $idx "
meta_file = " $RESULTS_DIR /meta_ $idx "
echo " $provider | $model " > " $meta_file "
# Run test in background
run_test " $provider " " $model " " $result_file " " $output_file " &
( ( running_jobs++) )
# Wait if we've hit the parallel limit
if [ $running_jobs -ge $MAX_PARALLEL ] ; then
wait -n 2>/dev/null || wait
( ( running_jobs--) )
2025-10-18 17:35:29 -04:00
fi
done
2026-02-03 11:21:59 -05:00
# Wait for all remaining jobs
wait
fi
echo ""
echo "=== Test Results ==="
echo ""
# Collect results
RESULTS = ( )
HARD_FAILURES = ( )
for job in " ${ JOBS [@] } " ; do
IFS = '|' read -r provider model idx <<< " $job "
result_file = " $RESULTS_DIR /result_ $idx "
output_file = " $RESULTS_DIR /output_ $idx "
echo " Provider: $provider "
echo " Model: $model "
echo ""
cat " $output_file "
echo ""
if [ -f " $result_file " ] && [ " $( cat " $result_file " ) " = "success" ] ; then
echo " ✓ SUCCESS: Test passed - $SUCCESS_MSG "
RESULTS += ( " ✓ ${ provider } : ${ model } " )
else
if is_allowed_failure " $provider " " $model " ; then
echo " ⚠ FLAKY: Test failed but model is in allowed failures list - $FAILURE_MSG "
RESULTS += ( " ⚠ ${ provider } : ${ model } (flaky) " )
else
echo " ✗ FAILED: Test failed - $FAILURE_MSG "
RESULTS += ( " ✗ ${ provider } : ${ model } " )
HARD_FAILURES += ( " ${ provider } : ${ model } " )
fi
fi
echo "---"
2025-10-18 17:35:29 -04:00
done
2026-02-03 11:21:59 -05:00
2025-10-18 17:35:29 -04:00
echo ""
echo "=== Test Summary ==="
for result in " ${ RESULTS [@] } " ; do
echo " $result "
done
2026-01-22 16:10:41 -08:00
if [ ${# HARD_FAILURES [@] } -gt 0 ] ; then
echo ""
echo " Hard failures ( ${# HARD_FAILURES [@] } ): "
for failure in " ${ HARD_FAILURES [@] } " ; do
echo " - $failure "
done
2025-10-18 17:35:29 -04:00
echo ""
echo "Some tests failed!"
exit 1
else
2026-01-22 16:10:41 -08:00
if echo " ${ RESULTS [@] } " | grep -q "⚠" ; then
echo ""
echo "All required tests passed! (some flaky tests failed but are allowed)"
else
echo ""
echo "All tests passed!"
fi
2025-10-18 17:35:29 -04:00
fi