Skip to content

Server endpoints

The FastAPI server runs on http://localhost:8000 by default. Interactive docs are available at /docs.


Health

GET /health

Returns the server status and the health of each connected component.

Response

{
  "status": "ok",
  "turingdb": "ok",
  "valkey": "ok"
}

status is "ok" only when all components are healthy. Individual components report "ok" or "down".


Dev — one-time setup

POST /dev/build_vector_index

Builds the vector index from all graph nodes that have a text property.

This endpoint is intended to be called once after TuringDB is loaded with graph data. The index persists inside TuringDB — you do not need to rebuild it on subsequent server restarts.

The build is idempotent: already-computed embedding batches (stored as CSVs in data_dir) are skipped. You can safely re-run it after an interrupted build.

Request body

{
  "graph_name": "reactome",
  "model": "minishlab/potion-base-32M"
}
Field Description
graph_name Name of the TuringDB graph to index
model Embedding model to use (must be in the model registry)

Supported models

Model Dimensions Provider
snowflake-arctic-embed:33m 384 Ollama
all-minilm:22m 384 Ollama
all-minilm:33m 384 Ollama
minishlab/potion-base-8M 256 sentence-transformers
minishlab/potion-base-32M 512 sentence-transformers
minishlab/static-similarity-mrl-multilingual-v1 256 sentence-transformers

Response

{
  "index_name": "reactome_minishlab_potion_base_32M",
  "total_chunks": 48320,
  "batches_total": 48,
  "batches_computed": 12,
  "batches_skipped": 36
}
Field Description
index_name Name of the created TuringDB vector index
total_chunks Total text chunks across all nodes
batches_total Number of embedding batches
batches_computed Batches that required embedding (new work)
batches_skipped Batches loaded from cache (already computed)

Example

curl -X POST http://localhost:8000/dev/build_vector_index \
  -H "Content-Type: application/json" \
  -d '{"graph_name": "reactome", "model": "minishlab/potion-base-32M"}'

The TUI's RAG tab has a "Build index" button that does the same thing.


POST /vector/search

Embeds a query string and returns the top-k most similar nodes from the vector index.

Request body

{
  "query": "ATP synthesis in mitochondria",
  "graph_name": "reactome",
  "model": "minishlab/potion-base-32M",
  "top_k": 5
}
Field Default Description
query Natural language search query
graph_name Graph to search
model Embedding model (must match the model used at build time)
top_k 5 Number of results to return

Response

A JSON array of matching nodes:

[
  {
    "dbId": 12345,
    "displayName": "ATP synthesis coupled to electron transport",
    "text": "..."
  }
]

Chat

GET /chat/bootstrap-anon

Creates an anonymous session cookie (anon_id, 3-day expiry, httponly) and redirects back to the Streamlit app. Called automatically by the app when no cookie is present.

If the cookie is already present but older than 2 hours, the anon ID is rotated and a fresh cookie is set.

POST /chat/message

Enqueues a chat job and returns immediately with HTTP 202 Accepted. The request is processed asynchronously by a background worker pool — use GET /chat/job/{job_id} to poll for the result or GET /chat/job/{job_id}/stream to receive SSE events.

Rate limiting applies when the request carries an x-anon-id header: 20 requests / 10 min and 500 000 tokens / 10 min per user.

Request body

{
  "message": "What pathways involve ATP?",
  "session_id": "optional-uuid"
}
Field Description
message User's message
session_id Existing session ID (omit to start a new session)

Request headers

Header Description
x-anon-id Anonymous user token (set by the app from the anon_id cookie)
x-llm-provider Override LLM provider for this request: ollama or mistral
x-llm-agent-model Override the agent model name
x-llm-router-provider Override the router LLM provider
x-llm-router-model Override the router model name

All x-llm-* headers are optional. When omitted, the server uses the values from its .env configuration.

Response — HTTP 202

{
  "job_id": "uuid",
  "session_id": "uuid",
  "status": "pending"
}
Field Description
job_id ID to pass to the job endpoints below
session_id UUID for this session (pass back on subsequent requests)
status Always "pending" at submission time

GET /chat/job/{job_id}

Poll for the status and result of a queued job.

Response

{
  "job_id": "uuid",
  "status": "done",
  "result": {
    "session_id": "uuid",
    "answer": "...",
    "route_taken": "agent",
    "sources": [...],
    "token_usage": {"input_tokens": 123, "output_tokens": 456}
  }
}

status is one of "pending", "running", "done", or "error". The result field is present only when status is "done"; error (a string) is present only when status is "error". Returns 404 if the job has expired (TTL: 10 minutes).

GET /config

Returns the server's active LLM configuration. Used by the UI to initialise provider and model dropdowns with server-side defaults.

Response

{
  "llm_provider": "ollama",
  "router_provider": "ollama",
  "ollama_agent_model": "qwen2.5:7b",
  "ollama_router_model": "qwen2.5:3b",
  "mistral_agent_model": "mistral-large-latest",
  "mistral_router_model": "mistral-small-latest"
}

GET /chat/job/{job_id}/stream

SSE stream for a job. Emits routing and agent step events in real time, then a final job_done or job_error event.

Event Data When
routing_started {} Router begins classifying the message
routing_done {route, confidence, reasoning} Router finishes
agent_step {iteration, model} Each agent LLM call
tool_call {tool, args} Each tool invocation
tool_result {tool, summary} Tool result (truncated at 200 chars)
job_done Full ChatResponse JSON Job completed successfully
job_error {error} Job failed

GET /chat/sessions

Returns all live session IDs for a user. Expired sessions are pruned lazily.

Query parameters

Parameter Description
anon_id The anon_id cookie value

Response

{"sessions": ["uuid-1", "uuid-2"]}

GET /chat/session/{session_id}

Returns the full message history for a session. Returns 404 if the session has expired or does not exist.

Response

{
  "session_id": "uuid",
  "name": "My session",
  "created_at": 1712345678.0,
  "messages": [
    {"role": "user", "content": "What is EGFR?", "route": null, "confidence": null},
    {"role": "assistant", "content": "EGFR is...", "route": "agent", "confidence": 0.91}
  ]
}

PATCH /chat/session/{session_id}

Renames a session. Returns 404 if the session does not exist.

Request body

{"name": "My renamed session"}

Response

{"session_id": "uuid", "name": "My renamed session"}

DELETE /chat/session/{session_id}

Deletes a session and removes it from the user's session list. Returns HTTP 204 with no body.

Pass x-anon-id header to ensure the session is also removed from the user's session index in Valkey.


MCP (Model Context Protocol)

POST /mcp/*

The server exposes a FastMCP server mounted at /mcp. External AI agents (Claude Desktop, OpenAI Agents SDK, etc.) can connect to this endpoint to use the knowledge graph as a tool.

Two tools are available:

Tool Parameters Description
vector_search sentence, graph_name, top_k Semantic similarity search over the indexed graph
graph_query cypher_query, graph_name Execute a Cypher query and return results

Both tools create their own TuringDB client per call using the chat-agent configuration (TURINGDB_URL, TURINGDB_PORT).


Query (stub)

POST /query

Warning

This endpoint is not implemented and raises NotImplementedError. It is a placeholder for a future single-call vector search + RAG endpoint.