-
Notifications
You must be signed in to change notification settings - Fork 1
API Reference
Complete reference for all SQL Query Engine endpoints. The engine exposes two API surfaces: native inference routes (/inference/*) for direct pipeline control, and OpenAI-compatible routes (/v1/*) for integration with standard tooling.
| Deployment | Base URL |
|---|---|
| Docker Compose | http://localhost:5181 |
| Local development | http://localhost:8080 |
Returns server status and request metadata. No authentication required.
Response:
{
"code": 200,
"status": "[ SQL Query Engine ]: Agent is alive and reachable.",
"agent": "sqlQueryEngine",
"scheme": "http",
"host": "localhost",
"port": "5181",
"clientHost": "172.18.0.1",
"clientPort": 54321
}These endpoints provide direct control over the two-stage pipeline. They accept optional query parameters to override connection settings (see Configuration).
Runs the full pipeline: Stage 1 (NL β SQL generation) + Stage 2 (execution + repair loop).
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
chatID |
string | Session identifier. Namespaces all Redis context for this conversation. |
Request Body:
{
"basePrompt": "How many orders were placed in the last 30 days?",
"retryCount": 5,
"schemaExamples": 5,
"feedbackExamples": 3,
"schemaDescriptionKey": "dbSchemaDescription",
"extraPayload": {"source": "api-call"}
}| Field | Type | Required | Default | Description |
|---|---|---|---|---|
basePrompt |
string | Yes | β | Natural language question |
retryCount |
int | No | 5 |
Max repair loop iterations |
schemaExamples |
int | No | 5 |
Sample rows per table for schema introspection |
feedbackExamples |
int | No | 3 |
Result rows fed back to LLM during evaluation |
schemaDescriptionKey |
string | No | "dbSchemaDescription" |
Redis key for cached schema. Change to force regeneration. |
extraPayload |
object | No | null |
Passed through untouched in the response |
Success Response (200):
{
"code": 200,
"status": "[ test-session-001 | SQL Query Engine ]: Inference executed successfully.",
"chatID": "test-session-001",
"agentResponse": {
"generation": {
"queryDescription": "Count the number of orders placed in the last 30 days",
"sqlQuery": "SELECT COUNT(*) AS order_count FROM orders WHERE created_at >= NOW() - INTERVAL '30 days'"
},
"evaluation": {
"currentQuery": "SELECT COUNT(*) AS order_count FROM orders WHERE created_at >= NOW() - INTERVAL '30 days'",
"currentObservation": "Query executed successfully and returned 1 rows.",
"results": [{"order_count": 842}]
}
},
"extraPayload": {"source": "api-call"}
}Error Response (500):
{
"code": 500,
"status": "[ SQL Query Engine ]: SQL generation failed: Connection refused",
"error": "SQL generation failed: Connection refused"
}Runs Stage 1 only: generates SQL from natural language without executing it.
Request Body:
{
"basePrompt": "List all active users who signed up this year.",
"schemaExamples": 5,
"schemaDescriptionKey": "dbSchemaDescription",
"extraPayload": null
}| Field | Type | Required | Default | Description |
|---|---|---|---|---|
basePrompt |
string | Yes | β | Natural language question |
schemaExamples |
int | No | 5 |
Sample rows per table |
schemaDescriptionKey |
string | No | "dbSchemaDescription" |
Redis key for cached schema |
extraPayload |
object | No | null |
Passthrough payload |
Success Response (200):
{
"code": 200,
"status": "[ test-session-001 | SQL Generation ]: Generation executed successfully.",
"chatID": "test-session-001",
"agentResponse": {
"generation": {
"queryDescription": "List all users with active status who registered in the current year",
"sqlQuery": "SELECT * FROM users WHERE status = 'active' AND EXTRACT(YEAR FROM created_at) = EXTRACT(YEAR FROM NOW())"
}
},
"extraPayload": null
}Runs Stage 2 only: executes a provided SQL query and repairs it if it fails.
Request Body:
{
"basePrompt": "How many orders were placed in the last 30 days?",
"baseQuery": "SELECT COUNT(*) FROM orders WHERE created_at >= NOW() - INTERVAL '30 days'",
"baseDescription": "Count orders placed in the last 30 days.",
"retryCount": 3,
"schemaExamples": 5,
"feedbackExamples": 3,
"schemaDescriptionKey": "dbSchemaDescription",
"extraPayload": null
}| Field | Type | Required | Default | Description |
|---|---|---|---|---|
basePrompt |
string | Yes | β | Original natural language question |
baseQuery |
string | Yes | β | SQL query to execute and evaluate |
baseDescription |
string | Yes | β | Plain-English description of the query |
retryCount |
int | No | 5 |
Max repair iterations |
schemaExamples |
int | No | 5 |
Sample rows per table |
feedbackExamples |
int | No | 3 |
Result rows fed back to LLM |
schemaDescriptionKey |
string | No | "dbSchemaDescription" |
Redis key for schema |
extraPayload |
object | No | null |
Passthrough payload |
Success Response (200):
{
"code": 200,
"status": "[ test-session-001 | SQL Evaluation ]: Evaluation executed successfully.",
"chatID": "test-session-001",
"agentResponse": {
"evaluation": {
"currentQuery": "SELECT COUNT(*) AS order_count FROM orders WHERE created_at >= NOW() - INTERVAL '30 days'",
"currentObservation": "Query executed successfully and returned 1 rows.",
"results": [{"order_count": 842}]
}
},
"extraPayload": null
}These endpoints implement the OpenAI API specification, allowing the engine to be used as a drop-in backend for OpenAI SDKs, LangChain, OpenWebUI, and any other OpenAI-compatible client.
All /v1/* endpoints require a Bearer token when OPENAI_API_KEY is set.
Lists available models.
Headers:
Authorization: Bearer your-api-key
Response:
{
"object": "list",
"data": [
{
"id": "SQLBot",
"object": "model",
"created": 1700000000,
"owned_by": "sql-query-engine"
}
]
}The model name is controlled by the COMPLETIONS_MODEL_NAME environment variable (defaults to the value of BOT_NAME, falling back to SQLBot).
OpenAI-compatible chat completion. Supports both streaming (SSE) and non-streaming modes.
Headers:
Content-Type: application/json
Authorization: Bearer your-api-key
Request Body:
{
"model": "SQLBot",
"messages": [
{"role": "user", "content": "How many orders were placed last month?"}
],
"stream": true,
"chat_id": "my-session-001"
}| Field | Type | Required | Default | Description |
|---|---|---|---|---|
model |
string | Yes | β | Model identifier (ignored β the engine always uses the configured pipeline) |
messages |
array | Yes | β | Array of {role, content} message objects. The last user message is used as the SQL prompt. |
stream |
bool | No | true |
Enable SSE streaming |
chat_id |
string | No | MD5 of first user message | Session ID for context preservation. Provided automatically by OpenWebUI. |
temperature |
float | No | β | Ignored β temperature is set via the LLM_TEMPERATURE env var |
max_tokens |
int | No | β | Ignored β not applicable to the SQL engine |
Non-Streaming Response:
{
"id": "chatcmpl-abc123",
"object": "chat.completion",
"created": 1700000000,
"model": "SQLBot",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "<think>\n...pipeline progress...\n</think>\n\n**Query plan:** Count orders...\n\n```sql\nSELECT COUNT(*)...\n```\n\n**Results** β 1 row(s) returned:\n\n| order_count |\n| --- |\n| 842 |"
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 0,
"completion_tokens": 0,
"total_tokens": 0
}
}Streaming Response (SSE):
data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]}
data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"<think>\n"},"finish_reason":null}]}
data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"Analyzing schema..."},"finish_reason":null}]}
...
data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"\n</think>\n\n"},"finish_reason":null}]}
data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"**Query plan:** ..."},"finish_reason":null}]}
data: [DONE]
Progress messages from the pipeline are wrapped in <think>...</think> tags, which OpenWebUI renders as a collapsible "thinking" section.
Legacy text completions endpoint. Each request gets a fresh chatID (UUID-based).
Request Body:
{
"model": "SQLBot",
"prompt": "How many users signed up in the last 7 days?",
"stream": false
}Non-Streaming Response:
{
"id": "cmpl-abc123",
"object": "text_completion",
"created": 1700000000,
"model": "SQLBot",
"choices": [
{
"text": "<think>\n...pipeline progress...\n</think>\n\n**Query plan:** ...",
"index": 0,
"logprobs": null,
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 0,
"completion_tokens": 0,
"total_tokens": 0
}
}The engine auto-generates an OpenAPI specification:
| URL | Description |
|---|---|
/docs |
Swagger UI (interactive API explorer) |
/openapi.json |
Raw OpenAPI JSON schema |
# Download the schema
curl -s http://localhost:5181/openapi.json | jq .
# Open Swagger UI in browser
open http://localhost:5181/docs{
"code": 500,
"status": "[ SQL Query Engine ]: SQL generation failed: Connection refused",
"error": "SQL generation failed: Connection refused"
}401 β Invalid API key:
{
"detail": {
"error": {
"message": "Invalid API key. Provide a valid key in 'Authorization: Bearer <key>'.",
"type": "invalid_request_error",
"param": null,
"code": "invalid_api_key"
}
}
}500 β Missing configuration:
{
"detail": {
"error": {
"message": "Required environment variables not configured: LLM_BASE_URL, LLM_MODEL. Set them in docker-compose.yml or the host environment.",
"type": "server_error",
"code": "missing_configuration"
}
}
}Common error codes:
| Code | Cause |
|---|---|
| 401 | Missing or invalid Bearer token on /v1/* routes |
| 422 | Validation error (missing required fields, wrong types) |
| 500 | Internal error (LLM connection failed, database unreachable, Redis timeout, missing env vars) |
π Paper: arXiv:2604.16511 | π Dataset: Hugging Face | π» Source: GitHub
SQL Query Engine
Design
Setup
API
Internals
Evaluation
Help