Skip to content
2 min read · 415 words

API — Documents & RAG

All routes 404 when {agent_id} doesn't resolve. The two query routes additionally require the document_search tool (403 otherwise).

POST /agents/{id}/documents/upload — ingest a document

Body: multipart/form-data with a single file field. Constraints: filename ends .txt, content decodes as UTF-8, text non-empty.

bash
curl -X POST http://localhost:8001/agents/1/documents/upload -F "file=@sla.txt"
json
{
  "id": 1, "agent_id": 1, "filename": "sla.txt",
  "file_type": "txt", "status": "indexed",
  "chunks_count": 3, "created_at": "2026-07-16T10:30:00"
}

400 with a specific message for wrong type / bad encoding / empty file. Pipeline internals (chunking 800/100, per-chunk embedding, dual store) and the partial-failure caveat: RAG Ingestion.

GET /agents/{id}/documents — list documents

200DocumentResponse[], newest first.

GET /agents/{id}/chunks — inspect stored chunks

200DocumentChunkResponse[], oldest first — full chunk_text, chunk_index, document_id. Useful for verifying chunk boundaries when retrieval misbehaves (quality levers).

POST /agents/{id}/documents/search — raw vector search

Body (DocumentSearchRequest): {"query": "string", "top_k": 3}

json
{
  "query": "support SLA",
  "results": [
    {
      "chunk_text": "Premium customers have a 4-hour support SLA...",
      "score": 0.31,
      "document_id": 1,
      "filename": "sla.txt",
      "chunk_index": 0
    }
  ]
}

Raw Chroma distance, not a similarity percentage. See Retrieval.

Side effect: document_search ToolCall. 500 on embedding/store failure (failed ToolCall committed first).

POST /agents/{id}/documents/ask — corrective-RAG answer

Body (RAGAnswerRequest): {"question": "string", "top_k": 3}

Runs the corrective RAG graph: retrieve → evaluate → answer or refuse.

json
{
  "question": "What is the premium support SLA?",
  "answer": "Premium customers have a 4-hour support SLA.",
  "sources": [
    {"filename": "sla.txt", "document_id": 1, "chunk_index": 0, "score": 0.31}
  ],
  "retrieval_evaluation": {
    "has_answer": true, "confidence": 0.95,
    "reason": "The context states the premium SLA directly."
  }
}
json
{
  "question": "What is our vacation policy?",
  "answer": "I could not find this information in the uploaded documents.",
  "sources": [ {"filename": "sla.txt", "...": "..."} ],
  "retrieval_evaluation": { "has_answer": false, "confidence": 0.9, "reason": "..." }
}

Interpretation: a refusal is a 200 with the fixed refusal string — check retrieval_evaluation.has_answer to distinguish programmatically. sources always lists what was retrieved, even on refusal (that's the debugging window).

Side effect: langgraph_corrective_rag ToolCall containing answer + sources + evaluation. 500 on any node failure.