Calypso Context · Citations

Every answer says where it came from.

A grounded answer carries inline citations anchored to the text by character offsets, and a structured list of the sources it drew on: source number, label, page, modality, and a signed link to open the original. Your app renders references without parsing the answer.

The example

Ask once. Render the sources from the response.

Native mode keeps the response fully OpenAI-shaped: annotations on the text, sources in file_search_call.results. Nothing to parse, nothing vendor-specific to learn.

CALYPSO_API_KEY
import os
from openai import OpenAI

client = OpenAI(api_key=os.environ["CALYPSO_API_KEY"],
                base_url="https://api.calypso.so/v1")

resp = client.responses.create(
    model="calypso-agent",
    input="What is our refund policy?",
    metadata={"citation_compat": "native", "sources_appendix": "omit"},
)

print(resp.output_text)
for item in resp.output:
    if item.type == "file_search_call":
        for r in item.results:
            a = r.attributes
            print(f"[{a['source_index']}] {a['label']}")   # refund_policy_2026.pdf (p. 4)

Two surfaces

Responses for citation-aware UIs. Chat Completions for compatibility.

Both endpoints carry citations. Responses exposes the full structured surface; Chat Completions is limited to the url_citation shape that spec defines.

Responses

Citations live in
output[] → message → output_text.annotations[]
Sources live in
output[] → file_search_call.results[]

Recommended. Streaming sends one annotation.added event per citation and the full results in response.completed.

Chat Completions

Citations live in
choices[0].message.annotations[] as url_citation
Sources live in
A plain-text "Sources:" appendix in the content

File and media sources map to url_citation with a signed URL when one exists and the filename as title. When streaming, annotations arrive in a final chunk.

The attributes

What every source carries.

The same attributes appear on Responses results and on Search results. Build your source list from them directly.

source_indexStable, 1-based source number that matches the [n] order in the text. Use it for badges and the list.
labelDisplay-ready, for example refund_policy_2026.pdf (p. 4). Falls back to the filename.
page_number · page_label · locator_labelWhere in the document, when known. PDFs cite the page; other documents cite the file.
modality · mime_typetext, multimodal, or image, and the MIME type. An image citation points at the image itself.
access_url · media_idA signed URL to open the original when one is available, and media identifiers for previews.
text · excerpt · previewThe quoted evidence the answer drew on, plus structured excerpt and preview descriptors.

How it works

Ask, map, open.

  1. 01

    Ask an agent

    Call Responses with calypso-agent or a named agent. Retrieval runs against its buckets and the evidence comes back with the answer.

  2. 02

    Map offsets to the text

    Each annotation carries start_index and end_index. Place your [n] markers from the offsets, numbered by source_index.

  3. 03

    Let users open the source

    Render the source list from the attributes, and link each entry to its access_url so a reader can check the page.

Rendering

Four rules from the docs.

  1. 01

    Anchor by offsets, not markers

    Use start_index and end_index to place references. Do not parse [n] tokens out of the text.

  2. 02

    Number by source_index

    It is stable, 1-based, and consistent with citation order. Use it for badges and the list.

  3. 03

    Sort before slicing

    Apply annotations in descending start_index order so earlier insertions do not shift later offsets.

  4. 04

    Respect the grounding state

    Render a sources panel only when grounded_sources_state is available. hidden means policy suppresses sources; missing and none mean there is nothing to show.

From the docs

The schema in one table.

ModelOpenAI annotations: citation objects anchored to the text by character offsets; the answer text stays plain
Responsesoutput[] → message → output_text.annotations[] · output[] → file_search_call.results[]
Chat Completionschoices[0].message.annotations[] (url_citation) + "Sources:" appendix
Compatibility modesmetadata.citation_compat: legacy | native · metadata.sources_appendix: include | omit
Streaming eventresponse.output_text.annotation.added
Page-level citationsPDFs, which are read as page images; images cite the image; other documents cite the file
Grounding statesavailable · hidden · missing · none

Questions and answers

Before you render your first citation.

Keep reading

Start today

Ship answers your users can check.

Load a bucket, ask calypso-agent, and render the source list from the first response.