openapi: 3.2.0
info:
  title: Lab0 Knowledge API
  version: "1.0.0"
  summary: Upload documents and get answers grounded in them.
  description: |
    The Knowledge API stores your documents, makes them searchable, and answers
    questions using only what they say. This reference is generated from an
    OpenAPI document at `https://app.lab0.ai/app/api/knowledge/openapi.yaml`.

    1. Upload documents into a **namespace**, for example one per end customer.
    2. Wait until each file is `ready`.
    3. Ask a question about a namespace. An agent searches and reads the
       documents, then answers and lists the files it retrieved passages from.

    ## Quickstart

    1. Create an API key with **Read & write** access in Lab0 under **Account →
       API keys**.
    2. Upload a document with [Upload a file](#tag/files/POST/api/knowledge/files). Namespaces are created on
       first use.
    3. Poll [Get a file](#tag/files/GET/api/knowledge/files/{file_id}) every few seconds until its
       status is `ready` or `failed`.
    4. Ask a question with [Ask a question](#tag/answers/POST/api/knowledge/respond).

    Every endpoint has code samples in curl, Python, Node.js and Go.
    [Ask a question](#tag/answers/POST/api/knowledge/respond) also has samples that stream the
    answer, under **Code Examples** in its language picker.

    ## Authentication

    Send a personal API key as a bearer token:
    `Authorization: Bearer lab0_sk_...`. A key acts as the Lab0 user who created
    it, and every request sees only that user's files.

    - **Read-only** keys can list and fetch files and namespaces.
    - **Read & write** keys can also upload, ask questions, and delete files and
      namespaces.

    Requests from a signed-in browser session also work. Uploads and questions
    sent that way must include the header `X-Lab0-Knowledge: 1`.

    ## Namespaces

    A namespace groups the documents a question can draw on. A question covers
    one namespace, optionally narrowed to some of its files.

    - Names are 1 to 128 ASCII letters, digits, `.`, `_`, `:` or `-`. Surrounding
      whitespace is removed.
    - When a request leaves the namespace out, it uses `default`.
    - A namespace is created by the first upload into it. It stays, even when
      empty, until you delete it.

    ## Processing

    An upload returns at once with the file in status `pending`. The file then
    moves through `extracting`, `structuring` and `indexing` to `ready`. Markdown
    files skip extraction and structuring.

    There is no row-count limit per table. Large tables are split into passages
    between rows, repeating headers and preserving source citations. A single
    exceptionally long row may be split to fit the embedding model's input.

    Long passages are read in pages of up to 4,000 Unicode characters. The
    agent can continue within a passage to reach evidence later in a long row.

    Supported ingestion formats: `.md`, `.pdf`, `.docx`, `.pptx`, `.xlsx`,
    `.xlsm`, `.xls`, `.csv`, `.tsv`, `.txt`, `.json`, `.xml`, `.rtf`, `.xbrl`,
    `.ixbrl`, `.html`, `.htm`, `.jpg`, `.jpeg`, `.png`, `.tif`, `.tiff`, `.bmp`,
    `.gif`, `.webp`. Convert legacy `.doc` and `.ppt` to `.docx` and `.pptx`
    before uploading. Unsupported formats may fail during extraction.

    If processing fails, the status becomes `failed` and `error` says which step
    failed, and why when the reason is known. Delete the file and upload it again
    to retry.

    When answering, the agent searches the namespace's index, which holds a
    file's passages as soon as they are written during `indexing`. It can read
    further through a document only once the file is `ready`. Wait for `ready`
    before relying on a file in answers.

    ## Answers

    Each question is answered on its own, with no conversation history. To ask a
    follow-up, include the context it needs in the prompt.

    - The agent can search and read only the namespace's documents, and does not
      search the web. It is instructed to answer only from them, and to say so
      when they don't cover the question rather than guess.
    - The answer takes whatever form the prompt asks for. The agent is told not
      to include images, and Markdown images and HTML `<img>` tags are stripped.
    - `sources` lists the files the agent retrieved passages from. It can include
      a file the final answer did not use.
    - An answer usually takes several seconds and is cut off after three
      minutes.

    Set `stream: true` to receive the answer as server-sent events while it is
    written. The stream is:

    1. one `meta` event
    2. `chunk` events carrying text, and `tool` events while the agent searches
       and reads. A `chunk` with `"reset": true` means the text sent since the last
       tool call was not part of the answer: discard it.
    3. one `done` event with the same body as the JSON response

    If answering fails mid-stream, an `error` event comes before `done`, and
    `done` carries no answer. Text received before an `error` event is not an
    answer: discard it. A stream that ends without `done` is incomplete. Lines
    starting with `:` are keep-alive comments.
    [Ask a question](#tag/answers/POST/api/knowledge/respond) shows an example
    stream.

    ## Limits

    | Limit | Default |
    | --- | --- |
    | File size | 50 MB |
    | Storage per user | 2 GB |
    | Files per namespace | 1,000 |
    | Namespaces per user | 100 |
    | Prompt length | 8,000 characters |
    | `file_ids` per question | 50 |
    | Question request body | 64 KB |

    A file over the size limit gets `413`. Uploads past the other storage limits
    get `409`: delete files or namespaces to make room.

    ## Errors

    Errors return a JSON body with a machine-readable `code`, a human-readable
    `message`, and a `request_id` to quote when reporting a problem.

    | Status | `code` | Meaning |
    | --- | --- | --- |
    | 400 | `invalid_input` | The request is malformed or a value is invalid. |
    | 401 | `unauthorized` | The API key is missing, invalid or expired. |
    | 403 | `unauthorized` | The key's scope doesn't allow this, or a browser request lacks `X-Lab0-Knowledge: 1`. |
    | 404 | `not_found` | The file or namespace doesn't exist or isn't yours. |
    | 409 | `conflict` | A storage limit would be exceeded. |
    | 413 | `invalid_input` | The file or request body is too large. |
    | 500 | `internal_error` | Something went wrong on Lab0's side. Retry, and quote `request_id` if it keeps happening. |
    | 502 | `provider_error` | The model or document search failed. Retry. |
    | 503 | `unavailable` or `auth_unavailable` | The service or sign-in is unavailable. Retry later. |
    | 504 | `unavailable` | The answer took longer than three minutes. Try a narrower question. |

    Any request can get `500` or `503`. A streamed answer that fails after the
    stream has started reports the failure in an `error` event instead of a
    `502` or `504`.
servers:
  - url: https://app.lab0.ai/app
    description: Production
security:
  - apiKey: []
tags:
  - name: Files
    description: Upload, inspect and delete documents.
  - name: Namespaces
    description: List and delete groups of documents.
  - name: Answers
    description: Ask questions answered from a namespace's documents.
paths:
  /api/knowledge/files:
    post:
      operationId: uploadFile
      tags: [Files]
      summary: Upload a file
      description: |
        Stores the file and starts processing it in the background. The response
        is the file in status `pending`; poll [Get a file](#tag/files/GET/api/knowledge/files/{file_id})
        until it is `ready` or `failed`.

        Requires a write key.
      parameters:
        - $ref: "#/components/parameters/BrowserGuard"
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required: [file]
              properties:
                file:
                  type: string
                  format: binary
                  contentMediaType: application/octet-stream
                  description: The document. Its file name is kept as the file's `name`.
                namespace:
                  $ref: "#/components/schemas/NamespaceName"
      responses:
        "202":
          description: The file is stored and processing has started.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/File"
              example:
                id: kfile-3f9c2a7d1b6e4c08a5f2d9e1b7c4a6f0
                namespace: "customer:4821"
                name: contract.pdf
                mime_type: application/pdf
                byte_size: 482113
                status: pending
                created_at: "2026-10-09T09:30:00Z"
                updated_at: "2026-10-09T09:30:00Z"
        "400":
          $ref: "#/components/responses/InvalidInput"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "409":
          description: A storage limit would be exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              example:
                code: conflict
                message: This namespace already has the maximum of 1000 files.
                request_id: Kq3vX9pLmT2wR8sYcN5bH7dJ4fG6aZ1e
        "413":
          description: The file is larger than the file size limit.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              example:
                code: invalid_input
                message: Files can be at most 50 MB.
                request_id: Kq3vX9pLmT2wR8sYcN5bH7dJ4fG6aZ1e
        "503":
          $ref: "#/components/responses/Unavailable"
    get:
      operationId: listFiles
      tags: [Files]
      summary: List files
      description: Lists the files in one namespace, newest first. A namespace that doesn't exist has no files.
      parameters:
        - name: namespace
          in: query
          description: The namespace to list. Defaults to `default`.
          schema:
            $ref: "#/components/schemas/NamespaceName"
      responses:
        "200":
          description: The namespace's files.
          content:
            application/json:
              schema:
                type: object
                required: [files]
                properties:
                  files:
                    type: array
                    items:
                      $ref: "#/components/schemas/File"
              example:
                files:
                  - id: kfile-3f9c2a7d1b6e4c08a5f2d9e1b7c4a6f0
                    namespace: "customer:4821"
                    name: contract.pdf
                    mime_type: application/pdf
                    byte_size: 482113
                    status: ready
                    created_at: "2026-10-09T09:30:00Z"
                    updated_at: "2026-10-09T09:30:41Z"
        "400":
          $ref: "#/components/responses/InvalidInput"
        "401":
          $ref: "#/components/responses/Unauthorized"
  /api/knowledge/files/{file_id}:
    parameters:
      - $ref: "#/components/parameters/FileID"
    get:
      operationId: getFile
      tags: [Files]
      summary: Get a file
      description: Returns one file and its processing status.
      responses:
        "200":
          description: The file.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/File"
              examples:
                ready:
                  summary: Ready
                  value:
                    id: kfile-3f9c2a7d1b6e4c08a5f2d9e1b7c4a6f0
                    namespace: "customer:4821"
                    name: contract.pdf
                    mime_type: application/pdf
                    byte_size: 482113
                    status: ready
                    created_at: "2026-10-09T09:30:00Z"
                    updated_at: "2026-10-09T09:30:41Z"
                failed:
                  summary: Processing failed
                  value:
                    id: kfile-9b2e7c4a1d3f4e6a8c0b5d7f9e1a3c5b
                    namespace: "customer:4821"
                    name: scan.pdf
                    mime_type: application/pdf
                    byte_size: 1048576
                    status: failed
                    error: Document extraction failed.
                    created_at: "2026-10-09T09:31:00Z"
                    updated_at: "2026-10-09T09:31:12Z"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
    delete:
      operationId: deleteFile
      tags: [Files]
      summary: Delete a file
      description: |
        Deletes the file, its stored content and its search index entries. A file
        can be deleted while it is processing; anything processing writes
        afterwards is removed too.

        Requires a write key.
      responses:
        "200":
          description: The deleted file, as it was when deleted.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/File"
              example:
                id: kfile-3f9c2a7d1b6e4c08a5f2d9e1b7c4a6f0
                namespace: "customer:4821"
                name: contract.pdf
                mime_type: application/pdf
                byte_size: 482113
                status: ready
                created_at: "2026-10-09T09:30:00Z"
                updated_at: "2026-10-09T09:30:41Z"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/DeleteForbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /api/knowledge/namespaces:
    get:
      operationId: listNamespaces
      tags: [Namespaces]
      summary: List namespaces
      description: Lists your namespaces in name order, with their file counts and sizes.
      responses:
        "200":
          description: Your namespaces.
          content:
            application/json:
              schema:
                type: object
                required: [namespaces]
                properties:
                  namespaces:
                    type: array
                    items:
                      $ref: "#/components/schemas/Namespace"
              example:
                namespaces:
                  - name: "customer:4821"
                    file_count: 12
                    byte_size: 18340221
                    created_at: "2026-10-01T14:02:00Z"
                    updated_at: "2026-10-09T09:30:00Z"
        "401":
          $ref: "#/components/responses/Unauthorized"
  /api/knowledge/namespaces/{namespace}:
    delete:
      operationId: deleteNamespace
      tags: [Namespaces]
      summary: Delete a namespace
      description: |
        Deletes the namespace with all its files, their stored content and the
        namespace's search index.

        Requires a write key.
      parameters:
        - name: namespace
          in: path
          required: true
          description: The namespace to delete.
          schema:
            $ref: "#/components/schemas/NamespaceName"
      responses:
        "200":
          description: The namespace is deleted.
          content:
            application/json:
              schema:
                type: object
                required: [deleted_files]
                properties:
                  deleted_files:
                    type: integer
                    description: How many files were deleted with the namespace.
              example:
                deleted_files: 12
        "400":
          $ref: "#/components/responses/InvalidInput"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/DeleteForbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /api/knowledge/respond:
    post:
      operationId: respond
      x-codeSamples:
        - lang: curl
          label: "curl (streaming)"
          source: |
            curl -N https://app.lab0.ai/app/api/knowledge/respond \
              --header "Authorization: Bearer $LAB0_API_KEY" \
              --header "Content-Type: application/json" \
              --data '{"prompt": "How much notice is needed to terminate for convenience?", "namespace": "customer:4821", "stream": true}'
        - lang: python
          label: "Python (streaming)"
          source: |
            import json
            import os

            import requests

            response = requests.post(
                "https://app.lab0.ai/app/api/knowledge/respond",
                headers={"Authorization": "Bearer " + os.environ["LAB0_API_KEY"]},
                json={
                    "prompt": "How much notice is needed to terminate for convenience?",
                    "namespace": "customer:4821",
                    "stream": True,
                },
                stream=True,
            )
            if not response.ok:
                raise RuntimeError(f"{response.status_code}: {response.text}")
            response.encoding = "utf-8"

            event = None
            for line in response.iter_lines(decode_unicode=True, delimiter="\n"):
                if line.startswith("event: "):
                    event = line.removeprefix("event: ")
                elif line.startswith("data: "):
                    data = json.loads(line.removeprefix("data: "))
                    if event == "chunk":
                        # A reset withdraws the text written since the last tool call. An
                        # app would clear it; a terminal can't, so this starts a new line.
                        print("\n" if data.get("reset") else data["text"], end="", flush=True)
                    elif event == "done":
                        print("\nSources:", [source["file_name"] for source in data["sources"]])
                    elif event == "error":
                        raise RuntimeError(data["message"])
        - lang: typescript
          label: "TypeScript (streaming)"
          source: |
            const response = await fetch("https://app.lab0.ai/app/api/knowledge/respond", {
              method: "POST",
              headers: {
                Authorization: `Bearer ${process.env.LAB0_API_KEY}`,
                "Content-Type": "application/json",
              },
              body: JSON.stringify({
                prompt: "How much notice is needed to terminate for convenience?",
                namespace: "customer:4821",
                stream: true,
              }),
            });
            if (!response.ok) {
              throw new Error(`${response.status}: ${await response.text()}`);
            }

            const reader = response.body!.pipeThrough(new TextDecoderStream()).getReader();
            let buffer = "";
            for (let read = await reader.read(); !read.done; read = await reader.read()) {
              buffer += read.value;
              let end: number;
              while ((end = buffer.indexOf("\n\n")) >= 0) {
                const block = buffer.slice(0, end);
                buffer = buffer.slice(end + 2);
                const event = /^event: (.*)$/m.exec(block)?.[1];
                const data = /^data: (.*)$/m.exec(block)?.[1];
                if (!event || !data) continue; // a keep-alive comment
                const payload = JSON.parse(data);
                if (event === "chunk") {
                  // A reset withdraws the text written since the last tool call. An app
                  // would clear it; a terminal can't, so this starts a new line.
                  process.stdout.write(payload.reset ? "\n" : payload.text);
                } else if (event === "done") {
                  console.log(
                    "\nSources:",
                    payload.sources.map((source: { file_name: string }) => source.file_name),
                  );
                } else if (event === "error") {
                  throw new Error(payload.message);
                }
              }
            }
        - lang: go
          label: "Go (streaming)"
          source: |
            package main

            import (
            	"bufio"
            	"bytes"
            	"encoding/json"
            	"fmt"
            	"io"
            	"net/http"
            	"os"
            	"strings"
            )

            func main() {
            	body, _ := json.Marshal(map[string]any{
            		"prompt":    "How much notice is needed to terminate for convenience?",
            		"namespace": "customer:4821",
            		"stream":    true,
            	})
            	request, _ := http.NewRequest("POST", "https://app.lab0.ai/app/api/knowledge/respond", bytes.NewReader(body))
            	request.Header.Set("Authorization", "Bearer "+os.Getenv("LAB0_API_KEY"))
            	request.Header.Set("Content-Type", "application/json")
            	response, err := http.DefaultClient.Do(request)
            	if err != nil {
            		panic(err)
            	}
            	defer response.Body.Close()
            	if response.StatusCode != http.StatusOK {
            		message, _ := io.ReadAll(response.Body)
            		panic(fmt.Sprintf("%s: %s", response.Status, message))
            	}

            	scanner := bufio.NewScanner(response.Body)
            	scanner.Buffer(make([]byte, 64<<10), 1<<20) // done carries the whole answer on one line
            	var event string
            	for scanner.Scan() {
            		line := scanner.Text()
            		if name, ok := strings.CutPrefix(line, "event: "); ok {
            			event = name
            			continue
            		}
            		data, ok := strings.CutPrefix(line, "data: ")
            		if !ok {
            			continue
            		}
            		var payload struct {
            			Text    string `json:"text"`
            			Reset   bool   `json:"reset"`
            			Message string `json:"message"`
            			Sources []struct {
            				FileName string `json:"file_name"`
            			} `json:"sources"`
            		}
            		if err := json.Unmarshal([]byte(data), &payload); err != nil {
            			panic(err)
            		}
            		switch {
            		case event == "chunk" && payload.Reset:
            			// A reset withdraws the text written since the last tool call. An
            			// app would clear it; a terminal can't, so this starts a new line.
            			fmt.Println()
            		case event == "chunk":
            			fmt.Print(payload.Text)
            		case event == "done":
            			fmt.Println()
            			for _, source := range payload.Sources {
            				fmt.Println("Source:", source.FileName)
            			}
            		case event == "error":
            			panic(payload.Message)
            		}
            	}
            	if err := scanner.Err(); err != nil {
            		panic(err)
            	}
            }
      tags: [Answers]
      summary: Ask a question
      description: |
        Answers the prompt from the documents in one namespace, optionally only
        from the files listed in `file_ids`. The response is JSON, or a stream of
        server-sent events when `stream` is true.

        Requires a write key.
      parameters:
        - $ref: "#/components/parameters/BrowserGuard"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AnswerRequest"
            example:
              prompt: How much notice is needed to terminate for convenience?
              namespace: "customer:4821"
      responses:
        "200":
          description: The answer, as JSON or, with `stream` set, as server-sent events.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Answer"
              example:
                answer: "Either party can terminate for convenience with **45 days'** written notice."
                sources:
                  - file_id: kfile-3f9c2a7d1b6e4c08a5f2d9e1b7c4a6f0
                    file_name: contract.pdf
                model: openai/gpt-6-astra
            text/event-stream:
              itemSchema:
                $ref: "#/components/schemas/AnswerStreamEvent"
              examples:
                answer:
                  summary: A streamed answer
                  serializedValue: |+
                    event: meta
                    data: {"namespace":"customer:4821","model":"openai/gpt-6-astra"}

                    event: tool
                    data: {"name":"search_documents","call_id":"call_1","status":"started"}

                    event: tool
                    data: {"name":"search_documents","call_id":"call_1","status":"completed"}

                    event: chunk
                    data: {"text":"Either party can terminate "}

                    event: chunk
                    data: {"text":"with **45 days'** written notice."}

                    event: done
                    data: {"answer":"Either party can terminate with **45 days'** written notice.","sources":[{"file_id":"kfile-3f9c2a7d1b6e4c08a5f2d9e1b7c4a6f0","file_name":"contract.pdf"}],"model":"openai/gpt-6-astra"}

        "400":
          $ref: "#/components/responses/InvalidInput"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          description: The namespace doesn't exist, or a file in `file_ids` isn't in it.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              example:
                code: not_found
                message: Knowledge namespace not found.
                request_id: Kq3vX9pLmT2wR8sYcN5bH7dJ4fG6aZ1e
        "413":
          description: The request body is larger than 64 KB.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              example:
                code: invalid_input
                message: The request body is too large.
                request_id: Kq3vX9pLmT2wR8sYcN5bH7dJ4fG6aZ1e
        "502":
          description: The model or the document search failed. Retry the request. A streamed answer reports this in an `error` event instead.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              example:
                code: provider_error
                message: Searching the documents failed. Try again.
                request_id: Kq3vX9pLmT2wR8sYcN5bH7dJ4fG6aZ1e
        "503":
          $ref: "#/components/responses/Unavailable"
        "504":
          description: Answering took longer than three minutes. A streamed answer reports this in an `error` event instead.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              example:
                code: unavailable
                message: Answering took too long. Try a narrower question.
                request_id: Kq3vX9pLmT2wR8sYcN5bH7dJ4fG6aZ1e
components:
  securitySchemes:
    apiKey:
      type: http
      scheme: bearer
      description: A personal API key (`lab0_sk_...`), created in Lab0 under **Account → API keys**.
  parameters:
    FileID:
      name: file_id
      in: path
      required: true
      description: The file's ID.
      schema:
        type: string
        examples: [kfile-3f9c2a7d1b6e4c08a5f2d9e1b7c4a6f0]
    BrowserGuard:
      name: X-Lab0-Knowledge
      in: header
      description: Required, with the value `1`, on requests made with a browser session. API-key requests don't need it.
      schema:
        type: string
        const: "1"
  responses:
    InvalidInput:
      description: The request is malformed or a value is invalid.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
          example:
            code: invalid_input
            message: "namespace must match ^[A-Za-z0-9._:-]{1,128}$"
            request_id: Kq3vX9pLmT2wR8sYcN5bH7dJ4fG6aZ1e
    Unauthorized:
      description: The API key is missing, invalid or expired.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
          example:
            code: unauthorized
            message: Invalid or expired API key.
            request_id: Kq3vX9pLmT2wR8sYcN5bH7dJ4fG6aZ1e
    Forbidden:
      description: The key's scope doesn't allow this, or a browser request lacks `X-Lab0-Knowledge`.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
          example:
            code: unauthorized
            message: This API key is read-only. Create a key with write scope to perform this action.
            request_id: Kq3vX9pLmT2wR8sYcN5bH7dJ4fG6aZ1e
    DeleteForbidden:
      description: The API key is read-only. Deleting needs a Read & write key.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
          example:
            code: unauthorized
            message: API keys cannot perform destructive (DELETE) operations. Sign in to delete platform resources.
            request_id: Kq3vX9pLmT2wR8sYcN5bH7dJ4fG6aZ1e
    NotFound:
      description: The resource doesn't exist or isn't yours.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
          example:
            code: not_found
            message: Knowledge file not found.
            request_id: Kq3vX9pLmT2wR8sYcN5bH7dJ4fG6aZ1e
    Unavailable:
      description: The service or sign-in is unavailable. Retry later.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
          example:
            code: auth_unavailable
            message: Sign-in is temporarily unavailable.
            request_id: Kq3vX9pLmT2wR8sYcN5bH7dJ4fG6aZ1e
  schemas:
    NamespaceName:
      type: string
      description: A namespace name. Defaults to `default` where it is optional.
      pattern: "^[A-Za-z0-9._:-]{1,128}$"
      examples: ["customer:4821"]
    File:
      type: object
      required: [id, namespace, name, mime_type, byte_size, status, created_at, updated_at]
      properties:
        id:
          type: string
          description: The file's ID.
        namespace:
          $ref: "#/components/schemas/NamespaceName"
        name:
          type: string
          description: The uploaded file's name.
        mime_type:
          type: string
          description: The file's media type, from the upload or its file name.
        byte_size:
          type: integer
          description: The file's size in bytes.
        status:
          type: string
          enum: [pending, extracting, structuring, indexing, ready, failed]
          description: Where the file is in processing. Wait for `ready` before relying on the file in answers.
        error:
          type: string
          description: Why processing failed. Present only when `status` is `failed`.
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    Namespace:
      type: object
      required: [name, file_count, byte_size, created_at, updated_at]
      properties:
        name:
          $ref: "#/components/schemas/NamespaceName"
        file_count:
          type: integer
          description: How many files the namespace holds.
        byte_size:
          type: integer
          description: The total size of its files in bytes.
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    AnswerRequest:
      type: object
      required: [prompt]
      properties:
        prompt:
          type: string
          minLength: 1
          maxLength: 8000
          description: The question or instruction. Surrounding whitespace is removed.
        namespace:
          $ref: "#/components/schemas/NamespaceName"
        file_ids:
          type: array
          maxItems: 50
          items:
            type: string
          description: Answer only from these files, all of which must be in the namespace. Leave out to use every file.
        stream:
          type: boolean
          default: false
          description: Stream the answer as server-sent events.
    Answer:
      type: object
      required: [answer, sources, model]
      properties:
        answer:
          type: string
          description: The answer, in the form the prompt asked for.
        sources:
          type: array
          items:
            $ref: "#/components/schemas/Source"
          description: The files the agent retrieved passages from while answering.
        model:
          type: string
          description: The model that wrote the answer.
    Source:
      type: object
      required: [file_id, file_name]
      properties:
        file_id:
          type: string
        file_name:
          type: string
    AnswerStreamEvent:
      oneOf:
        - title: meta
          description: Sent first.
          type: object
          required: [event, data]
          properties:
            event:
              const: meta
            data:
              type: string
              description: JSON with the `namespace` being answered from and the `model` answering.
              contentMediaType: application/json
              contentSchema:
                $ref: "#/components/schemas/AnswerStreamMeta"
        - title: chunk
          description: Sent as the answer is written.
          type: object
          required: [event, data]
          properties:
            event:
              const: chunk
            data:
              type: string
              description: 'JSON with `text` to append to the answer, or `"reset": true` to discard the text since the last `tool` event.'
              contentMediaType: application/json
              contentSchema:
                $ref: "#/components/schemas/AnswerStreamChunk"
        - title: tool
          description: Sent when the agent starts or finishes searching or reading documents.
          type: object
          required: [event, data]
          properties:
            event:
              const: tool
            data:
              type: string
              description: JSON with the tool's `name` and `call_id`, and a `status` of `started`, `completed` or `error` (with `error`).
              contentMediaType: application/json
              contentSchema:
                $ref: "#/components/schemas/AnswerStreamTool"
        - title: error
          description: Sent when answering fails, just before `done`. Discard the text received before it.
          type: object
          required: [event, data]
          properties:
            event:
              const: error
            data:
              type: string
              description: JSON with a `message` saying why.
              contentMediaType: application/json
              contentSchema:
                $ref: "#/components/schemas/AnswerStreamError"
        - title: done
          description: Sent last.
          type: object
          required: [event, data]
          properties:
            event:
              const: done
            data:
              type: string
              description: JSON with the same body as the JSON response, or `{}` after an `error` event.
              contentMediaType: application/json
              contentSchema:
                oneOf:
                  - $ref: "#/components/schemas/Answer"
                  - type: object
                    maxProperties: 0
    AnswerStreamMeta:
      type: object
      description: The `data` of a `meta` event.
      required: [namespace, model]
      properties:
        namespace:
          $ref: "#/components/schemas/NamespaceName"
        model:
          type: string
    AnswerStreamChunk:
      type: object
      description: The `data` of a `chunk` event.
      required: [text]
      properties:
        text:
          type: string
          description: Text to append to the answer. Empty on a reset.
        reset:
          type: boolean
          description: When true, discard the text received since the last `tool` event.
    AnswerStreamTool:
      type: object
      description: The `data` of a `tool` event.
      required: [name, call_id, status]
      properties:
        name:
          type: string
          description: The tool, such as `search_documents`, `read_document` or `list_documents`.
        call_id:
          type: string
          description: Pairs a call's `started` and finishing events.
        status:
          type: string
          enum: [started, completed, error]
        error:
          type: string
          description: Why the call failed, when `status` is `error`. After a refused call, such as reading a file outside the namespace, the agent continues. If the documents couldn't be searched or read, answering fails with an `error` event.
    AnswerStreamError:
      type: object
      description: The `data` of an `error` event.
      required: [message]
      properties:
        message:
          type: string
    Error:
      type: object
      required: [code, message]
      properties:
        code:
          type: string
          description: A machine-readable error code, such as `invalid_input`, `unauthorized`, `not_found`, `conflict`, `provider_error` or `unavailable`.
        message:
          type: string
          description: A human-readable explanation.
        request_id:
          type: string
          description: Identifies the request when reporting a problem.
        details:
          type: object
          description: More about the error, for errors that have more to say.
