AI Agents API
Base path /api/ai. Every route needs a signed-in user and an active license. Agent runs also follow the administrator's AI settings: with AI agents switched off they answer 403 AGENTS_DISABLED, and with rate limiting on, too many runs answer 429 RATE_LIMITED. Errors are JSON with error (a sentence you can show) and code.
Routes
| Method | Endpoint | Purpose |
|---|---|---|
| GET | /api/ai/agents | The agent ids |
| POST | /api/ai/agents/:id | Run an agent; ?async=true queues it when the async mode allows |
| GET | /api/ai/agents/:id/runs | Run history of one agent |
| GET | /api/ai/agents/jobs | Queued runs |
| GET | /api/ai/agents/jobs/:id | One queued run, with its result |
| DELETE | /api/ai/agents/jobs/:id | Cancel a queued or running job |
| GET | /api/ai/status | Whether a provider is set up |
| GET | /api/ai/providers | The providers you can choose |
| GET | /api/ai/settings | The AI settings |
| PUT | /api/ai/settings | Change the AI settings (admin) |
| POST | /api/ai/nl-to-sql | The IDE's question-to-SQL request |
| POST | /api/ai/chat | The IDE's AI assistant |
| POST | /api/ai/review-script | The AI review on approvals |
Run an agent
POST /api/ai/agents/script-review
{ "input": { "script": "DELETE FROM orders;", "connectionId": "6f1c…" } }
The ids are script-review, nl-to-sql, schema-explorer, error-diagnosis, query-optimization, auto-rollback, change-impact, release-summary, compliance and anomaly-detection. With a connectionId the agent uses that connection's engine; without one, agents that allow it need dialect, one of the engines the server supports.
| Agent | Input |
|---|---|
| script-review | script; connectionId or dialect; optional notes |
| nl-to-sql | prompt, connectionId |
| schema-explorer | connectionId; history: the turns so far, each { "role": "user" | "assistant", "content": "…" }, ending with the user's question |
| error-diagnosis | sql, errorMessage; connectionId or dialect |
| query-optimization | sql (one statement), connectionId |
| auto-rollback | forwardScript, dialect; optional preConditions |
| change-impact | script, connectionId |
| release-summary | releaseId; or releaseName, version and scripts: [{ "name", "script", "environment"? }] |
| compliance | script, dialect; optional environment |
| anomaly-detection | optional scriptId and lookbackCount (1 to 1000, default 200) |
Text fields are limited to 200,000 characters. A missing or invalid field is refused before anything runs:
400 { "ok": false, "error": "dialect is required when no connection is chosen: one of postgresql, mysql, …", "code": "INVALID_AGENT_INPUT" }
A finished run answers 200:
{ "ok": true,
"result": { "riskScore": "high", "summary": "…", "findings": [ … ], "suggestedRollback": null },
"runId": "…", "ms": 2380, "model": "…",
"usage": { "promptTokens": 1240, "completionTokens": 380, "totalTokens": 1620 },
"warnings": [ "1 table is left out of the AI context by an administrator's exclusion list." ],
"cached": false }
model and usage are absent when the agent answered without the AI model. A failed run answers with ok: false, error, code and the status of the cause (see Error codes). Each agent's output is described on its page in the AI Agents guide.
Queued runs
When the administrator's async mode is Always, or it is Opt-in and you add ?async=true, the run is queued:
202 Location: /api/ai/agents/jobs/8c2e…
{ "jobId": "8c2e…", "status": "pending" }
Poll GET /api/ai/agents/jobs/:id until status is success, error or cancelled. The job carries agent, status, input, result, warnings, error_message, run_id, enqueued_at, started_at, finished_at, ms, model and cost_total_tok. GET /api/ai/agents/jobs?limit=50 lists jobs without their input and result. DELETE cancels a job that is pending or running; a job that has finished answers 404 JOB_NOT_FOUND. A job left running for 10 minutes, for example after a restart, is queued again.
Users see and cancel only their own jobs; administrators see all. Someone else's job, or an id that is not a UUID, answers 404 JOB_NOT_FOUND.
Run history
GET /api/ai/agents/script-review/runs?limit=50
{ "runs": [ { "id": "…", "agent": "script-review", "status": "success", "user_email": "dba@example.com",
"model": "…", "input_summary": "dialect=postgresql, 412c, schema=yes", "output_summary": "risk=high, findings=4",
"cost_total_tok": 1820, "ms": 2380, "error_message": null, "created_at": "…" } ] }
limit is 1 to 500, default 50. Besides the ten agents, ide-chat, review-script and blast-radius-narrative have run history. Users see their own runs; administrators see everyone's. Prompts and answers are not stored.
Status and providers
GET /api/ai/status
{ "configured": true, "provider": "anthropic", "model": "…" }
Administrators also get endpoint. GET /api/ai/providers lists each provider's id, label, defaultModel, requiresApiKey and requiresEndpoint.
Settings
GET /api/ai/settings gives other users provider, model, apiKeySet and scriptReviewMode. Administrators also get endpoint, apiVersion, deployment, region, projectId, awsRoleArn, awsAccessKeyIdSet, awsSecretAccessKeySet, awsSessionTokenSet, extraHeaders (names with the value [stored]), maxTokens, temperature, timeoutMs and agents. Keys are never returned.
PUT /api/ai/settings
{ "provider": "anthropic", "apiKey": "…", "model": "…", "temperature": 0.2,
"extraHeaders": { "X-Team": "[stored]", "X-Gateway": "eu-1" },
"agents": { "globalEnabled": true, "schemaDetailLevel": "types", "excludedTables": "hr.salaries, payroll",
"sendRowData": false, "schemaTableCap": 0, "rateLimitEnabled": true, "rateLimitPerMinute": 30,
"cacheEnabled": false, "cacheTtlSeconds": 300, "asyncMode": "opt-in" } }
Send only the fields you change. An empty or missing apiKey, awsAccessKeyId, awsSecretAccessKey or awsSessionToken keeps the stored value; a header sent as [stored] keeps its value and a header left out is removed. Secrets are encrypted before they are stored. This is the only way to change AI settings: the general settings API refuses ai_ and agents_ keys with 400 USE_AI_SETTINGS. Invalid values are refused, naming every problem:
400 { "error": "temperature must be a number from 0 to 2; agents.asyncMode must be off, opt-in, always", "code": "INVALID_AI_SETTINGS" }
| Field | Allowed |
|---|---|
provider | An id from /api/ai/providers, or empty |
endpoint | An http:// or https:// URL, up to 500 characters |
awsRoleArn | An IAM role ARN |
maxTokens / temperature / timeoutMs | 1 to 200,000 / 0 to 2 / 1,000 to 600,000 |
extraHeaders | Up to 20 headers with valid names and values of up to 2,000 characters |
scriptReviewMode | auto or manual |
agents.schemaTableCap / rateLimitPerMinute / cacheTtlSeconds | 0 to 100,000 / 1 to 10,000 / 1 to 86,400 |
agents.schemaDetailLevel / asyncMode | names, types, full / off, opt-in, always |
agents.globalEnabled, rateLimitEnabled, cacheEnabled, sendRowData | true or false |
IDE and approval requests
| Request | Body | Answer |
|---|---|---|
POST /api/ai/nl-to-sql | prompt, connectionId | { "success": true, "content": "SELECT …;", "model", "usage" } |
POST /api/ai/chat | messages: the conversation, last 20 turns used; optional connectionId | { "success": true, "content": "…", "model", "usage" } |
POST /api/ai/review-script | script; optional databaseType (no engine is assumed without it) | { "success": true, "riskScore", "findings", "summary" }; riskScore is low, medium, high or critical. An answer from the model without a usable risk score, or not in the review format, is 502 with success: false and the reason; no risk is guessed |
They follow the same settings as the agents, are recorded in the run history, and answer failures with success: false, error, code and the status below.
Error codes
| Status | Code | Meaning |
|---|---|---|
| 400 | INVALID_AGENT_INPUT | A field is missing or invalid; the message names it |
| 400 | INVALID_AI_SETTINGS | A setting is out of range; the message names each one |
| 400 | USE_AI_SETTINGS | An AI setting was sent to /api/db-devops/settings; use PUT /api/ai/settings |
| 403 | AGENTS_DISABLED | An administrator switched AI agents off |
| 404 | CONNECTION_NOT_FOUND | The connection does not exist |
| 404 | RELEASE_NOT_FOUND | The release does not exist |
| 404 | JOB_NOT_FOUND | No such job for you, or it has already finished (on cancel) |
| 404 | AGENT_NOT_FOUND | No agent, or no run history, with that id |
| 429 | RATE_LIMITED | Too many runs of this agent this minute; the message says how long to wait |
| 503 | AI_NOT_CONFIGURED | No AI provider is set up |
| 502 | CONNECTION_FAILED | The connection could not be opened |
| 502 | SCHEMA_UNREADABLE | The schema or foreign keys could not be read |
| 502 | HISTORY_UNREADABLE | The script run history could not be read |
| 502 | MODEL_ANSWER_UNUSABLE | The AI model's answer was missing something or could not be read; run again |
| 502 | MODEL_ANSWER_CUT_OFF | The AI model's answer stopped at the Max Tokens limit; raise Max Tokens, then run again |
| 502 | AI_REQUEST_FAILED | The AI provider returned an error or did not answer |
| 502 | AGENT_RUN_FAILED | The run failed for another reason; the message says why |
| 500 | JOB_ENQUEUE_FAILED | The run could not be queued |
| 500 | AI_SETTINGS_UNREADABLE / AI_SETTINGS_SAVE_FAILED | The settings store could not be read or written |