V2 API Migration Guide#
This guide helps you migrate from the v1 to v2 Evaluator API.
Note
Migration Timeline: The v1 API will remain fully supported during the v2 transition period. You can migrate at your own pace.
Warning
v2 API Preview: The v2 API is available for testing and feedback but is not yet recommended for production use. Breaking changes may occur before the stable release.
Breaking Changes Summary#
Removed Endpoints#
The following v1 endpoints have been removed in v2. Their functionality has been consolidated into other endpoints:
v1 Endpoint |
v2 Replacement |
Notes |
---|---|---|
|
|
Status details included in job details response or |
Changed Endpoints#
v1 Endpoint |
v2 Endpoint |
Breaking Changes |
---|---|---|
|
|
Major: Returns JSON with pagination instead of ZIP file |
|
|
New path structure and downloads a gzip instead of a zip artifact. |
|
|
New path structure |
Request Format Changes#
Job Creation#
The most significant change is in job creation, which now requires additional fields and uses a spec
envelope.
{
"namespace": "my-organization",
"target": "my-organization/my-target",
"config": "my-organization/my-config"
}
Example job with in-line target and config (secrets supported).
{
// New required envelope
"spec": {
"target": {
// example target definition
"type": "model",
"model": {}
},
"config": {
// example config definition
"type": "custom",
"params": {}
}
}
}
Example job referencing config and target created with v1 API. Secrets are not supported, see the following V2 Secrets section.
{
// New required envelope
"spec": {
"target": "my-organization/my-target",
"config": "my-organization/my-config"
}
}
Key Changes:#
Spec envelope: Target and config must be wrapped in a required
spec
objectEndpoint URL: Use
/v2/evaluation/jobs
instead of/v1/evaluation/jobs
V2 Secrets#
Jobs created with the v2 API cannot use configuration or targets from the v1 API containing API keys. This will result in missing secrets and the job may fail if the secrets are needed.
To securely use API keys for jobs with the v2 API, the secrets must be defined in-line with the job definition.
{
"spec": {
"target": {
"type": "model",
"model": {
// API key is supported
}
},
"config": {
"type": "custom",
"params": {
// API keys are supported
}
}
}
}
Response Format Changes#
Job Status Consolidation#
Multiple endpoints for status information
GET /v1/evaluation/jobs/{id}
- Basic job infoGET /v1/evaluation/jobs/{id}/status
- Status onlyGET /v1/evaluation/jobs/{id}/status-details
- Detailed status
# v1 - Multiple API calls needed
job = client.evaluation.jobs.retrieve(job_id)
status = client.evaluation.jobs.get_status(job_id)
status_details = client.evaluation.jobs.get_status_details(job_id)
Single consolidated endpoint
GET /v2/evaluation/jobs/{id}
- All information including status and status_details
# v2 - Single API call
job = client.evaluation.jobs.retrieve(job_id)
# job.status and job.status_details are included
Log Format Changes#
This is the most significant breaking change in v2.
ZIP file download
curl "${EVALUATOR_BASE_URL}/v1/evaluation/jobs/{id}/logs" -o logs.zip
unzip logs.zip
cat logs/job.log
JSON response with pagination
curl "${EVALUATOR_BASE_URL}/v2/evaluation/jobs/{id}/logs" | jq -r '.data[].message'
v2 Response Format:
{
"data": [
{
"id": 4362,
"job_id": "job-dq1pjj6vj5p64xaeqgvuk4",
"job_step": "evaluation",
"job_task": "64976129addc499f88071823fcc48f30",
"message": "Log message here\n",
"timestamp": "2025-09-08T19:20:44.799146"
}
],
"next_page": "cursor",
"prev_page": null,
"total": 373
}
Result Access Changes#
v1 Paths:
Download results:
/v1/evaluation/jobs/{id}/download-results
Get results:
/v1/evaluation/jobs/{id}/results
v2 Paths:
Download artifacts:
/v2/evaluation/jobs/{id}/results/artifacts/download
Get evaluation results:
/v2/evaluation/jobs/{id}/results/evaluation-results/download
List available results:
/v2/evaluation/jobs/{id}/results
Migration Examples#
Job Creation Migration#
job = client.evaluation.jobs.create(
namespace="my-organization",
target="my-organization/my-target",
config="my-organization/my-config"
)
job = client.v2.evaluation.jobs.create(
spec={
"target": "my-organization/my-target",
"config": "my-organization/my-config"
}
)
Status Monitoring Migration#
# Multiple API calls
job = client.evaluation.jobs.retrieve(job_id)
status = client.evaluation.jobs.get_status(job_id)
status_details = client.evaluation.jobs.get_status_details(job_id)
print(f"Status: {status}")
print(f"Details: {status_details}")
# Single API call
job = client.v2.evaluation.jobs.retrieve(job_id)
print(f"Status: {job.status}")
print(f"Details: {job.status_details}")
print(f"Errors: {job.error_details}")
Log Processing Migration#
# Download ZIP file
logs_zip = client.evaluation.jobs.download_logs(job_id)
with open(f"{job_id}_logs.zip", 'wb') as f:
f.write(logs_zip)
# Extract and process
import zipfile
with zipfile.ZipFile(f"{job_id}_logs.zip", 'r') as zip_ref:
zip_ref.extractall("logs")
with open("logs/job.log", 'r') as f:
for line in f:
print(line.strip())
# Get JSON logs with pagination
logs_response = client.v2.evaluation.jobs.logs.list(job_id)
# Process logs directly
for log_entry in logs_response.data:
print(f"[{log_entry.timestamp}] {log_entry.message.strip()}")
# Handle pagination
while logs_response.next_page:
logs_response = client.evaluation.jobs.logs.list(
job_id,
page_cursor=logs_response.next_page
)
for log_entry in logs_response.data:
print(f"[{log_entry.timestamp}] {log_entry.message.strip()}")
Results Download Migration#
# Download results
results_zip = client.evaluation.jobs.download_results(job_id)
with open(f"{job_id}_results.zip", 'wb') as f:
f.write(results_zip)
# List available results
available_results = client.v2.evaluation.jobs.results.list(job_id)
print(f"Available results: {[r.result_name for r in available_results.data]}")
# Download specific result types
artifacts_zip = client.v2.evaluation.jobs.results.artifacts.retrieve(job_id)
artifacts_zip.write_to_file("evaluation_artifacts.tar.gz")
eval_results = client.v2.evaluation.jobs.results.evaluation_results.retrieve(job_id)
with open("evaluation_results.json", "w") as f:
f.write(eval_results.model_dump_json(indent=2, exclude_none=True))