File search

Retrieval over documents your customer uploaded, not the public corpora — a store, a few files, and a tool the model calls when a question needs them.

Three pieces. A vector store is a named bucket you create. Files you upload into it are chunked and embedded automatically — you never touch an embedding yourself. And file_search is a built-in tool: name your store on the request, and the model decides mid-answer when a question needs to search it.

What this costs
Metered two ways: storage, per GB-month, for what a store holds, and a fee per query each time the model actually calls file_search. Pricing is set by your platform operator and may not be published yet — check Pricing.

Create a store

POST/v1/vector_stores
ParameterTypeDescription
name
Required
stringA name for the store — yours to choose, shown back on every read.
owner
Optional
stringA label for your own bookkeeping. Stored and returned as-is; nothing here enforces access with it.
Response
{
  "id": "vs_9a2f1e7c3b0d5a41e6f2",
  "name": "vendor-contracts",
  "object": "vector_store"
}

Upload files into it

POST/v1/files

Sent as multipart/form-data, not JSON — two fields, file and vector_store_id.

Text is extracted, not merely stored: PDF (its text layer only — a scanned page with nothing selectable extracts nothing), Word .docx, and anything else is read as plain UTF-8 text, which is exactly right for .txt, .md, .csv, .json and source code, and exactly wrong for a legacy .doc, .xlsx or .pptx — those are binary formats that will decode into noise, not an error, and quietly pollute the store. Convert those to PDF or plain text first.
Response
{
  "id": "file_2c88a1f0d94b7e315a02",
  "filename": "contract.pdf",
  "bytes": 84213,
  "chunks": 41,
  "vector_store_id": "vs_9a2f1e7c3b0d5a41e6f2"
}

Each file is split into roughly 900-character passages with 150 characters of overlap at every boundary, cut on paragraph breaks where it can — so a sentence that starts in one chunk and finishes in the next still retrieves for either half.

Create and upload, together

# Create the store.
STORE=$(curl https://api.console.larsa.larsima.com/v1/vector_stores \
  -H "Authorization: Bearer $LARSA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "vendor-contracts"}')
echo "$STORE"
STORE_ID=$(echo "$STORE" | python3 -c 'import json, sys; print(json.load(sys.stdin)["id"])')

# Upload a file into it. Multipart, not JSON.
curl https://api.console.larsa.larsima.com/v1/files \
  -H "Authorization: Bearer $LARSA_API_KEY" \
  -F "vector_store_id=$STORE_ID" \
  -F "file=@contract.pdf"

Search it from a chat completion

tools
[{ "type": "file_search", "vector_store_ids": ["vs_9a2f1e7c3b0d5a41e6f2"] }]
The store ids you put on the request always win — even if the model tries to pass different ones as arguments, yours overwrite them before the search runs, so it can never search a store you did not authorize. Only larsa-auto executes file_search; that's the model every example on this page uses.
curl https://api.console.larsa.larsima.com/v1/chat/completions \
  -H "Authorization: Bearer $LARSA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "larsa-auto",
    "messages": [{"role": "user", "content":
      "What is the termination notice period in the vendor contract? Name which file it came from."}],
    "tools": [{"type": "file_search",
      "vector_store_ids": ["vs_9a2f1e7c3b0d5a41e6f2"]}]
  }'

Citing what comes back

Each hit the model sees carries a filename, a similarity score, and the matched passage — nothing tracks page or paragraph numbers, because extraction does not keep them. Cite by filename: ask the model, in your system prompt, to name the source file for every fact it pulls from a search.

FieldTypeMeaning
filenamestringThe uploaded file the passage came from.
scorenumberCosine similarity to the query, 0 to 1 — higher is closer.
textstringThe matched passage itself, up to roughly 900 characters.

List and delete a store

GET/v1/vector_stores
DELETE/v1/vector_stores/{id}

Deleting a store deletes its files and their chunks with it — there is no separate step.

curl https://api.console.larsa.larsima.com/v1/vector_stores \
  -H "Authorization: Bearer $LARSA_API_KEY"

curl -X DELETE https://api.console.larsa.larsima.com/v1/vector_stores/vs_9a2f1e7c3b0d5a41e6f2 \
  -H "Authorization: Bearer $LARSA_API_KEY"
Navigate Open esc Close