PageIndex Agent Integration
Connect your own agent to PageIndex to find and read documents. Configure your framework with PageIndex's instructions and retrieval tools, then choose the documents or folder for each question. For a ready-to-run document-QA agent, use LLM Integration.
- Set up the PageIndex client — connect your library or index a document.
- Connect your agent — configure instructions and tools for your framework.
- Choose documents or a folder — prepare the context and question.
- Citations — include source references in your agent's answers.
Set up the PageIndex client
Only the index side needs configuring — your agent framework brings its own model.
export PAGEINDEX_API_KEY="your-pageindex-key"
from pageindex import PageIndexClient
client = PageIndexClient(index="cloud")
export OPENAI_API_KEY="your-openai-key"
from pageindex import PageIndexClient
client = PageIndexClient(
index="gpt-5.6-luna", # model that builds the tree index
)
Use an existing document ID from client.list_documents(), or submit a new document. wait=True blocks until it is ready:
doc_id = client.submit_document("./2023-annual-report.pdf", wait=True)["doc_id"]
See Client Configuration for the full parameter list.
Connect your agent
The system prompt — agent_instructions()
PageIndex's default system prompt. You can also pass your own system prompt.
instructions = client.agent_instructions()
Define messages as shown below.
from agents import Agent, Runner
agent = Agent(
name="PageIndex",
instructions=instructions,
tools=client.as_openai_tools(),
model="gpt-5.6-sol",
)
result = Runner.run_sync(agent, messages)
print(result.final_output)
pip install "anthropic>=0.108.0"
import anthropic
anthropic_client = anthropic.Anthropic()
runner_config = dict(
model="claude-opus-5",
max_tokens=16000,
system=instructions,
tools=client.as_anthropic_tools(),
)
runner = anthropic_client.beta.messages.tool_runner(
**runner_config,
messages=messages,
)
final = runner.until_done()
print(final.content[0].text)
Use as_anthropic_tools(asynchronous=True) with AsyncAnthropic. For a manual messages.create loop, serialize tools with [tool.to_dict() for tool in tools].
pip install claude-agent-sdk
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions
options = ClaudeAgentOptions(
model="claude-opus-5",
system_prompt=instructions,
mcp_servers={"pageindex": client.as_claude_mcp()},
allowed_tools=["mcp__pageindex"],
)
async def input_messages():
for message in messages:
yield {
"type": "user",
"message": message,
"parent_tool_use_id": None,
"session_id": "",
}
async def main():
async for message in query(prompt=input_messages(), options=options):
print(message)
asyncio.run(main())
On cloud, as_claude_mcp() returns the remote PageIndex MCP config. Locally it returns an in-process SDK MCP server exposing the agent tools.
tools = client.agent_tools()
Pass instructions and these plain Python functions to your framework's agent, then supply messages as its conversation history. Each function takes JSON-serializable arguments and returns a JSON string. Tool failures are reported inside that JSON; unrecoverable cloud failures raise PageIndexAPIError.
Document management tools
Tools are read-only by default (include_management=False). To also expose tools that modify the library, pass include_management=True to both agent_instructions() and your framework's tool method, such as as_openai_tools() or agent_tools(), so the instructions match the tool set.
On cloud, the default uses the read-only MCP endpoint (/mcp?tools=read); True uses the full /mcp tool list, including upload and delete. Locally, True adds remove_document.
Shortcut: one-call configuration bundles
These helpers return the system instructions and tools together. Use the matching replacement for your framework's configuration above:
agent = Agent(**client.openai_agent_config(model="gpt-5.6-sol"))
runner_config = client.anthropic_runner_config(model="claude-opus-5")
options = ClaudeAgentOptions(**client.claude_agent_config(model="claude-opus-5"))
The Anthropic bundle also includes a max_tokens default. Use the explicit configuration to customize instructions, tools, or servers.
Choose documents or a folder
Build the messages used in the integration examples above. First, tell the agent where to look with document_context() or folder_context(). These return text containing the selected documents' or folder's metadata and retrieval guidance. Choose one of the following:
context = client.document_context(doc_id)
context = client.document_context([doc_id_1, doc_id_2])
Folders are available on cloud. Find a folder ID with client.list_folders().
context = client.folder_context("my-folder-id")
This tells the agent to discover documents within the folder. See Folders for creating and organizing folders.
To also specify documents, place the folder context before the document context:
context = "\n\n".join(filter(None, [
client.folder_context("my-folder-id"),
client.document_context(doc_id),
]))
Put the selected context in its own first user message, then add the question as a second message. All framework examples above use this list:
messages = [
{"role": "user", "content": context},
{"role": "user", "content": "Summarize the auditor's concerns."},
]
To let the agent discover documents across your library, omit the context message and pass just the question. folder_context("root") also leaves discovery unrestricted and returns an empty string.
The context steers the agent; it does not restrict tool access to the selected documents or folder. The framework tools retain access to your library. Both context methods raise PageIndexAPIError if a selected document or folder is missing or inaccessible.
Citations
Replace instructions = client.agent_instructions() in Connect your agent with the following, before creating the agent or runner:
instructions = client.agent_instructions() + "\n\n" + client.citation_prompt()
Answers then cite their sources with <cite doc="report.pdf" page="12"/> tags.
Block-level citations — cloud only. Local citations stop at the page. On cloud, a citation also carries a block attribute naming one layout block:
Revenue increased during the reporting period. <cite doc="report.pdf" page="12" block="p12_text_3"/>
get_citations() parses the tags in the agent's answer into a list, resolving each doc name to a document ID and each block to its position:
citations = client.get_citations(answer)
# [{'document': 'report.pdf', 'doc_id': 'pi-…', 'page': 12,
# 'block_id': 'p12_text_3', 'bbox': [78, 24, 293, 44], 'block_type': 'text', 'text': '…'}]
bbox is [x0, y0, x1, y1] in thousandths of the page's width and height, origin top-left, and comes only when the block could be read — use citation.get("bbox").
An agent's answer carries the same tags as a chat() answer, so the rest works the same: see Display the citations to rewrite them as numbered links, and Highlight the cited region to draw a citation's box on the page image.