diff --git a/tests/agents/rlm/test_agent.py b/tests/agents/rlm/test_agent.py
index 2816ca6a..2d5cd060 100644
--- a/tests/agents/rlm/test_agent.py
+++ b/tests/agents/rlm/test_agent.py
@@ -1,3 +1,5 @@
+from pathlib import Path
+
import pytest
from pydantic_ai import Agent
@@ -7,6 +9,11 @@ from haiku.rag.agents.rlm.models import CodeExecution, RLMResult
from haiku.rag.config import Config
+@pytest.fixture(scope="module")
+def vcr_cassette_dir():
+ return str(Path(__file__).parent.parent.parent / "cassettes" / "test_rlm")
+
+
class TestCreateRLMAgent:
def test_creates_agent_with_correct_types(self):
agent = create_rlm_agent(Config)
@@ -104,3 +111,63 @@ class TestExecuteCodeTool:
result = await repl.execute_async("1/0")
assert result.success is False
assert "ZeroDivisionError" in result.stderr
+
+
+class TestClientRLMIntegration:
+ """Integration tests for client.rlm() method."""
+
+ @pytest.mark.asyncio
+ @pytest.mark.vcr()
+ async def test_rlm_count_documents(self, allow_model_requests, temp_db_path):
+ """Test RLM agent can count documents."""
+ from haiku.rag.client import HaikuRAG
+
+ async with HaikuRAG(temp_db_path, create=True) as client:
+ await client.create_document("First document about cats.", title="Doc 1")
+ await client.create_document("Second document about dogs.", title="Doc 2")
+ await client.create_document("Third document about birds.", title="Doc 3")
+
+ answer = await client.rlm("How many documents are in the database?")
+
+ assert "3" in answer
+
+ @pytest.mark.asyncio
+ @pytest.mark.vcr()
+ async def test_rlm_aggregation(self, allow_model_requests, temp_db_path):
+ """Test RLM agent can perform aggregation across documents."""
+ from haiku.rag.client import HaikuRAG
+
+ async with HaikuRAG(temp_db_path, create=True) as client:
+ await client.create_document(
+ "Sales report Q1: Revenue was $100,000.", title="Q1 Report"
+ )
+ await client.create_document(
+ "Sales report Q2: Revenue was $150,000.", title="Q2 Report"
+ )
+ await client.create_document(
+ "Sales report Q3: Revenue was $200,000.", title="Q3 Report"
+ )
+
+ answer = await client.rlm(
+ "What is the total revenue across all quarterly reports?"
+ )
+
+ assert "450" in answer or "450,000" in answer
+
+ @pytest.mark.asyncio
+ @pytest.mark.vcr()
+ async def test_rlm_with_filter(self, allow_model_requests, temp_db_path):
+ """Test RLM agent respects filter parameter."""
+ from haiku.rag.client import HaikuRAG
+
+ async with HaikuRAG(temp_db_path, create=True) as client:
+ await client.create_document("Cat document.", title="Cats")
+ await client.create_document("Dog document.", title="Dogs")
+ await client.create_document("Bird document.", title="Birds")
+
+ answer = await client.rlm(
+ "How many documents are available?",
+ filter="title = 'Cats'",
+ )
+
+ assert "1" in answer
diff --git a/tests/cassettes/test_rlm/TestClientRLMIntegration.test_rlm_aggregation.yaml b/tests/cassettes/test_rlm/TestClientRLMIntegration.test_rlm_aggregation.yaml
new file mode 100644
index 00000000..34fd3ab3
--- /dev/null
+++ b/tests/cassettes/test_rlm/TestClientRLMIntegration.test_rlm_aggregation.yaml
@@ -0,0 +1,2824 @@
+interactions:
+- request:
+ headers:
+ accept:
+ - application/json
+ accept-encoding:
+ - gzip, deflate, zstd
+ connection:
+ - keep-alive
+ content-length:
+ - '108'
+ content-type:
+ - application/json
+ host:
+ - localhost:11434
+ method: POST
+ parsed_body:
+ encoding_format: base64
+ input:
+ - 'Sales report Q1: Revenue was $100,000.'
+ model: qwen3-embedding:4b
+ uri: http://localhost:11434/v1/embeddings
+ response:
+ headers:
+ content-type:
+ - application/json
+ transfer-encoding:
+ - chunked
+ parsed_body:
+ data:
+ - embedding: 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
+ index: 0
+ object: embedding
+ model: qwen3-embedding:4b
+ object: list
+ usage:
+ prompt_tokens: 17
+ total_tokens: 17
+ status:
+ code: 200
+ message: OK
+- request:
+ headers:
+ accept:
+ - application/json
+ accept-encoding:
+ - gzip, deflate, zstd
+ connection:
+ - keep-alive
+ content-length:
+ - '108'
+ content-type:
+ - application/json
+ host:
+ - localhost:11434
+ method: POST
+ parsed_body:
+ encoding_format: base64
+ input:
+ - 'Sales report Q2: Revenue was $150,000.'
+ model: qwen3-embedding:4b
+ uri: http://localhost:11434/v1/embeddings
+ response:
+ headers:
+ content-type:
+ - application/json
+ transfer-encoding:
+ - chunked
+ parsed_body:
+ data:
+ - embedding: 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
+ index: 0
+ object: embedding
+ model: qwen3-embedding:4b
+ object: list
+ usage:
+ prompt_tokens: 17
+ total_tokens: 17
+ status:
+ code: 200
+ message: OK
+- request:
+ headers:
+ accept:
+ - application/json
+ accept-encoding:
+ - gzip, deflate, zstd
+ connection:
+ - keep-alive
+ content-length:
+ - '108'
+ content-type:
+ - application/json
+ host:
+ - localhost:11434
+ method: POST
+ parsed_body:
+ encoding_format: base64
+ input:
+ - 'Sales report Q3: Revenue was $200,000.'
+ model: qwen3-embedding:4b
+ uri: http://localhost:11434/v1/embeddings
+ response:
+ headers:
+ content-type:
+ - application/json
+ transfer-encoding:
+ - chunked
+ parsed_body:
+ data:
+ - embedding: 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
+ index: 0
+ object: embedding
+ model: qwen3-embedding:4b
+ object: list
+ usage:
+ prompt_tokens: 17
+ total_tokens: 17
+ status:
+ code: 200
+ message: OK
+- request:
+ headers:
+ accept:
+ - application/json
+ accept-encoding:
+ - gzip, deflate, zstd
+ connection:
+ - keep-alive
+ content-length:
+ - '7702'
+ content-type:
+ - application/json
+ host:
+ - localhost:11434
+ method: POST
+ parsed_body:
+ messages:
+ - content: |-
+ You are a Recursive Language Model (RLM) agent that solves complex research questions by writing and executing Python code.
+
+ IMPORTANT: You MUST use the `execute_code` tool to run Python code. The functions described below are ONLY available inside the execute_code tool - you cannot access them any other way. Always execute code to answer questions; do not just describe what code would do.
+
+ CRITICAL: Inside execute_code, these functions are ALREADY available in the namespace. Do NOT import them - just use them directly:
+ - search("query") ✓ CORRECT
+ - from haiku.rag import search ✗ WRONG - will fail
+
+ You have access to a sandboxed Python environment with these haiku.rag functions (use them directly, no imports needed):
+
+ ## Available Functions
+
+ ### search(query, limit=10) -> list[dict]
+ Search the knowledge base using hybrid search (vector + full-text).
+ Returns list of dicts with keys: chunk_id, content, document_id, document_title, document_uri, score, page_numbers, headings
+
+ ### list_documents(limit=10, offset=0) -> list[dict]
+ List available documents in the knowledge base.
+ Returns list of dicts with keys: id, title, uri, created_at
+
+ ### get_document(id_or_title) -> str | None
+ Get the full text content of a document by ID, title, or URI.
+ Returns the document content as a string, or None if not found.
+
+ ### get_docling_document(id_or_title) -> DoclingDocument | None
+ Get the structured DoclingDocument object for advanced analysis.
+ Returns a DoclingDocument object, or None if not found.
+ See "DoclingDocument API" section below for how to use it.
+
+ ### ask(question) -> str
+ Ask a question using the QA agent with RAG. Returns the answer as a string.
+ Use this for semantic analysis that benefits from LLM reasoning.
+
+ ## Standard Library Modules
+ You can import: json, re, collections, math, statistics, itertools, functools, datetime, typing
+
+ ## Strategy Guide
+
+ 1. **Explore First**: Start by listing documents or searching to understand what's available. Document names may differ from filenames (e.g., "tbmed593.pdf" might be stored as "TB MED 593" or similar).
+ 2. **If get_document returns None**: Use `list_documents()` to see actual document titles, or `search()` to find relevant content.
+ 3. **Iterative Refinement**: Run code, examine results, adjust your approach based on what you find.
+ 4. **Use print() Liberally**: The REPL captures stdout - print intermediate results to see what you're working with.
+ 5. **Aggregate with Code**: For counting, averaging, or comparing across documents, write loops and use collections.
+ 6. **Use ask() for Semantic Analysis**: When you need to understand meaning or interpret content, use the ask() function.
+ 7. **Cite Your Sources**: Track which documents/chunks informed your answer for citation.
+
+ ## DoclingDocument API
+
+ When you call `get_docling_document(id_or_title)`, you get a DoclingDocument object for structured document analysis.
+
+ ### Properties
+ - `doc.texts` - List of all text items (paragraphs, headings, etc.)
+ - `doc.tables` - List of all tables
+ - `doc.pictures` - List of all pictures/figures
+ - `doc.name` - Document name
+
+ ### Methods
+ - `doc.iterate_items(with_groups=False)` - Iterate all items with hierarchy level
+ Returns tuples of (item, level) where level is nesting depth
+ - `doc.export_to_markdown()` - Export entire document as markdown string
+
+ ### Text Item Properties
+ - `item.text` - The text content
+ - `item.label` - Type: TITLE, PARAGRAPH, SECTION_HEADER, LIST_ITEM, etc.
+ - `item.prov` - Provenance (page numbers, bounding boxes)
+
+ ### Table Access
+ - `table.data.num_rows`, `table.data.num_cols` - Dimensions
+ - `table.data.table_cells` - List of TableCell objects
+ - `cell.text`, `cell.start_row_offset_idx`, `cell.start_col_offset_idx`
+
+ ### Example Usage
+ ```python
+ doc = get_docling_document("My Document")
+
+ # Get all headings
+ headings = [t.text for t in doc.texts if "HEADER" in str(t.label)]
+
+ # Iterate with structure
+ for item, level in doc.iterate_items():
+ print(" " * level + item.text[:50])
+
+ # Extract table data
+ for table in doc.tables:
+ for cell in table.data.table_cells:
+ print(f"Row {cell.start_row_offset_idx}, Col {cell.start_col_offset_idx}: {cell.text}")
+ ```
+
+ ## Example Patterns
+
+ ### Counting documents matching a condition
+ ```python
+ docs = list_documents(limit=100)
+ count = 0
+ for doc in docs:
+ content = get_document(doc['id'])
+ if content and 'keyword' in content.lower():
+ count += 1
+ print(f"Found in: {doc['title']}")
+ print(f"Total: {count}")
+ ```
+
+ ### Aggregating data across documents
+ ```python
+ import re
+ numbers = []
+ results = search("financial data", limit=20)
+ for r in results:
+ matches = re.findall(r'\$([\d,]+)', r['content'])
+ for m in matches:
+ numbers.append(int(m.replace(',', '')))
+ print(f"Average: ${sum(numbers)/len(numbers):,.2f}")
+ ```
+
+ ### Using ask() for semantic analysis
+ ```python
+ # First search to find relevant content
+ results = search("machine learning approaches")
+ # Then use ask() to synthesize an answer
+ summary = ask("What are the main machine learning approaches discussed?")
+ print(summary)
+ ```
+
+ ## Workflow
+
+ 1. **ALWAYS start by using execute_code** to explore the knowledge base
+ 2. Run multiple code blocks as needed to gather information
+ 3. After collecting data, provide your final answer
+
+ ## Output Format
+
+ After executing code and gathering information, provide:
+ 1. A clear answer to the user's question
+ 2. Key findings from your analysis
+ 3. References to specific documents/chunks that informed your answer
+
+ CRITICAL: You MUST call execute_code at least once before providing your answer. Never give up without trying to execute code first.
+ role: system
+ - content: What is the total revenue across all quarterly reports?
+ role: user
+ model: gpt-oss
+ reasoning_effort: low
+ stream: false
+ tool_choice: auto
+ tools:
+ - function:
+ description: |-
+ Execute Python code in the sandboxed environment.
+
+ The code has access to haiku.rag functions (search, list_documents,
+ get_document, get_docling_document, ask) and safe standard library
+ modules (json, re, collections, math, statistics, itertools,
+ functools, datetime, typing).
+
+ Use print() to output results. Variables persist between executions.
+
+ Structured result with success status, stdout, and stderr.
+
+ name: execute_code
+ parameters:
+ additionalProperties: false
+ properties:
+ code:
+ description: Python code to execute.
+ type: string
+ required:
+ - code
+ type: object
+ strict: true
+ type: function
+ - function:
+ description: Result from RLM agent execution.
+ name: final_result
+ parameters:
+ $defs:
+ CodeExecution:
+ additionalProperties: false
+ description: Result of executing a code block in the RLM sandbox.
+ properties:
+ code:
+ description: The Python code that was executed
+ type: string
+ stderr:
+ description: Standard error captured during execution
+ type: string
+ stdout:
+ description: Standard output captured during execution
+ type: string
+ success:
+ description: Whether execution completed without error
+ type: boolean
+ required:
+ - code
+ - stdout
+ - stderr
+ - success
+ type: object
+ additionalProperties: false
+ properties:
+ answer:
+ description: The answer to the user's question
+ type: string
+ code_executions:
+ description: History of code executions during the RLM session
+ items:
+ $ref: '#/$defs/CodeExecution'
+ type: array
+ required:
+ - answer
+ type: object
+ type: function
+ uri: http://localhost:11434/v1/chat/completions
+ response:
+ headers:
+ content-length:
+ - '695'
+ content-type:
+ - application/json
+ parsed_body:
+ choices:
+ - finish_reason: tool_calls
+ index: 0
+ message:
+ content: ''
+ reasoning: We need revenue from quarterly reports. Search for "quarterly report" and revenue.
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"results = search(\"quarterly report revenue\", limit=50)\nprint(len(results))\nfor r in
+ results[:5]:\n print(r[''document_title''], r[''score''], r[''page_numbers''])\n"}'
+ name: execute_code
+ id: call_8cd1wnf6
+ index: 0
+ type: function
+ created: 1769703355
+ id: chatcmpl-273
+ model: gpt-oss
+ object: chat.completion
+ system_fingerprint: fp_ollama
+ usage:
+ completion_tokens: 87
+ prompt_tokens: 1601
+ total_tokens: 1688
+ status:
+ code: 200
+ message: OK
+- request:
+ headers:
+ accept:
+ - application/json
+ accept-encoding:
+ - gzip, deflate, zstd
+ connection:
+ - keep-alive
+ content-length:
+ - '94'
+ content-type:
+ - application/json
+ host:
+ - localhost:11434
+ method: POST
+ parsed_body:
+ encoding_format: base64
+ input:
+ - quarterly report revenue
+ model: qwen3-embedding:4b
+ uri: http://localhost:11434/v1/embeddings
+ response:
+ headers:
+ content-type:
+ - application/json
+ transfer-encoding:
+ - chunked
+ parsed_body:
+ data:
+ - embedding: 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
+ index: 0
+ object: embedding
+ model: qwen3-embedding:4b
+ object: list
+ usage:
+ prompt_tokens: 5
+ total_tokens: 5
+ status:
+ code: 200
+ message: OK
+- request:
+ headers:
+ accept:
+ - application/json
+ accept-encoding:
+ - gzip, deflate, zstd
+ connection:
+ - keep-alive
+ content-length:
+ - '8540'
+ content-type:
+ - application/json
+ host:
+ - localhost:11434
+ method: POST
+ parsed_body:
+ messages:
+ - content: |-
+ You are a Recursive Language Model (RLM) agent that solves complex research questions by writing and executing Python code.
+
+ IMPORTANT: You MUST use the `execute_code` tool to run Python code. The functions described below are ONLY available inside the execute_code tool - you cannot access them any other way. Always execute code to answer questions; do not just describe what code would do.
+
+ CRITICAL: Inside execute_code, these functions are ALREADY available in the namespace. Do NOT import them - just use them directly:
+ - search("query") ✓ CORRECT
+ - from haiku.rag import search ✗ WRONG - will fail
+
+ You have access to a sandboxed Python environment with these haiku.rag functions (use them directly, no imports needed):
+
+ ## Available Functions
+
+ ### search(query, limit=10) -> list[dict]
+ Search the knowledge base using hybrid search (vector + full-text).
+ Returns list of dicts with keys: chunk_id, content, document_id, document_title, document_uri, score, page_numbers, headings
+
+ ### list_documents(limit=10, offset=0) -> list[dict]
+ List available documents in the knowledge base.
+ Returns list of dicts with keys: id, title, uri, created_at
+
+ ### get_document(id_or_title) -> str | None
+ Get the full text content of a document by ID, title, or URI.
+ Returns the document content as a string, or None if not found.
+
+ ### get_docling_document(id_or_title) -> DoclingDocument | None
+ Get the structured DoclingDocument object for advanced analysis.
+ Returns a DoclingDocument object, or None if not found.
+ See "DoclingDocument API" section below for how to use it.
+
+ ### ask(question) -> str
+ Ask a question using the QA agent with RAG. Returns the answer as a string.
+ Use this for semantic analysis that benefits from LLM reasoning.
+
+ ## Standard Library Modules
+ You can import: json, re, collections, math, statistics, itertools, functools, datetime, typing
+
+ ## Strategy Guide
+
+ 1. **Explore First**: Start by listing documents or searching to understand what's available. Document names may differ from filenames (e.g., "tbmed593.pdf" might be stored as "TB MED 593" or similar).
+ 2. **If get_document returns None**: Use `list_documents()` to see actual document titles, or `search()` to find relevant content.
+ 3. **Iterative Refinement**: Run code, examine results, adjust your approach based on what you find.
+ 4. **Use print() Liberally**: The REPL captures stdout - print intermediate results to see what you're working with.
+ 5. **Aggregate with Code**: For counting, averaging, or comparing across documents, write loops and use collections.
+ 6. **Use ask() for Semantic Analysis**: When you need to understand meaning or interpret content, use the ask() function.
+ 7. **Cite Your Sources**: Track which documents/chunks informed your answer for citation.
+
+ ## DoclingDocument API
+
+ When you call `get_docling_document(id_or_title)`, you get a DoclingDocument object for structured document analysis.
+
+ ### Properties
+ - `doc.texts` - List of all text items (paragraphs, headings, etc.)
+ - `doc.tables` - List of all tables
+ - `doc.pictures` - List of all pictures/figures
+ - `doc.name` - Document name
+
+ ### Methods
+ - `doc.iterate_items(with_groups=False)` - Iterate all items with hierarchy level
+ Returns tuples of (item, level) where level is nesting depth
+ - `doc.export_to_markdown()` - Export entire document as markdown string
+
+ ### Text Item Properties
+ - `item.text` - The text content
+ - `item.label` - Type: TITLE, PARAGRAPH, SECTION_HEADER, LIST_ITEM, etc.
+ - `item.prov` - Provenance (page numbers, bounding boxes)
+
+ ### Table Access
+ - `table.data.num_rows`, `table.data.num_cols` - Dimensions
+ - `table.data.table_cells` - List of TableCell objects
+ - `cell.text`, `cell.start_row_offset_idx`, `cell.start_col_offset_idx`
+
+ ### Example Usage
+ ```python
+ doc = get_docling_document("My Document")
+
+ # Get all headings
+ headings = [t.text for t in doc.texts if "HEADER" in str(t.label)]
+
+ # Iterate with structure
+ for item, level in doc.iterate_items():
+ print(" " * level + item.text[:50])
+
+ # Extract table data
+ for table in doc.tables:
+ for cell in table.data.table_cells:
+ print(f"Row {cell.start_row_offset_idx}, Col {cell.start_col_offset_idx}: {cell.text}")
+ ```
+
+ ## Example Patterns
+
+ ### Counting documents matching a condition
+ ```python
+ docs = list_documents(limit=100)
+ count = 0
+ for doc in docs:
+ content = get_document(doc['id'])
+ if content and 'keyword' in content.lower():
+ count += 1
+ print(f"Found in: {doc['title']}")
+ print(f"Total: {count}")
+ ```
+
+ ### Aggregating data across documents
+ ```python
+ import re
+ numbers = []
+ results = search("financial data", limit=20)
+ for r in results:
+ matches = re.findall(r'\$([\d,]+)', r['content'])
+ for m in matches:
+ numbers.append(int(m.replace(',', '')))
+ print(f"Average: ${sum(numbers)/len(numbers):,.2f}")
+ ```
+
+ ### Using ask() for semantic analysis
+ ```python
+ # First search to find relevant content
+ results = search("machine learning approaches")
+ # Then use ask() to synthesize an answer
+ summary = ask("What are the main machine learning approaches discussed?")
+ print(summary)
+ ```
+
+ ## Workflow
+
+ 1. **ALWAYS start by using execute_code** to explore the knowledge base
+ 2. Run multiple code blocks as needed to gather information
+ 3. After collecting data, provide your final answer
+
+ ## Output Format
+
+ After executing code and gathering information, provide:
+ 1. A clear answer to the user's question
+ 2. Key findings from your analysis
+ 3. References to specific documents/chunks that informed your answer
+
+ CRITICAL: You MUST call execute_code at least once before providing your answer. Never give up without trying to execute code first.
+ role: system
+ - content: What is the total revenue across all quarterly reports?
+ role: user
+ - content: |-
+
+ We need revenue from quarterly reports. Search for "quarterly report" and revenue.
+
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"results = search(\"quarterly report revenue\", limit=50)\nprint(len(results))\nfor r in results[:5]:\n print(r[''document_title''],
+ r[''score''], r[''page_numbers''])\n"}'
+ name: execute_code
+ id: call_8cd1wnf6
+ type: function
+ - content: '{"code":"results = search(\"quarterly report revenue\", limit=50)\nprint(len(results))\nfor r in results[:5]:\n print(r[''document_title''],
+ r[''score''], r[''page_numbers''])\n","stdout":"3\nQ1 Report 0.03226645663380623 []\nQ2 Report 0.03226645663380623
+ []\nQ3 Report 0.032258063554763794 []\n","stderr":"","success":true}'
+ role: tool
+ tool_call_id: call_8cd1wnf6
+ model: gpt-oss
+ reasoning_effort: low
+ stream: false
+ tool_choice: auto
+ tools:
+ - function:
+ description: |-
+ Execute Python code in the sandboxed environment.
+
+ The code has access to haiku.rag functions (search, list_documents,
+ get_document, get_docling_document, ask) and safe standard library
+ modules (json, re, collections, math, statistics, itertools,
+ functools, datetime, typing).
+
+ Use print() to output results. Variables persist between executions.
+
+ Structured result with success status, stdout, and stderr.
+
+ name: execute_code
+ parameters:
+ additionalProperties: false
+ properties:
+ code:
+ description: Python code to execute.
+ type: string
+ required:
+ - code
+ type: object
+ strict: true
+ type: function
+ - function:
+ description: Result from RLM agent execution.
+ name: final_result
+ parameters:
+ $defs:
+ CodeExecution:
+ additionalProperties: false
+ description: Result of executing a code block in the RLM sandbox.
+ properties:
+ code:
+ description: The Python code that was executed
+ type: string
+ stderr:
+ description: Standard error captured during execution
+ type: string
+ stdout:
+ description: Standard output captured during execution
+ type: string
+ success:
+ description: Whether execution completed without error
+ type: boolean
+ required:
+ - code
+ - stdout
+ - stderr
+ - success
+ type: object
+ additionalProperties: false
+ properties:
+ answer:
+ description: The answer to the user's question
+ type: string
+ code_executions:
+ description: History of code executions during the RLM session
+ items:
+ $ref: '#/$defs/CodeExecution'
+ type: array
+ required:
+ - answer
+ type: object
+ type: function
+ uri: http://localhost:11434/v1/chat/completions
+ response:
+ headers:
+ content-length:
+ - '635'
+ content-type:
+ - application/json
+ parsed_body:
+ choices:
+ - finish_reason: tool_calls
+ index: 0
+ message:
+ content: ''
+ reasoning: 'We have 3 reports: Q1, Q2, Q3. Likely Q4 also exists. Search again for Q4.'
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"results = search(\"Q4 Report\", limit=10)\nprint(len(results))\nfor r in results:\n print(r[''document_title''])\n"}'
+ name: execute_code
+ id: call_mgo4t2ty
+ index: 0
+ type: function
+ created: 1769703357
+ id: chatcmpl-775
+ model: gpt-oss
+ object: chat.completion
+ system_fingerprint: fp_ollama
+ usage:
+ completion_tokens: 85
+ prompt_tokens: 1812
+ total_tokens: 1897
+ status:
+ code: 200
+ message: OK
+- request:
+ headers:
+ accept:
+ - application/json
+ accept-encoding:
+ - gzip, deflate, zstd
+ connection:
+ - keep-alive
+ content-length:
+ - '79'
+ content-type:
+ - application/json
+ host:
+ - localhost:11434
+ method: POST
+ parsed_body:
+ encoding_format: base64
+ input:
+ - Q4 Report
+ model: qwen3-embedding:4b
+ uri: http://localhost:11434/v1/embeddings
+ response:
+ headers:
+ content-type:
+ - application/json
+ transfer-encoding:
+ - chunked
+ parsed_body:
+ data:
+ - embedding: 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
+ index: 0
+ object: embedding
+ model: qwen3-embedding:4b
+ object: list
+ usage:
+ prompt_tokens: 4
+ total_tokens: 4
+ status:
+ code: 200
+ message: OK
+- request:
+ headers:
+ accept:
+ - application/json
+ accept-encoding:
+ - gzip, deflate, zstd
+ connection:
+ - keep-alive
+ content-length:
+ - '9198'
+ content-type:
+ - application/json
+ host:
+ - localhost:11434
+ method: POST
+ parsed_body:
+ messages:
+ - content: |-
+ You are a Recursive Language Model (RLM) agent that solves complex research questions by writing and executing Python code.
+
+ IMPORTANT: You MUST use the `execute_code` tool to run Python code. The functions described below are ONLY available inside the execute_code tool - you cannot access them any other way. Always execute code to answer questions; do not just describe what code would do.
+
+ CRITICAL: Inside execute_code, these functions are ALREADY available in the namespace. Do NOT import them - just use them directly:
+ - search("query") ✓ CORRECT
+ - from haiku.rag import search ✗ WRONG - will fail
+
+ You have access to a sandboxed Python environment with these haiku.rag functions (use them directly, no imports needed):
+
+ ## Available Functions
+
+ ### search(query, limit=10) -> list[dict]
+ Search the knowledge base using hybrid search (vector + full-text).
+ Returns list of dicts with keys: chunk_id, content, document_id, document_title, document_uri, score, page_numbers, headings
+
+ ### list_documents(limit=10, offset=0) -> list[dict]
+ List available documents in the knowledge base.
+ Returns list of dicts with keys: id, title, uri, created_at
+
+ ### get_document(id_or_title) -> str | None
+ Get the full text content of a document by ID, title, or URI.
+ Returns the document content as a string, or None if not found.
+
+ ### get_docling_document(id_or_title) -> DoclingDocument | None
+ Get the structured DoclingDocument object for advanced analysis.
+ Returns a DoclingDocument object, or None if not found.
+ See "DoclingDocument API" section below for how to use it.
+
+ ### ask(question) -> str
+ Ask a question using the QA agent with RAG. Returns the answer as a string.
+ Use this for semantic analysis that benefits from LLM reasoning.
+
+ ## Standard Library Modules
+ You can import: json, re, collections, math, statistics, itertools, functools, datetime, typing
+
+ ## Strategy Guide
+
+ 1. **Explore First**: Start by listing documents or searching to understand what's available. Document names may differ from filenames (e.g., "tbmed593.pdf" might be stored as "TB MED 593" or similar).
+ 2. **If get_document returns None**: Use `list_documents()` to see actual document titles, or `search()` to find relevant content.
+ 3. **Iterative Refinement**: Run code, examine results, adjust your approach based on what you find.
+ 4. **Use print() Liberally**: The REPL captures stdout - print intermediate results to see what you're working with.
+ 5. **Aggregate with Code**: For counting, averaging, or comparing across documents, write loops and use collections.
+ 6. **Use ask() for Semantic Analysis**: When you need to understand meaning or interpret content, use the ask() function.
+ 7. **Cite Your Sources**: Track which documents/chunks informed your answer for citation.
+
+ ## DoclingDocument API
+
+ When you call `get_docling_document(id_or_title)`, you get a DoclingDocument object for structured document analysis.
+
+ ### Properties
+ - `doc.texts` - List of all text items (paragraphs, headings, etc.)
+ - `doc.tables` - List of all tables
+ - `doc.pictures` - List of all pictures/figures
+ - `doc.name` - Document name
+
+ ### Methods
+ - `doc.iterate_items(with_groups=False)` - Iterate all items with hierarchy level
+ Returns tuples of (item, level) where level is nesting depth
+ - `doc.export_to_markdown()` - Export entire document as markdown string
+
+ ### Text Item Properties
+ - `item.text` - The text content
+ - `item.label` - Type: TITLE, PARAGRAPH, SECTION_HEADER, LIST_ITEM, etc.
+ - `item.prov` - Provenance (page numbers, bounding boxes)
+
+ ### Table Access
+ - `table.data.num_rows`, `table.data.num_cols` - Dimensions
+ - `table.data.table_cells` - List of TableCell objects
+ - `cell.text`, `cell.start_row_offset_idx`, `cell.start_col_offset_idx`
+
+ ### Example Usage
+ ```python
+ doc = get_docling_document("My Document")
+
+ # Get all headings
+ headings = [t.text for t in doc.texts if "HEADER" in str(t.label)]
+
+ # Iterate with structure
+ for item, level in doc.iterate_items():
+ print(" " * level + item.text[:50])
+
+ # Extract table data
+ for table in doc.tables:
+ for cell in table.data.table_cells:
+ print(f"Row {cell.start_row_offset_idx}, Col {cell.start_col_offset_idx}: {cell.text}")
+ ```
+
+ ## Example Patterns
+
+ ### Counting documents matching a condition
+ ```python
+ docs = list_documents(limit=100)
+ count = 0
+ for doc in docs:
+ content = get_document(doc['id'])
+ if content and 'keyword' in content.lower():
+ count += 1
+ print(f"Found in: {doc['title']}")
+ print(f"Total: {count}")
+ ```
+
+ ### Aggregating data across documents
+ ```python
+ import re
+ numbers = []
+ results = search("financial data", limit=20)
+ for r in results:
+ matches = re.findall(r'\$([\d,]+)', r['content'])
+ for m in matches:
+ numbers.append(int(m.replace(',', '')))
+ print(f"Average: ${sum(numbers)/len(numbers):,.2f}")
+ ```
+
+ ### Using ask() for semantic analysis
+ ```python
+ # First search to find relevant content
+ results = search("machine learning approaches")
+ # Then use ask() to synthesize an answer
+ summary = ask("What are the main machine learning approaches discussed?")
+ print(summary)
+ ```
+
+ ## Workflow
+
+ 1. **ALWAYS start by using execute_code** to explore the knowledge base
+ 2. Run multiple code blocks as needed to gather information
+ 3. After collecting data, provide your final answer
+
+ ## Output Format
+
+ After executing code and gathering information, provide:
+ 1. A clear answer to the user's question
+ 2. Key findings from your analysis
+ 3. References to specific documents/chunks that informed your answer
+
+ CRITICAL: You MUST call execute_code at least once before providing your answer. Never give up without trying to execute code first.
+ role: system
+ - content: What is the total revenue across all quarterly reports?
+ role: user
+ - content: |-
+
+ We need revenue from quarterly reports. Search for "quarterly report" and revenue.
+
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"results = search(\"quarterly report revenue\", limit=50)\nprint(len(results))\nfor r in results[:5]:\n print(r[''document_title''],
+ r[''score''], r[''page_numbers''])\n"}'
+ name: execute_code
+ id: call_8cd1wnf6
+ type: function
+ - content: '{"code":"results = search(\"quarterly report revenue\", limit=50)\nprint(len(results))\nfor r in results[:5]:\n print(r[''document_title''],
+ r[''score''], r[''page_numbers''])\n","stdout":"3\nQ1 Report 0.03226645663380623 []\nQ2 Report 0.03226645663380623
+ []\nQ3 Report 0.032258063554763794 []\n","stderr":"","success":true}'
+ role: tool
+ tool_call_id: call_8cd1wnf6
+ - content: |-
+
+ We have 3 reports: Q1, Q2, Q3. Likely Q4 also exists. Search again for Q4.
+
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"results = search(\"Q4 Report\", limit=10)\nprint(len(results))\nfor r in results:\n print(r[''document_title''])\n"}'
+ name: execute_code
+ id: call_mgo4t2ty
+ type: function
+ - content: '{"code":"results = search(\"Q4 Report\", limit=10)\nprint(len(results))\nfor r in results:\n print(r[''document_title''])\n","stdout":"3\nQ1
+ Report\nQ2 Report\nQ3 Report\n","stderr":"","success":true}'
+ role: tool
+ tool_call_id: call_mgo4t2ty
+ model: gpt-oss
+ reasoning_effort: low
+ stream: false
+ tool_choice: auto
+ tools:
+ - function:
+ description: |-
+ Execute Python code in the sandboxed environment.
+
+ The code has access to haiku.rag functions (search, list_documents,
+ get_document, get_docling_document, ask) and safe standard library
+ modules (json, re, collections, math, statistics, itertools,
+ functools, datetime, typing).
+
+ Use print() to output results. Variables persist between executions.
+
+ Structured result with success status, stdout, and stderr.
+
+ name: execute_code
+ parameters:
+ additionalProperties: false
+ properties:
+ code:
+ description: Python code to execute.
+ type: string
+ required:
+ - code
+ type: object
+ strict: true
+ type: function
+ - function:
+ description: Result from RLM agent execution.
+ name: final_result
+ parameters:
+ $defs:
+ CodeExecution:
+ additionalProperties: false
+ description: Result of executing a code block in the RLM sandbox.
+ properties:
+ code:
+ description: The Python code that was executed
+ type: string
+ stderr:
+ description: Standard error captured during execution
+ type: string
+ stdout:
+ description: Standard output captured during execution
+ type: string
+ success:
+ description: Whether execution completed without error
+ type: boolean
+ required:
+ - code
+ - stdout
+ - stderr
+ - success
+ type: object
+ additionalProperties: false
+ properties:
+ answer:
+ description: The answer to the user's question
+ type: string
+ code_executions:
+ description: History of code executions during the RLM session
+ items:
+ $ref: '#/$defs/CodeExecution'
+ type: array
+ required:
+ - answer
+ type: object
+ type: function
+ uri: http://localhost:11434/v1/chat/completions
+ response:
+ headers:
+ content-length:
+ - '663'
+ content-type:
+ - application/json
+ parsed_body:
+ choices:
+ - finish_reason: tool_calls
+ index: 0
+ message:
+ content: ''
+ reasoning: All quarterly reports 1-3 only? Maybe Q4 is in separate doc. Search “Quarterly Report 4”.
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"results = search(\"Quarterly Report 4\", limit=10)\nprint(len(results))\nfor r in results:\n print(r[''document_title''])\n"}'
+ name: execute_code
+ id: call_3d3jutqn
+ index: 0
+ type: function
+ created: 1769703359
+ id: chatcmpl-718
+ model: gpt-oss
+ object: chat.completion
+ system_fingerprint: fp_ollama
+ usage:
+ completion_tokens: 84
+ prompt_tokens: 1975
+ total_tokens: 2059
+ status:
+ code: 200
+ message: OK
+- request:
+ headers:
+ accept:
+ - application/json
+ accept-encoding:
+ - gzip, deflate, zstd
+ connection:
+ - keep-alive
+ content-length:
+ - '88'
+ content-type:
+ - application/json
+ host:
+ - localhost:11434
+ method: POST
+ parsed_body:
+ encoding_format: base64
+ input:
+ - Quarterly Report 4
+ model: qwen3-embedding:4b
+ uri: http://localhost:11434/v1/embeddings
+ response:
+ headers:
+ content-type:
+ - application/json
+ transfer-encoding:
+ - chunked
+ parsed_body:
+ data:
+ - embedding: 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
+ index: 0
+ object: embedding
+ model: qwen3-embedding:4b
+ object: list
+ usage:
+ prompt_tokens: 6
+ total_tokens: 6
+ status:
+ code: 200
+ message: OK
+- request:
+ headers:
+ accept:
+ - application/json
+ accept-encoding:
+ - gzip, deflate, zstd
+ connection:
+ - keep-alive
+ content-length:
+ - '9893'
+ content-type:
+ - application/json
+ host:
+ - localhost:11434
+ method: POST
+ parsed_body:
+ messages:
+ - content: |-
+ You are a Recursive Language Model (RLM) agent that solves complex research questions by writing and executing Python code.
+
+ IMPORTANT: You MUST use the `execute_code` tool to run Python code. The functions described below are ONLY available inside the execute_code tool - you cannot access them any other way. Always execute code to answer questions; do not just describe what code would do.
+
+ CRITICAL: Inside execute_code, these functions are ALREADY available in the namespace. Do NOT import them - just use them directly:
+ - search("query") ✓ CORRECT
+ - from haiku.rag import search ✗ WRONG - will fail
+
+ You have access to a sandboxed Python environment with these haiku.rag functions (use them directly, no imports needed):
+
+ ## Available Functions
+
+ ### search(query, limit=10) -> list[dict]
+ Search the knowledge base using hybrid search (vector + full-text).
+ Returns list of dicts with keys: chunk_id, content, document_id, document_title, document_uri, score, page_numbers, headings
+
+ ### list_documents(limit=10, offset=0) -> list[dict]
+ List available documents in the knowledge base.
+ Returns list of dicts with keys: id, title, uri, created_at
+
+ ### get_document(id_or_title) -> str | None
+ Get the full text content of a document by ID, title, or URI.
+ Returns the document content as a string, or None if not found.
+
+ ### get_docling_document(id_or_title) -> DoclingDocument | None
+ Get the structured DoclingDocument object for advanced analysis.
+ Returns a DoclingDocument object, or None if not found.
+ See "DoclingDocument API" section below for how to use it.
+
+ ### ask(question) -> str
+ Ask a question using the QA agent with RAG. Returns the answer as a string.
+ Use this for semantic analysis that benefits from LLM reasoning.
+
+ ## Standard Library Modules
+ You can import: json, re, collections, math, statistics, itertools, functools, datetime, typing
+
+ ## Strategy Guide
+
+ 1. **Explore First**: Start by listing documents or searching to understand what's available. Document names may differ from filenames (e.g., "tbmed593.pdf" might be stored as "TB MED 593" or similar).
+ 2. **If get_document returns None**: Use `list_documents()` to see actual document titles, or `search()` to find relevant content.
+ 3. **Iterative Refinement**: Run code, examine results, adjust your approach based on what you find.
+ 4. **Use print() Liberally**: The REPL captures stdout - print intermediate results to see what you're working with.
+ 5. **Aggregate with Code**: For counting, averaging, or comparing across documents, write loops and use collections.
+ 6. **Use ask() for Semantic Analysis**: When you need to understand meaning or interpret content, use the ask() function.
+ 7. **Cite Your Sources**: Track which documents/chunks informed your answer for citation.
+
+ ## DoclingDocument API
+
+ When you call `get_docling_document(id_or_title)`, you get a DoclingDocument object for structured document analysis.
+
+ ### Properties
+ - `doc.texts` - List of all text items (paragraphs, headings, etc.)
+ - `doc.tables` - List of all tables
+ - `doc.pictures` - List of all pictures/figures
+ - `doc.name` - Document name
+
+ ### Methods
+ - `doc.iterate_items(with_groups=False)` - Iterate all items with hierarchy level
+ Returns tuples of (item, level) where level is nesting depth
+ - `doc.export_to_markdown()` - Export entire document as markdown string
+
+ ### Text Item Properties
+ - `item.text` - The text content
+ - `item.label` - Type: TITLE, PARAGRAPH, SECTION_HEADER, LIST_ITEM, etc.
+ - `item.prov` - Provenance (page numbers, bounding boxes)
+
+ ### Table Access
+ - `table.data.num_rows`, `table.data.num_cols` - Dimensions
+ - `table.data.table_cells` - List of TableCell objects
+ - `cell.text`, `cell.start_row_offset_idx`, `cell.start_col_offset_idx`
+
+ ### Example Usage
+ ```python
+ doc = get_docling_document("My Document")
+
+ # Get all headings
+ headings = [t.text for t in doc.texts if "HEADER" in str(t.label)]
+
+ # Iterate with structure
+ for item, level in doc.iterate_items():
+ print(" " * level + item.text[:50])
+
+ # Extract table data
+ for table in doc.tables:
+ for cell in table.data.table_cells:
+ print(f"Row {cell.start_row_offset_idx}, Col {cell.start_col_offset_idx}: {cell.text}")
+ ```
+
+ ## Example Patterns
+
+ ### Counting documents matching a condition
+ ```python
+ docs = list_documents(limit=100)
+ count = 0
+ for doc in docs:
+ content = get_document(doc['id'])
+ if content and 'keyword' in content.lower():
+ count += 1
+ print(f"Found in: {doc['title']}")
+ print(f"Total: {count}")
+ ```
+
+ ### Aggregating data across documents
+ ```python
+ import re
+ numbers = []
+ results = search("financial data", limit=20)
+ for r in results:
+ matches = re.findall(r'\$([\d,]+)', r['content'])
+ for m in matches:
+ numbers.append(int(m.replace(',', '')))
+ print(f"Average: ${sum(numbers)/len(numbers):,.2f}")
+ ```
+
+ ### Using ask() for semantic analysis
+ ```python
+ # First search to find relevant content
+ results = search("machine learning approaches")
+ # Then use ask() to synthesize an answer
+ summary = ask("What are the main machine learning approaches discussed?")
+ print(summary)
+ ```
+
+ ## Workflow
+
+ 1. **ALWAYS start by using execute_code** to explore the knowledge base
+ 2. Run multiple code blocks as needed to gather information
+ 3. After collecting data, provide your final answer
+
+ ## Output Format
+
+ After executing code and gathering information, provide:
+ 1. A clear answer to the user's question
+ 2. Key findings from your analysis
+ 3. References to specific documents/chunks that informed your answer
+
+ CRITICAL: You MUST call execute_code at least once before providing your answer. Never give up without trying to execute code first.
+ role: system
+ - content: What is the total revenue across all quarterly reports?
+ role: user
+ - content: |-
+
+ We need revenue from quarterly reports. Search for "quarterly report" and revenue.
+
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"results = search(\"quarterly report revenue\", limit=50)\nprint(len(results))\nfor r in results[:5]:\n print(r[''document_title''],
+ r[''score''], r[''page_numbers''])\n"}'
+ name: execute_code
+ id: call_8cd1wnf6
+ type: function
+ - content: '{"code":"results = search(\"quarterly report revenue\", limit=50)\nprint(len(results))\nfor r in results[:5]:\n print(r[''document_title''],
+ r[''score''], r[''page_numbers''])\n","stdout":"3\nQ1 Report 0.03226645663380623 []\nQ2 Report 0.03226645663380623
+ []\nQ3 Report 0.032258063554763794 []\n","stderr":"","success":true}'
+ role: tool
+ tool_call_id: call_8cd1wnf6
+ - content: |-
+
+ We have 3 reports: Q1, Q2, Q3. Likely Q4 also exists. Search again for Q4.
+
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"results = search(\"Q4 Report\", limit=10)\nprint(len(results))\nfor r in results:\n print(r[''document_title''])\n"}'
+ name: execute_code
+ id: call_mgo4t2ty
+ type: function
+ - content: '{"code":"results = search(\"Q4 Report\", limit=10)\nprint(len(results))\nfor r in results:\n print(r[''document_title''])\n","stdout":"3\nQ1
+ Report\nQ2 Report\nQ3 Report\n","stderr":"","success":true}'
+ role: tool
+ tool_call_id: call_mgo4t2ty
+ - content: |-
+
+ All quarterly reports 1-3 only? Maybe Q4 is in separate doc. Search “Quarterly Report 4”.
+
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"results = search(\"Quarterly Report 4\", limit=10)\nprint(len(results))\nfor r in results:\n print(r[''document_title''])\n"}'
+ name: execute_code
+ id: call_3d3jutqn
+ type: function
+ - content: '{"code":"results = search(\"Quarterly Report 4\", limit=10)\nprint(len(results))\nfor r in results:\n print(r[''document_title''])\n","stdout":"3\nQ1
+ Report\nQ2 Report\nQ3 Report\n","stderr":"","success":true}'
+ role: tool
+ tool_call_id: call_3d3jutqn
+ model: gpt-oss
+ reasoning_effort: low
+ stream: false
+ tool_choice: auto
+ tools:
+ - function:
+ description: |-
+ Execute Python code in the sandboxed environment.
+
+ The code has access to haiku.rag functions (search, list_documents,
+ get_document, get_docling_document, ask) and safe standard library
+ modules (json, re, collections, math, statistics, itertools,
+ functools, datetime, typing).
+
+ Use print() to output results. Variables persist between executions.
+
+ Structured result with success status, stdout, and stderr.
+
+ name: execute_code
+ parameters:
+ additionalProperties: false
+ properties:
+ code:
+ description: Python code to execute.
+ type: string
+ required:
+ - code
+ type: object
+ strict: true
+ type: function
+ - function:
+ description: Result from RLM agent execution.
+ name: final_result
+ parameters:
+ $defs:
+ CodeExecution:
+ additionalProperties: false
+ description: Result of executing a code block in the RLM sandbox.
+ properties:
+ code:
+ description: The Python code that was executed
+ type: string
+ stderr:
+ description: Standard error captured during execution
+ type: string
+ stdout:
+ description: Standard output captured during execution
+ type: string
+ success:
+ description: Whether execution completed without error
+ type: boolean
+ required:
+ - code
+ - stdout
+ - stderr
+ - success
+ type: object
+ additionalProperties: false
+ properties:
+ answer:
+ description: The answer to the user's question
+ type: string
+ code_executions:
+ description: History of code executions during the RLM session
+ items:
+ $ref: '#/$defs/CodeExecution'
+ type: array
+ required:
+ - answer
+ type: object
+ type: function
+ uri: http://localhost:11434/v1/chat/completions
+ response:
+ headers:
+ content-length:
+ - '1144'
+ content-type:
+ - application/json
+ parsed_body:
+ choices:
+ - finish_reason: tool_calls
+ index: 0
+ message:
+ content: |-
+
+ It appears only Q1‑Q3 reports are present in the index. We need revenue figures from each. We'll retrieve the full text of each report and extract numbers labeled “Revenue”.
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"docs = [''Q1 Report'', ''Q2 Report'', ''Q3 Report'']\nrevenues = {}\nimport re\nfor d in
+ docs:\n content = get_document(d)\n if content:\n # Find revenue lines\n matches = re.findall(r''Revenue.*?:\\s*\\$([\\d,\\.]+)'',
+ content, re.IGNORECASE)\n if matches:\n # take first match\n rev = float(matches[0].replace('','',''''))\n revenues[d]
+ = rev\n else:\n revenues[d] = None\n else:\n revenues[d] = None\nprint(revenues)\n"}'
+ name: execute_code
+ id: call_2rg8jz4m
+ index: 0
+ type: function
+ created: 1769703364
+ id: chatcmpl-874
+ model: gpt-oss
+ object: chat.completion
+ system_fingerprint: fp_ollama
+ usage:
+ completion_tokens: 204
+ prompt_tokens: 2139
+ total_tokens: 2343
+ status:
+ code: 200
+ message: OK
+- request:
+ headers:
+ accept:
+ - application/json
+ accept-encoding:
+ - gzip, deflate, zstd
+ connection:
+ - keep-alive
+ content-length:
+ - '11457'
+ content-type:
+ - application/json
+ host:
+ - localhost:11434
+ method: POST
+ parsed_body:
+ messages:
+ - content: |-
+ You are a Recursive Language Model (RLM) agent that solves complex research questions by writing and executing Python code.
+
+ IMPORTANT: You MUST use the `execute_code` tool to run Python code. The functions described below are ONLY available inside the execute_code tool - you cannot access them any other way. Always execute code to answer questions; do not just describe what code would do.
+
+ CRITICAL: Inside execute_code, these functions are ALREADY available in the namespace. Do NOT import them - just use them directly:
+ - search("query") ✓ CORRECT
+ - from haiku.rag import search ✗ WRONG - will fail
+
+ You have access to a sandboxed Python environment with these haiku.rag functions (use them directly, no imports needed):
+
+ ## Available Functions
+
+ ### search(query, limit=10) -> list[dict]
+ Search the knowledge base using hybrid search (vector + full-text).
+ Returns list of dicts with keys: chunk_id, content, document_id, document_title, document_uri, score, page_numbers, headings
+
+ ### list_documents(limit=10, offset=0) -> list[dict]
+ List available documents in the knowledge base.
+ Returns list of dicts with keys: id, title, uri, created_at
+
+ ### get_document(id_or_title) -> str | None
+ Get the full text content of a document by ID, title, or URI.
+ Returns the document content as a string, or None if not found.
+
+ ### get_docling_document(id_or_title) -> DoclingDocument | None
+ Get the structured DoclingDocument object for advanced analysis.
+ Returns a DoclingDocument object, or None if not found.
+ See "DoclingDocument API" section below for how to use it.
+
+ ### ask(question) -> str
+ Ask a question using the QA agent with RAG. Returns the answer as a string.
+ Use this for semantic analysis that benefits from LLM reasoning.
+
+ ## Standard Library Modules
+ You can import: json, re, collections, math, statistics, itertools, functools, datetime, typing
+
+ ## Strategy Guide
+
+ 1. **Explore First**: Start by listing documents or searching to understand what's available. Document names may differ from filenames (e.g., "tbmed593.pdf" might be stored as "TB MED 593" or similar).
+ 2. **If get_document returns None**: Use `list_documents()` to see actual document titles, or `search()` to find relevant content.
+ 3. **Iterative Refinement**: Run code, examine results, adjust your approach based on what you find.
+ 4. **Use print() Liberally**: The REPL captures stdout - print intermediate results to see what you're working with.
+ 5. **Aggregate with Code**: For counting, averaging, or comparing across documents, write loops and use collections.
+ 6. **Use ask() for Semantic Analysis**: When you need to understand meaning or interpret content, use the ask() function.
+ 7. **Cite Your Sources**: Track which documents/chunks informed your answer for citation.
+
+ ## DoclingDocument API
+
+ When you call `get_docling_document(id_or_title)`, you get a DoclingDocument object for structured document analysis.
+
+ ### Properties
+ - `doc.texts` - List of all text items (paragraphs, headings, etc.)
+ - `doc.tables` - List of all tables
+ - `doc.pictures` - List of all pictures/figures
+ - `doc.name` - Document name
+
+ ### Methods
+ - `doc.iterate_items(with_groups=False)` - Iterate all items with hierarchy level
+ Returns tuples of (item, level) where level is nesting depth
+ - `doc.export_to_markdown()` - Export entire document as markdown string
+
+ ### Text Item Properties
+ - `item.text` - The text content
+ - `item.label` - Type: TITLE, PARAGRAPH, SECTION_HEADER, LIST_ITEM, etc.
+ - `item.prov` - Provenance (page numbers, bounding boxes)
+
+ ### Table Access
+ - `table.data.num_rows`, `table.data.num_cols` - Dimensions
+ - `table.data.table_cells` - List of TableCell objects
+ - `cell.text`, `cell.start_row_offset_idx`, `cell.start_col_offset_idx`
+
+ ### Example Usage
+ ```python
+ doc = get_docling_document("My Document")
+
+ # Get all headings
+ headings = [t.text for t in doc.texts if "HEADER" in str(t.label)]
+
+ # Iterate with structure
+ for item, level in doc.iterate_items():
+ print(" " * level + item.text[:50])
+
+ # Extract table data
+ for table in doc.tables:
+ for cell in table.data.table_cells:
+ print(f"Row {cell.start_row_offset_idx}, Col {cell.start_col_offset_idx}: {cell.text}")
+ ```
+
+ ## Example Patterns
+
+ ### Counting documents matching a condition
+ ```python
+ docs = list_documents(limit=100)
+ count = 0
+ for doc in docs:
+ content = get_document(doc['id'])
+ if content and 'keyword' in content.lower():
+ count += 1
+ print(f"Found in: {doc['title']}")
+ print(f"Total: {count}")
+ ```
+
+ ### Aggregating data across documents
+ ```python
+ import re
+ numbers = []
+ results = search("financial data", limit=20)
+ for r in results:
+ matches = re.findall(r'\$([\d,]+)', r['content'])
+ for m in matches:
+ numbers.append(int(m.replace(',', '')))
+ print(f"Average: ${sum(numbers)/len(numbers):,.2f}")
+ ```
+
+ ### Using ask() for semantic analysis
+ ```python
+ # First search to find relevant content
+ results = search("machine learning approaches")
+ # Then use ask() to synthesize an answer
+ summary = ask("What are the main machine learning approaches discussed?")
+ print(summary)
+ ```
+
+ ## Workflow
+
+ 1. **ALWAYS start by using execute_code** to explore the knowledge base
+ 2. Run multiple code blocks as needed to gather information
+ 3. After collecting data, provide your final answer
+
+ ## Output Format
+
+ After executing code and gathering information, provide:
+ 1. A clear answer to the user's question
+ 2. Key findings from your analysis
+ 3. References to specific documents/chunks that informed your answer
+
+ CRITICAL: You MUST call execute_code at least once before providing your answer. Never give up without trying to execute code first.
+ role: system
+ - content: What is the total revenue across all quarterly reports?
+ role: user
+ - content: |-
+
+ We need revenue from quarterly reports. Search for "quarterly report" and revenue.
+
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"results = search(\"quarterly report revenue\", limit=50)\nprint(len(results))\nfor r in results[:5]:\n print(r[''document_title''],
+ r[''score''], r[''page_numbers''])\n"}'
+ name: execute_code
+ id: call_8cd1wnf6
+ type: function
+ - content: '{"code":"results = search(\"quarterly report revenue\", limit=50)\nprint(len(results))\nfor r in results[:5]:\n print(r[''document_title''],
+ r[''score''], r[''page_numbers''])\n","stdout":"3\nQ1 Report 0.03226645663380623 []\nQ2 Report 0.03226645663380623
+ []\nQ3 Report 0.032258063554763794 []\n","stderr":"","success":true}'
+ role: tool
+ tool_call_id: call_8cd1wnf6
+ - content: |-
+
+ We have 3 reports: Q1, Q2, Q3. Likely Q4 also exists. Search again for Q4.
+
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"results = search(\"Q4 Report\", limit=10)\nprint(len(results))\nfor r in results:\n print(r[''document_title''])\n"}'
+ name: execute_code
+ id: call_mgo4t2ty
+ type: function
+ - content: '{"code":"results = search(\"Q4 Report\", limit=10)\nprint(len(results))\nfor r in results:\n print(r[''document_title''])\n","stdout":"3\nQ1
+ Report\nQ2 Report\nQ3 Report\n","stderr":"","success":true}'
+ role: tool
+ tool_call_id: call_mgo4t2ty
+ - content: |-
+
+ All quarterly reports 1-3 only? Maybe Q4 is in separate doc. Search “Quarterly Report 4”.
+
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"results = search(\"Quarterly Report 4\", limit=10)\nprint(len(results))\nfor r in results:\n print(r[''document_title''])\n"}'
+ name: execute_code
+ id: call_3d3jutqn
+ type: function
+ - content: '{"code":"results = search(\"Quarterly Report 4\", limit=10)\nprint(len(results))\nfor r in results:\n print(r[''document_title''])\n","stdout":"3\nQ1
+ Report\nQ2 Report\nQ3 Report\n","stderr":"","success":true}'
+ role: tool
+ tool_call_id: call_3d3jutqn
+ - content: |2-
+
+ It appears only Q1‑Q3 reports are present in the index. We need revenue figures from each. We'll retrieve the full text of each report and extract numbers labeled “Revenue”.
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"docs = [''Q1 Report'', ''Q2 Report'', ''Q3 Report'']\nrevenues = {}\nimport re\nfor d in
+ docs:\n content = get_document(d)\n if content:\n # Find revenue lines\n matches = re.findall(r''Revenue.*?:\\s*\\$([\\d,\\.]+)'',
+ content, re.IGNORECASE)\n if matches:\n # take first match\n rev = float(matches[0].replace('','',''''))\n revenues[d]
+ = rev\n else:\n revenues[d] = None\n else:\n revenues[d] = None\nprint(revenues)\n"}'
+ name: execute_code
+ id: call_2rg8jz4m
+ type: function
+ - content: '{"code":"docs = [''Q1 Report'', ''Q2 Report'', ''Q3 Report'']\nrevenues = {}\nimport re\nfor d in docs:\n content
+ = get_document(d)\n if content:\n # Find revenue lines\n matches = re.findall(r''Revenue.*?:\\s*\\$([\\d,\\.]+)'',
+ content, re.IGNORECASE)\n if matches:\n # take first match\n rev = float(matches[0].replace('','',''''))\n revenues[d]
+ = rev\n else:\n revenues[d] = None\n else:\n revenues[d] = None\nprint(revenues)\n","stdout":"{''Q1
+ Report'': None, ''Q2 Report'': None, ''Q3 Report'': None}\n","stderr":"","success":true}'
+ role: tool
+ tool_call_id: call_2rg8jz4m
+ model: gpt-oss
+ reasoning_effort: low
+ stream: false
+ tool_choice: auto
+ tools:
+ - function:
+ description: |-
+ Execute Python code in the sandboxed environment.
+
+ The code has access to haiku.rag functions (search, list_documents,
+ get_document, get_docling_document, ask) and safe standard library
+ modules (json, re, collections, math, statistics, itertools,
+ functools, datetime, typing).
+
+ Use print() to output results. Variables persist between executions.
+
+ Structured result with success status, stdout, and stderr.
+
+ name: execute_code
+ parameters:
+ additionalProperties: false
+ properties:
+ code:
+ description: Python code to execute.
+ type: string
+ required:
+ - code
+ type: object
+ strict: true
+ type: function
+ - function:
+ description: Result from RLM agent execution.
+ name: final_result
+ parameters:
+ $defs:
+ CodeExecution:
+ additionalProperties: false
+ description: Result of executing a code block in the RLM sandbox.
+ properties:
+ code:
+ description: The Python code that was executed
+ type: string
+ stderr:
+ description: Standard error captured during execution
+ type: string
+ stdout:
+ description: Standard output captured during execution
+ type: string
+ success:
+ description: Whether execution completed without error
+ type: boolean
+ required:
+ - code
+ - stdout
+ - stderr
+ - success
+ type: object
+ additionalProperties: false
+ properties:
+ answer:
+ description: The answer to the user's question
+ type: string
+ code_executions:
+ description: History of code executions during the RLM session
+ items:
+ $ref: '#/$defs/CodeExecution'
+ type: array
+ required:
+ - answer
+ type: object
+ type: function
+ uri: http://localhost:11434/v1/chat/completions
+ response:
+ headers:
+ content-length:
+ - '558'
+ content-type:
+ - application/json
+ parsed_body:
+ choices:
+ - finish_reason: tool_calls
+ index: 0
+ message:
+ content: ''
+ reasoning: No revenue found by pattern. Let's inspect content snippet.
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"content = get_document(''Q1 Report'')\nprint(content[:500])\n"}'
+ name: execute_code
+ id: call_oqz8cbe0
+ index: 0
+ type: function
+ created: 1769703365
+ id: chatcmpl-151
+ model: gpt-oss
+ object: chat.completion
+ system_fingerprint: fp_ollama
+ usage:
+ completion_tokens: 52
+ prompt_tokens: 2528
+ total_tokens: 2580
+ status:
+ code: 200
+ message: OK
+- request:
+ headers:
+ accept:
+ - application/json
+ accept-encoding:
+ - gzip, deflate, zstd
+ connection:
+ - keep-alive
+ content-length:
+ - '11977'
+ content-type:
+ - application/json
+ host:
+ - localhost:11434
+ method: POST
+ parsed_body:
+ messages:
+ - content: |-
+ You are a Recursive Language Model (RLM) agent that solves complex research questions by writing and executing Python code.
+
+ IMPORTANT: You MUST use the `execute_code` tool to run Python code. The functions described below are ONLY available inside the execute_code tool - you cannot access them any other way. Always execute code to answer questions; do not just describe what code would do.
+
+ CRITICAL: Inside execute_code, these functions are ALREADY available in the namespace. Do NOT import them - just use them directly:
+ - search("query") ✓ CORRECT
+ - from haiku.rag import search ✗ WRONG - will fail
+
+ You have access to a sandboxed Python environment with these haiku.rag functions (use them directly, no imports needed):
+
+ ## Available Functions
+
+ ### search(query, limit=10) -> list[dict]
+ Search the knowledge base using hybrid search (vector + full-text).
+ Returns list of dicts with keys: chunk_id, content, document_id, document_title, document_uri, score, page_numbers, headings
+
+ ### list_documents(limit=10, offset=0) -> list[dict]
+ List available documents in the knowledge base.
+ Returns list of dicts with keys: id, title, uri, created_at
+
+ ### get_document(id_or_title) -> str | None
+ Get the full text content of a document by ID, title, or URI.
+ Returns the document content as a string, or None if not found.
+
+ ### get_docling_document(id_or_title) -> DoclingDocument | None
+ Get the structured DoclingDocument object for advanced analysis.
+ Returns a DoclingDocument object, or None if not found.
+ See "DoclingDocument API" section below for how to use it.
+
+ ### ask(question) -> str
+ Ask a question using the QA agent with RAG. Returns the answer as a string.
+ Use this for semantic analysis that benefits from LLM reasoning.
+
+ ## Standard Library Modules
+ You can import: json, re, collections, math, statistics, itertools, functools, datetime, typing
+
+ ## Strategy Guide
+
+ 1. **Explore First**: Start by listing documents or searching to understand what's available. Document names may differ from filenames (e.g., "tbmed593.pdf" might be stored as "TB MED 593" or similar).
+ 2. **If get_document returns None**: Use `list_documents()` to see actual document titles, or `search()` to find relevant content.
+ 3. **Iterative Refinement**: Run code, examine results, adjust your approach based on what you find.
+ 4. **Use print() Liberally**: The REPL captures stdout - print intermediate results to see what you're working with.
+ 5. **Aggregate with Code**: For counting, averaging, or comparing across documents, write loops and use collections.
+ 6. **Use ask() for Semantic Analysis**: When you need to understand meaning or interpret content, use the ask() function.
+ 7. **Cite Your Sources**: Track which documents/chunks informed your answer for citation.
+
+ ## DoclingDocument API
+
+ When you call `get_docling_document(id_or_title)`, you get a DoclingDocument object for structured document analysis.
+
+ ### Properties
+ - `doc.texts` - List of all text items (paragraphs, headings, etc.)
+ - `doc.tables` - List of all tables
+ - `doc.pictures` - List of all pictures/figures
+ - `doc.name` - Document name
+
+ ### Methods
+ - `doc.iterate_items(with_groups=False)` - Iterate all items with hierarchy level
+ Returns tuples of (item, level) where level is nesting depth
+ - `doc.export_to_markdown()` - Export entire document as markdown string
+
+ ### Text Item Properties
+ - `item.text` - The text content
+ - `item.label` - Type: TITLE, PARAGRAPH, SECTION_HEADER, LIST_ITEM, etc.
+ - `item.prov` - Provenance (page numbers, bounding boxes)
+
+ ### Table Access
+ - `table.data.num_rows`, `table.data.num_cols` - Dimensions
+ - `table.data.table_cells` - List of TableCell objects
+ - `cell.text`, `cell.start_row_offset_idx`, `cell.start_col_offset_idx`
+
+ ### Example Usage
+ ```python
+ doc = get_docling_document("My Document")
+
+ # Get all headings
+ headings = [t.text for t in doc.texts if "HEADER" in str(t.label)]
+
+ # Iterate with structure
+ for item, level in doc.iterate_items():
+ print(" " * level + item.text[:50])
+
+ # Extract table data
+ for table in doc.tables:
+ for cell in table.data.table_cells:
+ print(f"Row {cell.start_row_offset_idx}, Col {cell.start_col_offset_idx}: {cell.text}")
+ ```
+
+ ## Example Patterns
+
+ ### Counting documents matching a condition
+ ```python
+ docs = list_documents(limit=100)
+ count = 0
+ for doc in docs:
+ content = get_document(doc['id'])
+ if content and 'keyword' in content.lower():
+ count += 1
+ print(f"Found in: {doc['title']}")
+ print(f"Total: {count}")
+ ```
+
+ ### Aggregating data across documents
+ ```python
+ import re
+ numbers = []
+ results = search("financial data", limit=20)
+ for r in results:
+ matches = re.findall(r'\$([\d,]+)', r['content'])
+ for m in matches:
+ numbers.append(int(m.replace(',', '')))
+ print(f"Average: ${sum(numbers)/len(numbers):,.2f}")
+ ```
+
+ ### Using ask() for semantic analysis
+ ```python
+ # First search to find relevant content
+ results = search("machine learning approaches")
+ # Then use ask() to synthesize an answer
+ summary = ask("What are the main machine learning approaches discussed?")
+ print(summary)
+ ```
+
+ ## Workflow
+
+ 1. **ALWAYS start by using execute_code** to explore the knowledge base
+ 2. Run multiple code blocks as needed to gather information
+ 3. After collecting data, provide your final answer
+
+ ## Output Format
+
+ After executing code and gathering information, provide:
+ 1. A clear answer to the user's question
+ 2. Key findings from your analysis
+ 3. References to specific documents/chunks that informed your answer
+
+ CRITICAL: You MUST call execute_code at least once before providing your answer. Never give up without trying to execute code first.
+ role: system
+ - content: What is the total revenue across all quarterly reports?
+ role: user
+ - content: |-
+
+ We need revenue from quarterly reports. Search for "quarterly report" and revenue.
+
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"results = search(\"quarterly report revenue\", limit=50)\nprint(len(results))\nfor r in results[:5]:\n print(r[''document_title''],
+ r[''score''], r[''page_numbers''])\n"}'
+ name: execute_code
+ id: call_8cd1wnf6
+ type: function
+ - content: '{"code":"results = search(\"quarterly report revenue\", limit=50)\nprint(len(results))\nfor r in results[:5]:\n print(r[''document_title''],
+ r[''score''], r[''page_numbers''])\n","stdout":"3\nQ1 Report 0.03226645663380623 []\nQ2 Report 0.03226645663380623
+ []\nQ3 Report 0.032258063554763794 []\n","stderr":"","success":true}'
+ role: tool
+ tool_call_id: call_8cd1wnf6
+ - content: |-
+
+ We have 3 reports: Q1, Q2, Q3. Likely Q4 also exists. Search again for Q4.
+
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"results = search(\"Q4 Report\", limit=10)\nprint(len(results))\nfor r in results:\n print(r[''document_title''])\n"}'
+ name: execute_code
+ id: call_mgo4t2ty
+ type: function
+ - content: '{"code":"results = search(\"Q4 Report\", limit=10)\nprint(len(results))\nfor r in results:\n print(r[''document_title''])\n","stdout":"3\nQ1
+ Report\nQ2 Report\nQ3 Report\n","stderr":"","success":true}'
+ role: tool
+ tool_call_id: call_mgo4t2ty
+ - content: |-
+
+ All quarterly reports 1-3 only? Maybe Q4 is in separate doc. Search “Quarterly Report 4”.
+
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"results = search(\"Quarterly Report 4\", limit=10)\nprint(len(results))\nfor r in results:\n print(r[''document_title''])\n"}'
+ name: execute_code
+ id: call_3d3jutqn
+ type: function
+ - content: '{"code":"results = search(\"Quarterly Report 4\", limit=10)\nprint(len(results))\nfor r in results:\n print(r[''document_title''])\n","stdout":"3\nQ1
+ Report\nQ2 Report\nQ3 Report\n","stderr":"","success":true}'
+ role: tool
+ tool_call_id: call_3d3jutqn
+ - content: |2-
+
+ It appears only Q1‑Q3 reports are present in the index. We need revenue figures from each. We'll retrieve the full text of each report and extract numbers labeled “Revenue”.
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"docs = [''Q1 Report'', ''Q2 Report'', ''Q3 Report'']\nrevenues = {}\nimport re\nfor d in
+ docs:\n content = get_document(d)\n if content:\n # Find revenue lines\n matches = re.findall(r''Revenue.*?:\\s*\\$([\\d,\\.]+)'',
+ content, re.IGNORECASE)\n if matches:\n # take first match\n rev = float(matches[0].replace('','',''''))\n revenues[d]
+ = rev\n else:\n revenues[d] = None\n else:\n revenues[d] = None\nprint(revenues)\n"}'
+ name: execute_code
+ id: call_2rg8jz4m
+ type: function
+ - content: '{"code":"docs = [''Q1 Report'', ''Q2 Report'', ''Q3 Report'']\nrevenues = {}\nimport re\nfor d in docs:\n content
+ = get_document(d)\n if content:\n # Find revenue lines\n matches = re.findall(r''Revenue.*?:\\s*\\$([\\d,\\.]+)'',
+ content, re.IGNORECASE)\n if matches:\n # take first match\n rev = float(matches[0].replace('','',''''))\n revenues[d]
+ = rev\n else:\n revenues[d] = None\n else:\n revenues[d] = None\nprint(revenues)\n","stdout":"{''Q1
+ Report'': None, ''Q2 Report'': None, ''Q3 Report'': None}\n","stderr":"","success":true}'
+ role: tool
+ tool_call_id: call_2rg8jz4m
+ - content: |-
+
+ No revenue found by pattern. Let's inspect content snippet.
+
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"content = get_document(''Q1 Report'')\nprint(content[:500])\n"}'
+ name: execute_code
+ id: call_oqz8cbe0
+ type: function
+ - content: '{"code":"content = get_document(''Q1 Report'')\nprint(content[:500])\n","stdout":"Sales report Q1: Revenue
+ was $100,000.\n","stderr":"","success":true}'
+ role: tool
+ tool_call_id: call_oqz8cbe0
+ model: gpt-oss
+ reasoning_effort: low
+ stream: false
+ tool_choice: auto
+ tools:
+ - function:
+ description: |-
+ Execute Python code in the sandboxed environment.
+
+ The code has access to haiku.rag functions (search, list_documents,
+ get_document, get_docling_document, ask) and safe standard library
+ modules (json, re, collections, math, statistics, itertools,
+ functools, datetime, typing).
+
+ Use print() to output results. Variables persist between executions.
+
+ Structured result with success status, stdout, and stderr.
+
+ name: execute_code
+ parameters:
+ additionalProperties: false
+ properties:
+ code:
+ description: Python code to execute.
+ type: string
+ required:
+ - code
+ type: object
+ strict: true
+ type: function
+ - function:
+ description: Result from RLM agent execution.
+ name: final_result
+ parameters:
+ $defs:
+ CodeExecution:
+ additionalProperties: false
+ description: Result of executing a code block in the RLM sandbox.
+ properties:
+ code:
+ description: The Python code that was executed
+ type: string
+ stderr:
+ description: Standard error captured during execution
+ type: string
+ stdout:
+ description: Standard output captured during execution
+ type: string
+ success:
+ description: Whether execution completed without error
+ type: boolean
+ required:
+ - code
+ - stdout
+ - stderr
+ - success
+ type: object
+ additionalProperties: false
+ properties:
+ answer:
+ description: The answer to the user's question
+ type: string
+ code_executions:
+ description: History of code executions during the RLM session
+ items:
+ $ref: '#/$defs/CodeExecution'
+ type: array
+ required:
+ - answer
+ type: object
+ type: function
+ uri: http://localhost:11434/v1/chat/completions
+ response:
+ headers:
+ content-length:
+ - '855'
+ content-type:
+ - application/json
+ parsed_body:
+ choices:
+ - finish_reason: tool_calls
+ index: 0
+ message:
+ content: ''
+ reasoning: Need to handle different phrasing. Search for "$" pattern.
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"import re\nrevs={}\nfor d in [''Q1 Report'',''Q2 Report'',''Q3 Report'']:\n content=get_document(d)\n if
+ content:\n vals=re.findall(r''\\$([\\d,]+)'',content)\n if vals:\n rev=sum(int(v.replace('','',''''))
+ for v in vals)\n else:\n rev=None\n else:\n rev=None\n revs[d]=rev\nprint(revs)\n"}'
+ name: execute_code
+ id: call_2j8yqv8s
+ index: 0
+ type: function
+ created: 1769703369
+ id: chatcmpl-192
+ model: gpt-oss
+ object: chat.completion
+ system_fingerprint: fp_ollama
+ usage:
+ completion_tokens: 139
+ prompt_tokens: 2641
+ total_tokens: 2780
+ status:
+ code: 200
+ message: OK
+- request:
+ headers:
+ accept:
+ - application/json
+ accept-encoding:
+ - gzip, deflate, zstd
+ connection:
+ - keep-alive
+ content-length:
+ - '13113'
+ content-type:
+ - application/json
+ host:
+ - localhost:11434
+ method: POST
+ parsed_body:
+ messages:
+ - content: |-
+ You are a Recursive Language Model (RLM) agent that solves complex research questions by writing and executing Python code.
+
+ IMPORTANT: You MUST use the `execute_code` tool to run Python code. The functions described below are ONLY available inside the execute_code tool - you cannot access them any other way. Always execute code to answer questions; do not just describe what code would do.
+
+ CRITICAL: Inside execute_code, these functions are ALREADY available in the namespace. Do NOT import them - just use them directly:
+ - search("query") ✓ CORRECT
+ - from haiku.rag import search ✗ WRONG - will fail
+
+ You have access to a sandboxed Python environment with these haiku.rag functions (use them directly, no imports needed):
+
+ ## Available Functions
+
+ ### search(query, limit=10) -> list[dict]
+ Search the knowledge base using hybrid search (vector + full-text).
+ Returns list of dicts with keys: chunk_id, content, document_id, document_title, document_uri, score, page_numbers, headings
+
+ ### list_documents(limit=10, offset=0) -> list[dict]
+ List available documents in the knowledge base.
+ Returns list of dicts with keys: id, title, uri, created_at
+
+ ### get_document(id_or_title) -> str | None
+ Get the full text content of a document by ID, title, or URI.
+ Returns the document content as a string, or None if not found.
+
+ ### get_docling_document(id_or_title) -> DoclingDocument | None
+ Get the structured DoclingDocument object for advanced analysis.
+ Returns a DoclingDocument object, or None if not found.
+ See "DoclingDocument API" section below for how to use it.
+
+ ### ask(question) -> str
+ Ask a question using the QA agent with RAG. Returns the answer as a string.
+ Use this for semantic analysis that benefits from LLM reasoning.
+
+ ## Standard Library Modules
+ You can import: json, re, collections, math, statistics, itertools, functools, datetime, typing
+
+ ## Strategy Guide
+
+ 1. **Explore First**: Start by listing documents or searching to understand what's available. Document names may differ from filenames (e.g., "tbmed593.pdf" might be stored as "TB MED 593" or similar).
+ 2. **If get_document returns None**: Use `list_documents()` to see actual document titles, or `search()` to find relevant content.
+ 3. **Iterative Refinement**: Run code, examine results, adjust your approach based on what you find.
+ 4. **Use print() Liberally**: The REPL captures stdout - print intermediate results to see what you're working with.
+ 5. **Aggregate with Code**: For counting, averaging, or comparing across documents, write loops and use collections.
+ 6. **Use ask() for Semantic Analysis**: When you need to understand meaning or interpret content, use the ask() function.
+ 7. **Cite Your Sources**: Track which documents/chunks informed your answer for citation.
+
+ ## DoclingDocument API
+
+ When you call `get_docling_document(id_or_title)`, you get a DoclingDocument object for structured document analysis.
+
+ ### Properties
+ - `doc.texts` - List of all text items (paragraphs, headings, etc.)
+ - `doc.tables` - List of all tables
+ - `doc.pictures` - List of all pictures/figures
+ - `doc.name` - Document name
+
+ ### Methods
+ - `doc.iterate_items(with_groups=False)` - Iterate all items with hierarchy level
+ Returns tuples of (item, level) where level is nesting depth
+ - `doc.export_to_markdown()` - Export entire document as markdown string
+
+ ### Text Item Properties
+ - `item.text` - The text content
+ - `item.label` - Type: TITLE, PARAGRAPH, SECTION_HEADER, LIST_ITEM, etc.
+ - `item.prov` - Provenance (page numbers, bounding boxes)
+
+ ### Table Access
+ - `table.data.num_rows`, `table.data.num_cols` - Dimensions
+ - `table.data.table_cells` - List of TableCell objects
+ - `cell.text`, `cell.start_row_offset_idx`, `cell.start_col_offset_idx`
+
+ ### Example Usage
+ ```python
+ doc = get_docling_document("My Document")
+
+ # Get all headings
+ headings = [t.text for t in doc.texts if "HEADER" in str(t.label)]
+
+ # Iterate with structure
+ for item, level in doc.iterate_items():
+ print(" " * level + item.text[:50])
+
+ # Extract table data
+ for table in doc.tables:
+ for cell in table.data.table_cells:
+ print(f"Row {cell.start_row_offset_idx}, Col {cell.start_col_offset_idx}: {cell.text}")
+ ```
+
+ ## Example Patterns
+
+ ### Counting documents matching a condition
+ ```python
+ docs = list_documents(limit=100)
+ count = 0
+ for doc in docs:
+ content = get_document(doc['id'])
+ if content and 'keyword' in content.lower():
+ count += 1
+ print(f"Found in: {doc['title']}")
+ print(f"Total: {count}")
+ ```
+
+ ### Aggregating data across documents
+ ```python
+ import re
+ numbers = []
+ results = search("financial data", limit=20)
+ for r in results:
+ matches = re.findall(r'\$([\d,]+)', r['content'])
+ for m in matches:
+ numbers.append(int(m.replace(',', '')))
+ print(f"Average: ${sum(numbers)/len(numbers):,.2f}")
+ ```
+
+ ### Using ask() for semantic analysis
+ ```python
+ # First search to find relevant content
+ results = search("machine learning approaches")
+ # Then use ask() to synthesize an answer
+ summary = ask("What are the main machine learning approaches discussed?")
+ print(summary)
+ ```
+
+ ## Workflow
+
+ 1. **ALWAYS start by using execute_code** to explore the knowledge base
+ 2. Run multiple code blocks as needed to gather information
+ 3. After collecting data, provide your final answer
+
+ ## Output Format
+
+ After executing code and gathering information, provide:
+ 1. A clear answer to the user's question
+ 2. Key findings from your analysis
+ 3. References to specific documents/chunks that informed your answer
+
+ CRITICAL: You MUST call execute_code at least once before providing your answer. Never give up without trying to execute code first.
+ role: system
+ - content: What is the total revenue across all quarterly reports?
+ role: user
+ - content: |-
+
+ We need revenue from quarterly reports. Search for "quarterly report" and revenue.
+
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"results = search(\"quarterly report revenue\", limit=50)\nprint(len(results))\nfor r in results[:5]:\n print(r[''document_title''],
+ r[''score''], r[''page_numbers''])\n"}'
+ name: execute_code
+ id: call_8cd1wnf6
+ type: function
+ - content: '{"code":"results = search(\"quarterly report revenue\", limit=50)\nprint(len(results))\nfor r in results[:5]:\n print(r[''document_title''],
+ r[''score''], r[''page_numbers''])\n","stdout":"3\nQ1 Report 0.03226645663380623 []\nQ2 Report 0.03226645663380623
+ []\nQ3 Report 0.032258063554763794 []\n","stderr":"","success":true}'
+ role: tool
+ tool_call_id: call_8cd1wnf6
+ - content: |-
+
+ We have 3 reports: Q1, Q2, Q3. Likely Q4 also exists. Search again for Q4.
+
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"results = search(\"Q4 Report\", limit=10)\nprint(len(results))\nfor r in results:\n print(r[''document_title''])\n"}'
+ name: execute_code
+ id: call_mgo4t2ty
+ type: function
+ - content: '{"code":"results = search(\"Q4 Report\", limit=10)\nprint(len(results))\nfor r in results:\n print(r[''document_title''])\n","stdout":"3\nQ1
+ Report\nQ2 Report\nQ3 Report\n","stderr":"","success":true}'
+ role: tool
+ tool_call_id: call_mgo4t2ty
+ - content: |-
+
+ All quarterly reports 1-3 only? Maybe Q4 is in separate doc. Search “Quarterly Report 4”.
+
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"results = search(\"Quarterly Report 4\", limit=10)\nprint(len(results))\nfor r in results:\n print(r[''document_title''])\n"}'
+ name: execute_code
+ id: call_3d3jutqn
+ type: function
+ - content: '{"code":"results = search(\"Quarterly Report 4\", limit=10)\nprint(len(results))\nfor r in results:\n print(r[''document_title''])\n","stdout":"3\nQ1
+ Report\nQ2 Report\nQ3 Report\n","stderr":"","success":true}'
+ role: tool
+ tool_call_id: call_3d3jutqn
+ - content: |2-
+
+ It appears only Q1‑Q3 reports are present in the index. We need revenue figures from each. We'll retrieve the full text of each report and extract numbers labeled “Revenue”.
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"docs = [''Q1 Report'', ''Q2 Report'', ''Q3 Report'']\nrevenues = {}\nimport re\nfor d in
+ docs:\n content = get_document(d)\n if content:\n # Find revenue lines\n matches = re.findall(r''Revenue.*?:\\s*\\$([\\d,\\.]+)'',
+ content, re.IGNORECASE)\n if matches:\n # take first match\n rev = float(matches[0].replace('','',''''))\n revenues[d]
+ = rev\n else:\n revenues[d] = None\n else:\n revenues[d] = None\nprint(revenues)\n"}'
+ name: execute_code
+ id: call_2rg8jz4m
+ type: function
+ - content: '{"code":"docs = [''Q1 Report'', ''Q2 Report'', ''Q3 Report'']\nrevenues = {}\nimport re\nfor d in docs:\n content
+ = get_document(d)\n if content:\n # Find revenue lines\n matches = re.findall(r''Revenue.*?:\\s*\\$([\\d,\\.]+)'',
+ content, re.IGNORECASE)\n if matches:\n # take first match\n rev = float(matches[0].replace('','',''''))\n revenues[d]
+ = rev\n else:\n revenues[d] = None\n else:\n revenues[d] = None\nprint(revenues)\n","stdout":"{''Q1
+ Report'': None, ''Q2 Report'': None, ''Q3 Report'': None}\n","stderr":"","success":true}'
+ role: tool
+ tool_call_id: call_2rg8jz4m
+ - content: |-
+
+ No revenue found by pattern. Let's inspect content snippet.
+
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"content = get_document(''Q1 Report'')\nprint(content[:500])\n"}'
+ name: execute_code
+ id: call_oqz8cbe0
+ type: function
+ - content: '{"code":"content = get_document(''Q1 Report'')\nprint(content[:500])\n","stdout":"Sales report Q1: Revenue
+ was $100,000.\n","stderr":"","success":true}'
+ role: tool
+ tool_call_id: call_oqz8cbe0
+ - content: |-
+
+ Need to handle different phrasing. Search for "$" pattern.
+
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"import re\nrevs={}\nfor d in [''Q1 Report'',''Q2 Report'',''Q3 Report'']:\n content=get_document(d)\n if
+ content:\n vals=re.findall(r''\\$([\\d,]+)'',content)\n if vals:\n rev=sum(int(v.replace('','',''''))
+ for v in vals)\n else:\n rev=None\n else:\n rev=None\n revs[d]=rev\nprint(revs)\n"}'
+ name: execute_code
+ id: call_2j8yqv8s
+ type: function
+ - content: '{"code":"import re\nrevs={}\nfor d in [''Q1 Report'',''Q2 Report'',''Q3 Report'']:\n content=get_document(d)\n if
+ content:\n vals=re.findall(r''\\$([\\d,]+)'',content)\n if vals:\n rev=sum(int(v.replace('','',''''))
+ for v in vals)\n else:\n rev=None\n else:\n rev=None\n revs[d]=rev\nprint(revs)\n","stdout":"{''Q1
+ Report'': 100000, ''Q2 Report'': 150000, ''Q3 Report'': 200000}\n","stderr":"","success":true}'
+ role: tool
+ tool_call_id: call_2j8yqv8s
+ model: gpt-oss
+ reasoning_effort: low
+ stream: false
+ tool_choice: auto
+ tools:
+ - function:
+ description: |-
+ Execute Python code in the sandboxed environment.
+
+ The code has access to haiku.rag functions (search, list_documents,
+ get_document, get_docling_document, ask) and safe standard library
+ modules (json, re, collections, math, statistics, itertools,
+ functools, datetime, typing).
+
+ Use print() to output results. Variables persist between executions.
+
+ Structured result with success status, stdout, and stderr.
+
+ name: execute_code
+ parameters:
+ additionalProperties: false
+ properties:
+ code:
+ description: Python code to execute.
+ type: string
+ required:
+ - code
+ type: object
+ strict: true
+ type: function
+ - function:
+ description: Result from RLM agent execution.
+ name: final_result
+ parameters:
+ $defs:
+ CodeExecution:
+ additionalProperties: false
+ description: Result of executing a code block in the RLM sandbox.
+ properties:
+ code:
+ description: The Python code that was executed
+ type: string
+ stderr:
+ description: Standard error captured during execution
+ type: string
+ stdout:
+ description: Standard output captured during execution
+ type: string
+ success:
+ description: Whether execution completed without error
+ type: boolean
+ required:
+ - code
+ - stdout
+ - stderr
+ - success
+ type: object
+ additionalProperties: false
+ properties:
+ answer:
+ description: The answer to the user's question
+ type: string
+ code_executions:
+ description: History of code executions during the RLM session
+ items:
+ $ref: '#/$defs/CodeExecution'
+ type: array
+ required:
+ - answer
+ type: object
+ type: function
+ uri: http://localhost:11434/v1/chat/completions
+ response:
+ headers:
+ content-length:
+ - '995'
+ content-type:
+ - application/json
+ parsed_body:
+ choices:
+ - finish_reason: stop
+ index: 0
+ message:
+ content: "**Answer**\n\nThe total revenue reported across the three quarterly reports is:\n\n\\- Q1 Report: **$100,000**
+ \ \n\\- Q2 Report: **$150,000** \n\\- Q3 Report: **$200,000**\n\n**Total Revenue (all quarters combined): $450,000**\n\n**Key
+ Findings & Sources**\n\n1. **Q1 Report** – revenue extraction from the text \"Revenue was $100,000.\"\n - Source
+ snippet: *“Sales report Q1: Revenue was $100,000.”*\n2. **Q2 Report** – revenue extracted from \"$150,000\" in
+ the document.\n3. **Q3 Report** – revenue extracted from \"$200,000\" in the document.\n\nAll figures were obtained
+ by searching each document for dollar amounts and summing them. No Q4 report was found in the available documents."
+ role: assistant
+ created: 1769703373
+ id: chatcmpl-568
+ model: gpt-oss
+ object: chat.completion
+ system_fingerprint: fp_ollama
+ usage:
+ completion_tokens: 180
+ prompt_tokens: 2941
+ total_tokens: 3121
+ status:
+ code: 200
+ message: OK
+- request:
+ headers:
+ accept:
+ - application/json
+ accept-encoding:
+ - gzip, deflate, zstd
+ connection:
+ - keep-alive
+ content-length:
+ - '14838'
+ content-type:
+ - application/json
+ host:
+ - localhost:11434
+ method: POST
+ parsed_body:
+ messages:
+ - content: |-
+ You are a Recursive Language Model (RLM) agent that solves complex research questions by writing and executing Python code.
+
+ IMPORTANT: You MUST use the `execute_code` tool to run Python code. The functions described below are ONLY available inside the execute_code tool - you cannot access them any other way. Always execute code to answer questions; do not just describe what code would do.
+
+ CRITICAL: Inside execute_code, these functions are ALREADY available in the namespace. Do NOT import them - just use them directly:
+ - search("query") ✓ CORRECT
+ - from haiku.rag import search ✗ WRONG - will fail
+
+ You have access to a sandboxed Python environment with these haiku.rag functions (use them directly, no imports needed):
+
+ ## Available Functions
+
+ ### search(query, limit=10) -> list[dict]
+ Search the knowledge base using hybrid search (vector + full-text).
+ Returns list of dicts with keys: chunk_id, content, document_id, document_title, document_uri, score, page_numbers, headings
+
+ ### list_documents(limit=10, offset=0) -> list[dict]
+ List available documents in the knowledge base.
+ Returns list of dicts with keys: id, title, uri, created_at
+
+ ### get_document(id_or_title) -> str | None
+ Get the full text content of a document by ID, title, or URI.
+ Returns the document content as a string, or None if not found.
+
+ ### get_docling_document(id_or_title) -> DoclingDocument | None
+ Get the structured DoclingDocument object for advanced analysis.
+ Returns a DoclingDocument object, or None if not found.
+ See "DoclingDocument API" section below for how to use it.
+
+ ### ask(question) -> str
+ Ask a question using the QA agent with RAG. Returns the answer as a string.
+ Use this for semantic analysis that benefits from LLM reasoning.
+
+ ## Standard Library Modules
+ You can import: json, re, collections, math, statistics, itertools, functools, datetime, typing
+
+ ## Strategy Guide
+
+ 1. **Explore First**: Start by listing documents or searching to understand what's available. Document names may differ from filenames (e.g., "tbmed593.pdf" might be stored as "TB MED 593" or similar).
+ 2. **If get_document returns None**: Use `list_documents()` to see actual document titles, or `search()` to find relevant content.
+ 3. **Iterative Refinement**: Run code, examine results, adjust your approach based on what you find.
+ 4. **Use print() Liberally**: The REPL captures stdout - print intermediate results to see what you're working with.
+ 5. **Aggregate with Code**: For counting, averaging, or comparing across documents, write loops and use collections.
+ 6. **Use ask() for Semantic Analysis**: When you need to understand meaning or interpret content, use the ask() function.
+ 7. **Cite Your Sources**: Track which documents/chunks informed your answer for citation.
+
+ ## DoclingDocument API
+
+ When you call `get_docling_document(id_or_title)`, you get a DoclingDocument object for structured document analysis.
+
+ ### Properties
+ - `doc.texts` - List of all text items (paragraphs, headings, etc.)
+ - `doc.tables` - List of all tables
+ - `doc.pictures` - List of all pictures/figures
+ - `doc.name` - Document name
+
+ ### Methods
+ - `doc.iterate_items(with_groups=False)` - Iterate all items with hierarchy level
+ Returns tuples of (item, level) where level is nesting depth
+ - `doc.export_to_markdown()` - Export entire document as markdown string
+
+ ### Text Item Properties
+ - `item.text` - The text content
+ - `item.label` - Type: TITLE, PARAGRAPH, SECTION_HEADER, LIST_ITEM, etc.
+ - `item.prov` - Provenance (page numbers, bounding boxes)
+
+ ### Table Access
+ - `table.data.num_rows`, `table.data.num_cols` - Dimensions
+ - `table.data.table_cells` - List of TableCell objects
+ - `cell.text`, `cell.start_row_offset_idx`, `cell.start_col_offset_idx`
+
+ ### Example Usage
+ ```python
+ doc = get_docling_document("My Document")
+
+ # Get all headings
+ headings = [t.text for t in doc.texts if "HEADER" in str(t.label)]
+
+ # Iterate with structure
+ for item, level in doc.iterate_items():
+ print(" " * level + item.text[:50])
+
+ # Extract table data
+ for table in doc.tables:
+ for cell in table.data.table_cells:
+ print(f"Row {cell.start_row_offset_idx}, Col {cell.start_col_offset_idx}: {cell.text}")
+ ```
+
+ ## Example Patterns
+
+ ### Counting documents matching a condition
+ ```python
+ docs = list_documents(limit=100)
+ count = 0
+ for doc in docs:
+ content = get_document(doc['id'])
+ if content and 'keyword' in content.lower():
+ count += 1
+ print(f"Found in: {doc['title']}")
+ print(f"Total: {count}")
+ ```
+
+ ### Aggregating data across documents
+ ```python
+ import re
+ numbers = []
+ results = search("financial data", limit=20)
+ for r in results:
+ matches = re.findall(r'\$([\d,]+)', r['content'])
+ for m in matches:
+ numbers.append(int(m.replace(',', '')))
+ print(f"Average: ${sum(numbers)/len(numbers):,.2f}")
+ ```
+
+ ### Using ask() for semantic analysis
+ ```python
+ # First search to find relevant content
+ results = search("machine learning approaches")
+ # Then use ask() to synthesize an answer
+ summary = ask("What are the main machine learning approaches discussed?")
+ print(summary)
+ ```
+
+ ## Workflow
+
+ 1. **ALWAYS start by using execute_code** to explore the knowledge base
+ 2. Run multiple code blocks as needed to gather information
+ 3. After collecting data, provide your final answer
+
+ ## Output Format
+
+ After executing code and gathering information, provide:
+ 1. A clear answer to the user's question
+ 2. Key findings from your analysis
+ 3. References to specific documents/chunks that informed your answer
+
+ CRITICAL: You MUST call execute_code at least once before providing your answer. Never give up without trying to execute code first.
+ role: system
+ - content: What is the total revenue across all quarterly reports?
+ role: user
+ - content: |-
+
+ We need revenue from quarterly reports. Search for "quarterly report" and revenue.
+
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"results = search(\"quarterly report revenue\", limit=50)\nprint(len(results))\nfor r in results[:5]:\n print(r[''document_title''],
+ r[''score''], r[''page_numbers''])\n"}'
+ name: execute_code
+ id: call_8cd1wnf6
+ type: function
+ - content: '{"code":"results = search(\"quarterly report revenue\", limit=50)\nprint(len(results))\nfor r in results[:5]:\n print(r[''document_title''],
+ r[''score''], r[''page_numbers''])\n","stdout":"3\nQ1 Report 0.03226645663380623 []\nQ2 Report 0.03226645663380623
+ []\nQ3 Report 0.032258063554763794 []\n","stderr":"","success":true}'
+ role: tool
+ tool_call_id: call_8cd1wnf6
+ - content: |-
+
+ We have 3 reports: Q1, Q2, Q3. Likely Q4 also exists. Search again for Q4.
+
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"results = search(\"Q4 Report\", limit=10)\nprint(len(results))\nfor r in results:\n print(r[''document_title''])\n"}'
+ name: execute_code
+ id: call_mgo4t2ty
+ type: function
+ - content: '{"code":"results = search(\"Q4 Report\", limit=10)\nprint(len(results))\nfor r in results:\n print(r[''document_title''])\n","stdout":"3\nQ1
+ Report\nQ2 Report\nQ3 Report\n","stderr":"","success":true}'
+ role: tool
+ tool_call_id: call_mgo4t2ty
+ - content: |-
+
+ All quarterly reports 1-3 only? Maybe Q4 is in separate doc. Search “Quarterly Report 4”.
+
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"results = search(\"Quarterly Report 4\", limit=10)\nprint(len(results))\nfor r in results:\n print(r[''document_title''])\n"}'
+ name: execute_code
+ id: call_3d3jutqn
+ type: function
+ - content: '{"code":"results = search(\"Quarterly Report 4\", limit=10)\nprint(len(results))\nfor r in results:\n print(r[''document_title''])\n","stdout":"3\nQ1
+ Report\nQ2 Report\nQ3 Report\n","stderr":"","success":true}'
+ role: tool
+ tool_call_id: call_3d3jutqn
+ - content: |2-
+
+ It appears only Q1‑Q3 reports are present in the index. We need revenue figures from each. We'll retrieve the full text of each report and extract numbers labeled “Revenue”.
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"docs = [''Q1 Report'', ''Q2 Report'', ''Q3 Report'']\nrevenues = {}\nimport re\nfor d in
+ docs:\n content = get_document(d)\n if content:\n # Find revenue lines\n matches = re.findall(r''Revenue.*?:\\s*\\$([\\d,\\.]+)'',
+ content, re.IGNORECASE)\n if matches:\n # take first match\n rev = float(matches[0].replace('','',''''))\n revenues[d]
+ = rev\n else:\n revenues[d] = None\n else:\n revenues[d] = None\nprint(revenues)\n"}'
+ name: execute_code
+ id: call_2rg8jz4m
+ type: function
+ - content: '{"code":"docs = [''Q1 Report'', ''Q2 Report'', ''Q3 Report'']\nrevenues = {}\nimport re\nfor d in docs:\n content
+ = get_document(d)\n if content:\n # Find revenue lines\n matches = re.findall(r''Revenue.*?:\\s*\\$([\\d,\\.]+)'',
+ content, re.IGNORECASE)\n if matches:\n # take first match\n rev = float(matches[0].replace('','',''''))\n revenues[d]
+ = rev\n else:\n revenues[d] = None\n else:\n revenues[d] = None\nprint(revenues)\n","stdout":"{''Q1
+ Report'': None, ''Q2 Report'': None, ''Q3 Report'': None}\n","stderr":"","success":true}'
+ role: tool
+ tool_call_id: call_2rg8jz4m
+ - content: |-
+
+ No revenue found by pattern. Let's inspect content snippet.
+
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"content = get_document(''Q1 Report'')\nprint(content[:500])\n"}'
+ name: execute_code
+ id: call_oqz8cbe0
+ type: function
+ - content: '{"code":"content = get_document(''Q1 Report'')\nprint(content[:500])\n","stdout":"Sales report Q1: Revenue
+ was $100,000.\n","stderr":"","success":true}'
+ role: tool
+ tool_call_id: call_oqz8cbe0
+ - content: |-
+
+ Need to handle different phrasing. Search for "$" pattern.
+
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"import re\nrevs={}\nfor d in [''Q1 Report'',''Q2 Report'',''Q3 Report'']:\n content=get_document(d)\n if
+ content:\n vals=re.findall(r''\\$([\\d,]+)'',content)\n if vals:\n rev=sum(int(v.replace('','',''''))
+ for v in vals)\n else:\n rev=None\n else:\n rev=None\n revs[d]=rev\nprint(revs)\n"}'
+ name: execute_code
+ id: call_2j8yqv8s
+ type: function
+ - content: '{"code":"import re\nrevs={}\nfor d in [''Q1 Report'',''Q2 Report'',''Q3 Report'']:\n content=get_document(d)\n if
+ content:\n vals=re.findall(r''\\$([\\d,]+)'',content)\n if vals:\n rev=sum(int(v.replace('','',''''))
+ for v in vals)\n else:\n rev=None\n else:\n rev=None\n revs[d]=rev\nprint(revs)\n","stdout":"{''Q1
+ Report'': 100000, ''Q2 Report'': 150000, ''Q3 Report'': 200000}\n","stderr":"","success":true}'
+ role: tool
+ tool_call_id: call_2j8yqv8s
+ - content: "**Answer**\n\nThe total revenue reported across the three quarterly reports is:\n\n\\- Q1 Report: **$100,000**
+ \ \n\\- Q2 Report: **$150,000** \n\\- Q3 Report: **$200,000**\n\n**Total Revenue (all quarters combined): $450,000**\n\n**Key
+ Findings & Sources**\n\n1. **Q1 Report** – revenue extraction from the text \"Revenue was $100,000.\"\n - Source
+ snippet: *“Sales report Q1: Revenue was $100,000.”*\n2. **Q2 Report** – revenue extracted from \"$150,000\" in the
+ document.\n3. **Q3 Report** – revenue extracted from \"$200,000\" in the document.\n\nAll figures were obtained
+ by searching each document for dollar amounts and summing them. No Q4 report was found in the available documents."
+ role: assistant
+ - content: |-
+ 1 validation error:
+ ```json
+ [
+ {
+ "type": "json_invalid",
+ "loc": [],
+ "msg": "Invalid JSON: expected value at line 1 column 1",
+ "input": "**Answer**\n\nThe total revenue reported across the three quarterly reports is:\n\n\\- Q1 Report: **$100,000** \n\\- Q2 Report: **$150,000** \n\\- Q3 Report: **$200,000**\n\n**Total Revenue (all quarters combined): $450,000**\n\n**Key Findings & Sources**\n\n1. **Q1 Report** – revenue extraction from the text \"Revenue was $100,000.\"\n - Source snippet: *“Sales report Q1: Revenue was $100,000.”*\n2. **Q2 Report** – revenue extracted from \"$150,000\" in the document.\n3. **Q3 Report** – revenue extracted from \"$200,000\" in the document.\n\nAll figures were obtained by searching each document for dollar amounts and summing them. No Q4 report was found in the available documents."
+ }
+ ]
+ ```
+
+ Fix the errors and try again.
+ role: user
+ model: gpt-oss
+ reasoning_effort: low
+ stream: false
+ tool_choice: auto
+ tools:
+ - function:
+ description: |-
+ Execute Python code in the sandboxed environment.
+
+ The code has access to haiku.rag functions (search, list_documents,
+ get_document, get_docling_document, ask) and safe standard library
+ modules (json, re, collections, math, statistics, itertools,
+ functools, datetime, typing).
+
+ Use print() to output results. Variables persist between executions.
+
+ Structured result with success status, stdout, and stderr.
+
+ name: execute_code
+ parameters:
+ additionalProperties: false
+ properties:
+ code:
+ description: Python code to execute.
+ type: string
+ required:
+ - code
+ type: object
+ strict: true
+ type: function
+ - function:
+ description: Result from RLM agent execution.
+ name: final_result
+ parameters:
+ $defs:
+ CodeExecution:
+ additionalProperties: false
+ description: Result of executing a code block in the RLM sandbox.
+ properties:
+ code:
+ description: The Python code that was executed
+ type: string
+ stderr:
+ description: Standard error captured during execution
+ type: string
+ stdout:
+ description: Standard output captured during execution
+ type: string
+ success:
+ description: Whether execution completed without error
+ type: boolean
+ required:
+ - code
+ - stdout
+ - stderr
+ - success
+ type: object
+ additionalProperties: false
+ properties:
+ answer:
+ description: The answer to the user's question
+ type: string
+ code_executions:
+ description: History of code executions during the RLM session
+ items:
+ $ref: '#/$defs/CodeExecution'
+ type: array
+ required:
+ - answer
+ type: object
+ type: function
+ uri: http://localhost:11434/v1/chat/completions
+ response:
+ headers:
+ content-length:
+ - '1126'
+ content-type:
+ - application/json
+ parsed_body:
+ choices:
+ - finish_reason: tool_calls
+ index: 0
+ message:
+ content: ''
+ reasoning: Need to output JSON.
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"answer":"The total revenue reported across the three quarterly reports is:\n- Q1 Report: $100,000\n-
+ Q2 Report: $150,000\n- Q3 Report: $200,000\n\n**Total Revenue (all quarters combined): $450,000**\n\n**Key
+ Findings \u0026 Sources**\n1. Q1 Report – revenue extracted from the text \"Revenue was $100,000.\" (Source:
+ Sales report Q1 text)\n2. Q2 Report – revenue extracted from \"$150,000\" in the document.\n3. Q3 Report –
+ revenue extracted from \"$200,000\" in the document.\n\nAll figures were obtained by searching each document
+ for dollar amounts and summing them. No Q4 report was found in the available documents.","code_executions":[]}'
+ name: final_result
+ id: call_1ouq42ea
+ index: 0
+ type: function
+ created: 1769703378
+ id: chatcmpl-830
+ model: gpt-oss
+ object: chat.completion
+ system_fingerprint: fp_ollama
+ usage:
+ completion_tokens: 195
+ prompt_tokens: 3387
+ total_tokens: 3582
+ status:
+ code: 200
+ message: OK
+version: 1
diff --git a/tests/cassettes/test_rlm/TestClientRLMIntegration.test_rlm_count_documents.yaml b/tests/cassettes/test_rlm/TestClientRLMIntegration.test_rlm_count_documents.yaml
new file mode 100644
index 00000000..b74f18bf
--- /dev/null
+++ b/tests/cassettes/test_rlm/TestClientRLMIntegration.test_rlm_count_documents.yaml
@@ -0,0 +1,656 @@
+interactions:
+- request:
+ headers:
+ accept:
+ - application/json
+ accept-encoding:
+ - gzip, deflate, zstd
+ connection:
+ - keep-alive
+ content-length:
+ - '96'
+ content-type:
+ - application/json
+ host:
+ - localhost:11434
+ method: POST
+ parsed_body:
+ encoding_format: base64
+ input:
+ - First document about cats.
+ model: qwen3-embedding:4b
+ uri: http://localhost:11434/v1/embeddings
+ response:
+ headers:
+ content-type:
+ - application/json
+ transfer-encoding:
+ - chunked
+ parsed_body:
+ data:
+ - embedding: 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
+ index: 0
+ object: embedding
+ model: qwen3-embedding:4b
+ object: list
+ usage:
+ prompt_tokens: 6
+ total_tokens: 6
+ status:
+ code: 200
+ message: OK
+- request:
+ headers:
+ accept:
+ - application/json
+ accept-encoding:
+ - gzip, deflate, zstd
+ connection:
+ - keep-alive
+ content-length:
+ - '97'
+ content-type:
+ - application/json
+ host:
+ - localhost:11434
+ method: POST
+ parsed_body:
+ encoding_format: base64
+ input:
+ - Second document about dogs.
+ model: qwen3-embedding:4b
+ uri: http://localhost:11434/v1/embeddings
+ response:
+ headers:
+ content-type:
+ - application/json
+ transfer-encoding:
+ - chunked
+ parsed_body:
+ data:
+ - embedding: WYA3uV2j0Ty18KM65Tf2vOxiS7r7gCI90kYxPUtLPLzxw608LAWLu8oxubzLBK88TIi+Ox5Dmby5+G88AXmMvMS6Lj0gGly8LBaZvOgXlbvIkoC8h7BEPCNgRjw/1Hy81jNlPP6cTjqoPae8sjWavNSlVz38RX08CabOvFtC6LwekAQ94AExvKjZdDu2ksu72fvZOtW/nrt3AyU8apgOOYVHyDvdblG9f13jPCfR3DtYoDS9OaJivDL0YTt0yIw8+PvUvA3QDr2kUhY8FkyjO1TEprw/9F28JfhMPDogXLzEWmA98AA/u6K1J73sUAK9Ptifu6Tz27y5A5K7rqQmvG21Pbt81tG8vUt9O9bFzLwOvik8EmYlvdeC8bshUC09fsL8uyMjRTqTn+g8I/ywvDCW5rvnC/o8PTg3vELCGjzA4xM9DTeFPEsSEDwTZ4Y9EOvQPIz9ajsNcIs8fSGRPGMLj7v+qWQ8LntjPHV29TtzUU28EX6kPDW4mjuKBMG70M+4vHrGMLye4dS67/BtPFMBBDsQS8+7uJM/PHUodryjLOS70BzAvCgrB7zbx8e83yLfvBW1p7s8wNa7PFeGPH1VezyglxC8dWsHPJ0+qrvEbZU7maFHPQQeVDyG4sg8SwTwu3tkmjz/LmO8vF1BPHp7ZjwhIzY8b7mgvOdor7w/JWm80MPXPPz0Hz15jqe8eAdzPHbKQ7yTWHA8rqVKPE20s7twfI+72UPIO69+fzyfwwC8N9y/u9wrmDuNbvs8rjIIvSZrS718g/i7cZbdPEUsQzznEYS7qcW+PEzxAjwcqcg6oei0PJnVyDwtrsM8TqW8vE3RN7r8BrG7iWg8PDoChjvQIoY86WRzu8eBVDz/xqc8lLk6PMb9g7voNR66Fu6GvGTHfbzjMTC8VJWWu4YJmbzUN8O8sbGvvA6tP7uMNhe9cWKaPK/GpbqJloc79nQEvFQ6+rsKRta7iXWJuwNjeTyXSFo5TSBnuyqbgrotcDW7SAJVPEVouLxxsCM8If0tO1K0G7xyfP674n2Pu/BPtryMMje8BQy9vLq8zDy5ecE7O5xtvBNZCzzm/I68yhlcPBU3nLu23XS8QsKAvNPtHzyd7Zc5uE3HPHfHLTyNV6S8Kk0Jva8fEzz+GxS8snSlvNY5t7wzOsM8yLMlPZ91HDwexIE7B58QvFoWhDtKJ9K8nfYqO5C/izzTUQO7IyVBO0Q+x7zDZlo8YYuIvHMQJLuas4G8raP1OW6rMTzLWxE797kVPP53PDs2Uvm8NF0mvVq7ybuauJ+8gkoFPPbZ4zp50gS8xlu2u2mTN7xzP8O70V7rvCv/ErySfoY7vCjju3wDebzE/w28f29FOrdhtbwKDLO8CJvFO9fEED10Z8Y5ttS+vBHzAzytPo27sJwHuwYvmzzxULU7vWqGvCfSxTw+N8q814wKPUCRbzqXakA8kuEZPJ+fTT1EhgW8EaOnO8xKuLs0PQE80qYJPcLV5rxe5hU7OWrIvJtmbjxMFam6NFa2uxinADyJ6G88gXegvHqMLjxV3Ts84xMOvZgAhTyDCgy7ztwxvEkSvDzd6o08x4znvE9ciLwoLJa8qdeLvHw70ru/BX48vxKfPFEwyTxOB9U8PDeFPPLzjDwCy4o7+rnPvEGxwLwzsvS6nk39u5/58ju8sw49GxEIvSkBRLzYDwy8Vh0rvJ8zgbzqcRw7RS82vdmkYrwzb2k8BuuavI3FrTwYfYE8h7fePC2+VDySpXI9tK5iO4n2DT3idd68FvAgvP8NTLpO9rQ6ck34u2O1AT0g+o48UvaVPFyqDDse9aC7cC+aPHvOjrwLCWu9L6IVPNkR4DznkGG8AFp3vHVTDr01wBM6cYXSvAjOjbuIAOo7aSylPN/X+TxIuUy8JtKLPFX/Sz2UU9C7QQEZvL7mQbzeVJk7RfkkPYrWp7wcdNi7u7RAvCA0Mj1UeEK88togvArunDv2u7W8PRHnPEkF1buDKZG7E+Nyu9LCODyt0ey8buRfu7AvO7tEtFA8CXp+PCJ9h7w3Nbo8JOAKOx1Y+DuPfsi71Y5oPCzxlzxk/z08jUlIPCqFOLyZFnc7zJ4OPatqI72m2Vo8pjMrPBOgxjyKviQ92wEUu4Jua7zzD9E5856yvBJzYDtyWyI8118RvGecQLz0xYI9e2daPA+KIbsUwam61RkDPDHMuDtTDh29dLcZvMQu4jyls448kRLbvG/uwrzb/sI8FbRIO+nDTzrT+B86WqJUu7IbXzyRu0Y8Db1vvIivtTrKe6u8RMWOvB0tfLwtm8E8yPMvO+2B/jx2iaG7JsbBPBkUqrsSiqC8ohdnvD+pL72Hsb08008evBy97TxT4148d6PYvHsZIzx6EQc7S4p0u0Lkf7yAYkm9o4rMvKNgBzvm4xg7vbGnvI3AP73BhNc72M+jPHOY7ryRBvC8BK/YOa2OsL1liKK7XtVxvBwYuLyE7fq7Z8LmvEl6qbwFsDm8WYDoPGbqpjxLEEK9jcGvvNGYF70l3d08AWOxuh9iGzsFS0m87g4nPGz4ejyN3Ks8kocfPZ7E/ztgHsE822W8vFPj67uoMEs8QbdnPEh7hDyiJOc8S8GpujgXeTzW3tG82gSfuktB8ruAVts7lq0MPAoJrDtpVaC8pwZ6PFzHvrm/A+28QLIhPT/hhbx+JVq8RHn5vNltGj3ldzc8w9bXvAeMKLzI/w89hQaKPH4cTTzOqMI883UIvVdQ1DwMSPS674c9vZ1aRrxRCIO8t+O+vEiaH7yOC7q8pIEXO5DbB73635i851KwPKMH4zzZwfu8lLTlvH80/ju6Q2+8dAOAPE2ZkLqmslA7HBGvvFefWbvLMdA6+ZYuvGQ0AjuvpdQ8CZKAuz0MrbsVfQY8aoDAu6A9xDsu7IC7PfRZPRAIgDxkBAu8WZfTuyQGNDwdoP68xoi3O4vOPL0aKUM8XwPMPGxYy7zuh/a7RIPyuwdWYbwzCMO7UFa5u1Lw27uC/j08/Wkgu7We/rwSz9W8d8WPPGhw/LzS0KK8dP6rO7ZqGj3dFjM87Ee6OjprCb3mF+i7uunXPMuqwzrs9/u8QDyBPDl0lDzeaJg8974GPLACN7zkbhS8TnsRO230TrvJrcu7cAadPBr0+LsJGeS8rtTNOs/cL7wQAP68JuzxPLodabvfMPG7l8BFvR8CrDx6nfo6cJ8ePSdClLzOylS8a71suxlbELy8gEk8rURJPJXnFTxAMee8fE8GPW9S67whegG9Um2AvB+G1DyptLw86+yMvA1Z5bzE1hy9YyjrvPT4lrzrG0e822KIvK6BLrxntwW8DCYAvCOatb02qWS8KntRPIm4WzxY+ZW8yR2KvDAFRLxNKCo9fNldOjmn3jd8abq8K4IRvdVR5Dxb1gs8xy2ovNGvNT3YkQo8s0ZVPLXXiryQ6gI9YsKivHoHlLyxmy+9tiaXupQMrDx4bAU8l1hNvMTjO7yxiAy83DYuPEQYKjyX7Ck94FrTus0NkDtcqFA5XyyLu3vP07xNjKy7UIG5PKjuGDsCj6G6WgXAvDGRDr0HwSM8+MS7O+098DrAPBM9JBcpuzCj+zuqMqs7jPzMvB1FYzp4RMu7Ouy8O+NMFzwn/Z28Djx1O2zkbjwlGxy9diH1O079Ijw48gG8D/45vNTZMLyXsrQ8nJScO85gGryOcVi8njJxPMfokLnqQr48EFy3PLllIz2eVk+9YNsYveijAr2COy87lU6uOer6BLwnPTi78vPZPGAsWTl+0WY8uwCqPIsJBT0lX/I7KrrWvGbLtry9USO8RWkVvZkkgbxxq+m8n086vLHfnTu2d6m8m7ZMOuh0sruBDSe9lAfzu4xJx7xp6F47jiUZPZ+vHLzbf4c7YUxWPR6G2Duqjbs8lG6DvPUwvjz6nfG8hWHAPDGvVzwnNqw8zYluu4pYmTuFBRu8wGWVO34maDx6Hb48NdnFvIU5KjzZ+Pe8fDnxvDBkVjyM35E8tKORPKdm2boeN5U7NaJgvHEGqrysYqc8sCnlO0x2JbwpVig9pZHFu3l3j7twHhm88+/pOqHTmLuzor+8x0HGu+oVIzuEN9S8e3+yvLUvBT3TeYW8j59UPPdHPLzsBpm8mlNUPLdkvjwKHNm7V1N4vJGYBz3az8C6M06vOotK2ryYHbc8sJS3u6DBAb2UKPK7/TervD2jRbud3M4709FKve/K+TtmaQQ8YErtvIN6jrzGctw7PPutvLZn7TvN7oO8rolJvQ9xzjxGHgy8gvLOu6h3/jvFzro8W43Iu1fmWzzwoys8DNkqvAP6ibwOVKw8yDA2PHrxxLzZdcy8UAhjPILrebywowi9yFfGPMnq/bs+GTO8pAuUOwqFnzwpnIQ84HhPu1X8XrwvcUk817+4PO/JizwQ08a7M90PvO2poDz/Pgk96/00O5gEGTwnhgc8uUkkvEeW37z2czs8E58mvZZxDL2ro+O8oC3WOwJYFr1bixs8ixfSvDCcPrwqfhY7ZOPHvHgRXjre3hQ7RtW2O0wc5jw5piw9PXkePJsnA7skgsO7lImEPO7XIbcUysI57J/ePHe6crzYaNQ8VhSsvFqpk7yXE7+86VyJPAK2sTutl8S7N6C7u4eUjzzNgc28kB2JPC4H7TxPjy89Vb4evGaHbzzgbyI8B8BvPFYZ6bz0RRo8oiV5vCd5bzzm/rS7ZvzlPOUOvDuKrxi9onRhPPuVnztfQGu8XEZvvF6BXjyHt7Y7CYOcu5sZOL2liZO7y+u7vGJnyrt/LVA8tg0FvVkXbzwGqBK9cZFGvGlaiDwh/Ig7jSjqOtBV5jtqzcg87AaGvDuG8LzYw6E8OPwdvAkPpbyruBS8ElShPMATI7sanjK9Pb81vM/6CDsHbLI8J2+LvDt7Bb2TWQM9xsasvElKBL2Ez6W8huc6PcDfw7zG97i7VesGvGmWBL09/Mu8Anf3vKAXdLxhGQQ89KHnu3sAyTynMsQ8vLdoucTxhDsJCQI936vsuxI6cbxmE1u7QA9JPBT9vzvDKO+8oietPFcWYzwcTUo8JfCnOz1PXDyUAkG8ZV+AO4KaiDuJUo+8JHSgu5opcrzNAJC7gPzePIeqj7xVyMg7FpO2uynoXjy/78q8iRMUPL4F+DsP1ZO4xiOnu3qS9bxx2by8wq1/vIdZmrwOIOO8yxiiunkuGTsCS7C80vEJPcmyujs2SU48OLIDPZ6+PT1iZxO96nbEPG2BWjvTVh08fqoBvMHzvbz7CRk8sX6Fu2vskDyd4E68MLoePEjXFDyPdm48DjOCPAliITzOI5479e4FvWRQ2zzZnnc8TIT7PNb2M72V7tU8vs1fPDl6kblO7pQ8rciavBT8FT0w7U683w9SPZHoL7xB1yq8WQpmvG2YK7x4MSc8gcupuhW2X7y4t9w89F4jPbXkQL2YywA9tQ49vcCJhrySMY48ARzIPGYgqTz7kNG8PO/5PO6K8DwBScO8JOrDOzcwRzuPnAM8W45wvB7yVzxEY4C6am2ZO+qutLxV34A7JVqbPGsdCDw618W8vi/+u1eWibzaxpO7brIivK89WjyWkIo8xWvsOpupTr3P1wu9pn9VPHxvcjwKh2y8lXeQPNpGk7uvUSQ9I4uFOz5ZXLvTErc83XQ1PbuKgTx4DGu8QcyZu5UYDTuOkzi8PaHXO9SMg7zY+IK8B0aevDwdQjzGeSS9O02TugJk77uCugI8PbI5PKrJtTtWIic8frGmvOI5B71KKdi8U6kavU3d2LwYySa8rGkVO2yTYjzLPB+5rGagPAUBXLuUP3C7nHEOPYF6lDt9/gU8Yp20uxAOI7zTnB49s+QWvMq1EztDCVk8iPXtPBO/xLuIvtI8dAkmPLUZpryjFsQ7tF8DvTXhL7xyCyk8UIubvPOwGrtpghA9p8cFvbNzqrtDDwi8VUKyPMBVyLxTJdW7tqkrvHWBhLptxuC8tmTjvKH+zTuopeY758luOydYlDwi9Ke7RBHFO0pBSjxIeAG5YmMFvdyVPjz5SZq8Mum8PBbCtzrq4Vc8SvdgPWekhDxD5Iu7ga2JPKb5yDzWM7u68qMCvFs+aLpI98W8YJiPvIGWTDwFOek8g7Q5vC8Eijx7LXU8w8QZPb74E7w3CA08XenQO+gbvjt7j6O7kgxYvE5qoDvC2qI8W3WXPP4JwjwYxL+7nww5O+ZTrTw2+6Y8J6u6vF63yDx4S488C15CvMTcJTziUMK8qDyMvC3nAb1A2qg8LpkgOwHY+zv5ar08G21TPcHxojokgV08Ug1zvOH/zTsDfzM7kHpLPHECn7xP9iO8THR+PAoC1jycqny59E4GvErgvzsmpfU8E0fMvNN687sIXW28BTbHPIF7RbsB3Ge8WqqcvAKmPrsLvzG9ZSrVOhrxHL1vPaE8YEJNvNsbOztkd+I72CYiu33+BT3FPo88L5dnPVO7E7ytkRy8rnwyPOn6Cz0UIYe8AioHPCQFTTzwa9E66xF0PF3MeryyZLG7yL4BvOvCHj06tPm8dP18PGFO/bqTixU6c70XPS4C8TwfrFK61wh1PE7LtTwbrle8ELs5Pd3/ML3vcRG7dJgTvTYbSr1VOME8gWQiPdz4Wrw/6r27qEYlPGBzzzw5jD89y4HSOyuuF72Ktq67gfMePP7nVTvHkcq75pQVPA6ZwTvfyR88xoiVOtl2uDrTKMA86XCIvDGgnbsgjSc9IzOmvFSmm7yoxPy8DMtbOx9LP7teXbK8uIhUPPMKOjtAln+6+JguO/MVPz1s+wc9ByWlOwR2eTyCCri773QhvLyjnLzdt6y8KdgevBd3OrzJddU7mC7LPG5bhrxEAUo8UeuPvEDZAr2/+l+9NOR5PSfUmjuJ0Fe9LhKbPKeS07o6AQW9ePASva+Ug7y6OBG946QrOhAOB7w5w2a8Ee3HvFG+RLzedz+8nuOeO6xoV7wGdV660P0MvBTIIj3h3MU6la82vcPGu7sIOFk7ZEjcuiHjAr14CwO8uqIiPQBU0LvWILm8m02HvHH48LtI90S8gaKIO80my7yxI7e71EmVPMaysTzS0Mq8xBmmO0R2j7xTgiS8H3E3POfmILzQWEA8jgiJPFK82jw2uMG7Fu6uvLY0oTxM6t+8FFocPU1Hz7u87Km8Et8zuwPcnrxX3Zs8tqyOO5BDH7sEWgu9pN7OPNzckzxH9Qu89xHmPBEysjuY9BU7XRO0PHSpjDw6sc67/QLMOgQHLjxfzuo6g4zNuRR4FDxZQry8rlVAPOllPzuS3HG8uju6OYrc2Dyib+s8puJUOCLcPjqgc8i7dBUhPYG4x7tURGw6DX8jPB7GFrzcRK47mTNKPIK5CL1iCVe8CkHvvM8cILxXEBc8qtOgOlBOQT3yF9085MhKvPZvkDxCxhM91vmYPBDmorzs97C8hOsSve8T4zx3HFO8loJRvEtjzDy9oZG8OnhMOzAriLk7Kiw7KxRtPO4cwbz962s8kajrOziXKb3VgpI77W9wvAj8Br1csQi914DtO2prWT2i1E28gQcFvDILBrzpBqC8rW/WO8a6N72k2Xa8zI3PupVRLD1m5Au9GCCauzxXX7w9+Lg7b14GvEV+sjye/To8aR+5vHMRsbwuxoc8todDvKzupbvJK/e54EplO3RdwDwuR926xUSZPO6W4zxRyjw7DIx7vF3Vnrw2usg8NsCfuWVHS7wY6Z+8LjEmPBbdIry73vw8Qp1kvOD66rv4hUM8vXMBPVX2njqLs+Y8fl50O6N3DLs9Hjq84+yoPN/Fp7tS6Ow6J/6TPAOmCLraQko7mUQJPfQRhbwO6xS8ye4BvYt+FLykd9i8FODfvHvlcTxki0+8MAbQvAndvbyQuxo9ZM1gPEbwgTtYPUe8fI79u2AvCzvhMfw8zrDWOzHIjTzHgv+8tlYdO13+qby5kbe8QZDoPJnxSzxmDZI8pLRBvGmGprrWvkO8fNrYPGGENzyVceG8ubwbPGCcmDxeyv+8YLRQvH7huLq8lcC8YvVaPNo3CTiiTTG9J4u6PFFMmzp8f6M7PRDHNx7fhDw7yhe7MTduPKqUGj2TN5q8wYUsPH+i2join8U8SkyIvJA5kLwps5w8uuozvUvyzrwbw+M7mZKXO4JhBzybZKc8yKs3O4sEiTtIpYu7vPofPDWSrLyZMcs6G2WOvDFV4bz4SKE8VHyRvKbF2juPIXw8mvnAvNMCT7vB9ag8wIb/OitlsjuIZjw8NRcRPEVCKjxbHa88FqP9u8SyQjyctCi8MvkQvOlx+zyX3Km8Cyx3vCq9DT3yHZ08EUKHPO2LnrwB84y8EXZuvE6JFD2aqpU5Hnk2PCjmyzuUqYA8hQGmvCAddT2cXIG8NURvvJQaBr2d+Fs8cY/OPN0S+Dx4Lkg87OfxvAcRHbumx0I8ZocmvGRxbzxNRRI99UsovDtDwTu5cNI7UHEtO4b/H7z3NYe6wj+cPMSmOTudaKq8qfz/O5DXRjwO7x4730vtOt95L7z+XOm89JGXvOFXBTzDI3o8aNn6PJ56hLu8KQu8xo5Iu3iXnTxkqQm9SJBCvGaBFLvjVfS8LpAGvcAbRjwUdrM7o/Q2u+zNFjrUrmo82CLgO6lWAb3ZCVU8+XFmPJuxyDwTxSa843pNPcANKjq+8ge6dOK4uzpbjLtcwjg9xYrTvJo8Mjyv5Li8boylvNfwdDyeA5o8QJa/O6/Kkrzzh/e8R407O1Hcp7zeVSc9tRSCvDgVzLxDgfe87MHevI4Xq7okGIa9j8vrO5CVEr3OFtO7NefvPJlExTzji588XdrzPIh2hbz2osk8oeeJOWxGWjwbSOM8kS6YvO/MArz8+Jm8X0STPBl5x7xA/H68H4s8PSGdxjwUft68rEPGvAxfuryOkDE6D/q5O2o7ijzJ7ha8GEWHvLIXED045FM8Fy+BOqKFy7zh4a28s7nDPOyJ/rzWQ7W8otEBPJjUerwfIbK82H3aPE/QGzuCdl69sUzEO98lYjwDcAC6O9euu6znprwCQpe83dSOvFIVRD3+q4Y8KubvPBVWjLzCRKS7qvL3vD1/qjz07gq993SQvBVRyjyMWAg8hxMFPfSmLDwhgLe85T49vB+wBb3nBX285wjoOnMn4DymXZu8mCEDvZe+fDyt0MA82NzGvK8VwjszF2o8qxEnPOLIV7xu8EM8cvH7vNP4bToRaTq802mEPIaOxzyVOgA53UyKPAxUXDxCqZY8XS8cvF9hsjviSq68RQKWPHNvsLwvF028tarVu/NDnTu406Q6Jq+gvFZAEzyguJ28kdrcu44wszvciD26fXBOvO/3SLotjAg9QFQivCWxcrz6Vrs8jSTlO9pq4bwqijW9yKsQPZd/sDwFJ0e8eNg3PJaE9btbEGO8qNqZO5PFibt1w9y8gebGvNNSNrsvmYe8WTxpvDL0brz5tyG8uLe1vA9/LDsqBUE87NqnO63tvzys2Da7ljGrvARMtTzEftu5j1scvNsWj7wLm3M8q+bOvMFGkTyte3M7rrRxPOqmerwuhi85zhA4PRDK1rwvMN68DpEMu/cw07upw4K8hzbPO2A42Tzmjg+9epjvPJPxX7xTScU8DhwrO+u/0bmegC28qd9WO/lPpzwxRwG8OYASPBw8iruPrZG7PC8JvEsKdT0+OTg73ePqu7at0jojIvI6mX9Eu9IbjjtqfEk7g6mjvH5feLsI5rW8sh+LvENcBr1dxia7owZovWnP3bzNST08WHIJvdV8YzubWJI8qnUjOgCMJjtDEci8I/GVu3wzgzxzX4S8ehM2PILxG71Kqrg8IbOCOn6q2Dy6bBm6Wl6dvPDBcbsiZUa9g4trvPwY9Ly0KBo8GKIFvZ2foLsq4As8A2lmvHWO5br7k8+7gD9WOa8hOLxmg2m8reM4vMPpQDx3HNq7tiWpvBZ8P7zxiy88dCiFPLaMNbt34qC8pJMqOgoDvjshE9u8V4ofvDOslryunoq8Nh99PO1krLuD4tI4ipapPHQGZDxYPMA8d9i6PHi4oLtZXMS7b71IPRfxnzuZjE48w/PBPFDfYjwRx+A8uOX9Os9BgTzOe4w7mr+AvM/I7DziESo8sDAwOy3SNrvxZqw8kjUvvPs3ejwqIcG7jHI6PB3RGLzssI2840cNu5oAhrsfXja8N3lbOW5KFzyUqGO8uFeJvFGtwTxovee5wC+mvJFem7z5EPG8heshu73QAzySFDe8CKeROxv7+Lvp2ni8vY+yO3Jz9jzOFa48jcdgO3zDETzlsIc8qS6xPIKhpbvKd2Q8IpFLuz/rtTsK9xK9SnDSOfyMo7v0DIS8euN6u76FOD1piJM8MRQPPPS6sLqKIMq7ULjVPBwxATynpbM83s3HPPSlBr2tkt+6rH8yu4teAzy4cMq6usrrvFCVpbwYUUU8jEDGvCF4JL3swpm8ATOxu+ySQDxa0k67ztwgPIp5CDxIORA6JKU9vecZtbx7V2O8r9w0PIBxvjyEkWW8g4DSOwFy4ryotwE7nxrDvNJ+kjyVDf+8/JLTPOosBDydjoa87NS1uM76srvJQVm9FIqUPC+eFrq9Soy8UZSUu01ZQTyU0dy7KM9oPUz5arxth1Q82yzmPOIVqrw8XnK8cSefvFDFMrtMzXk8/zfkvLBmeDz8uwE97A3wuiD8GDy2uNU6wHeFPLNsaz3xav668wzFu1Ys9btlG7e65J+Hu5GmWDtMk647Vz92vIpPXLzdrRA8zGp1ufmeMr0O+qc76hAcvN8m4rv2HnO7j0RqvB3LHrzliYw7fkjPvL+mo7sMS147LVo+vfBK8zuOsM07KedxPE/qpjtlgoU7u6qAOuB6TbxD3mi7S/33PKrQ2LrCqRG9jDXhun0nAbzr3QG8fZb0uuMGR7uREuS77U0DPOgYuzxE68K7AVlxvJg3xrx4h9o7ekP4O3S1ZDyLDbE8JCytvAyijjwGbKC70orOvN3i4zyXHjo8gEREvMobDT2a3Dq94lZZPE0ElDxQ5Oq8ajEJPRoEFry8pse7Fly5upYbID3Vgs67eRMxvTfXlLx89PW8Nop4uykrvLzRb/M7J01HPCoelTy6HJ68LHKLvArkjTkFpMA7qJvevJCn8zxShPq87lQ2vAP6fLvAXdc747uRO6egAr33m5u6pBCnPN4Y/DsTGNk8T4EWPf0sUDt2BrU7dHTwOxWy7LuJk1G887b5OvgGyrtH2W872DCDPBMMObwbEMI7FRmKO5FOyjxwAYe8P6Y7vEJrXjuhzy07SlVevO9dBD3SWEs8ahnuPH3xtLyu4J86OGeZPPgtnjz4SDo8/K5QvN4+v7wLZ+A8z7/4u9gYdjxlh947lpMEvCjupruCI9K78zfiOR5OzLsh1OE8k6cBvZwF/ztFUcm7zVgjOWWvXjsDSOS8szPePMbCFDyZTAW8sFEVOy42yzwvI0I8rhjwPE4wlDwWvSK8UL6WPI6hsDylLIe7duBjvLD777xhJQ86I/noOig8t7yTIYI8zAG6uuH8tLyI2Mm57VJtvAgUCrxGQ6M7yfH6vMRCM7z8pBK8LjecO+NU4ryxSQw6pNqovIRfeTzilgS9ca3ZPEO/Nzt/3R06vxifvMogMbzV4eW8w6bOu0nObrt69k+6B/bvO/DaB73Y+U88zX9pvJDIwLzBwwe8wl2Ou41gRDxX3GE82QABvTMo/Lv781A6RELtvGnusDvZoPG7X7OFPIJbQDtlrq685h0svIQ0QL1LjfI8W4rsvFIkDTzzNpE7QC0KvIRXqzw18jS9oBRzO1I4BTyKJfa7C98YvLPW17yaZRg9rrdGuzsA9Dzg8cw7sBBlvKMUIzw65tK8QtA6PQ8CgjzZ2qA8gJm/vJXmYjx7NXk8/uG+OstXyTyyODs8ESMdPHb0FzhP/Yq8S6K/O/zkvLyoEbo8iGUCPSVca7ybbCs7B0+WPKzXPz3T0h28ZR/uu4dz6ryknrG80uOgO48XhTq7+tO7KlfyO8s26buBjs67ClW0vJDGBbs1Iyi6EOy5vBJRPbvI74s8pY1iu52VnTqkxBa8RY+hu/0d5DsPWak8MxIbOzQMSztBWei8NvPMOgMjX7uHnuC8VN3vu/4UvLwXpDa8IuFRvESY87yMJ628806iPMmnBj2mlJC8HmtNOnuRkrwHQU68v4t/PC2aBLwf03U8FIUEPbWOA7yoU/O8vqHFvOBv77qBJ6U78kvHPPcdb7z4Hpo8kbNjPM12xzxsCbI8dI0gvL3l/zsd4NI7kqCPvEwqOD0xSZC8JtP8u8rrcDzv3PY6UdalO0vBFj1Afj47kN0kvISwZbw42pK74CdePO5r/rtngMg8h0wVvHYqAr0tbQ+7mXuMvFQJlzxU1IM7veUCPMfhAbxI9ok8tuURPEaQqDwYj3m7jpPhvL9M3jyz/aA8mwrkvJqdSDxnQ4W8+amKvEe4hjqsVUS8Rv7PvO7CHjztSus7vFjivHDgRjx0bjS7q7xbvDAWODpkWjy8Aut9PMy8kLwBg4y7m1aOuwTpmLxnaye9QH+Zuoaumjvrzzg8a0umPHxQozxPv3u8x5qxvOWU3Dssazi9tYzPu88bsbszLgy9aca6u+4LHbxL8VK7mrtavGA/tbvhFCO8IkipPElO0rzb9ve81c1VujPBjDzolCm9oqcpPeeEa7tlSaS7doXtu6Y0qDyd7w89ovwHPNPegjwbEFw89djXt5wgnTxE3Hq8+mL4u5/Pt7s8bjU8bnGZvEpWLDpmp3s867mOvPREgbyqAT08/MW2PEOAAz0QxNI8IrXdO2BL2zv4dpW89KwCPYJWUDsMH/M71WaUvKwwhLwzmtw8YoOBvSQRLDwFg3i70sEkugOmETwbqFc7BDDEu1BHpztbV8S8E0J9PMap3zx5r7W7brNAPOwxe7r+YAy8k4qPvIe6TrxWGPk7lbbSvPBnUL0U7Ry7c9rxvFLmsjy63zU8yKxXvCvgP7y1TDE8rb4yPE4bBD1wsvu7kQq+O8OBurxwyeG8UsOKPMsmPzsYzTm7umhhPPAVnzwBa4Y7/uFCPeI1zrthF8w8fZlHPHaVqDzt1yO7Kr/HPAmulryc4QS785y3PHX5nLxOknw8OA0xPPTMjjzttEE8NcGzu78Ajbx2g4M8mOEmPRRjJLyM9r88XKf+OPj0lboNEIM8XF9euzC2VrzqCNa4Djz4uz3bfTv7s9m8N/IsPIMpxjzAE/68EbhLvIcBKj25p5w7qLIFPQCLHLyFiBM8ZllnPO0mzDlfDaC8pCQ2uUhGCTwgNc679WTcPMqclTu9q1g95ePgPPX9FjwGw4K8RpMDvCXFNrsZOnS8m3WCuxcZLTsPqYu6knOdu5WKxDxoWI+8FAtmvNvPWLx8+RK9rbEavPjj87y+7sM7nGBru5T22zxkv1k78wZEvO3qtDsN0SG7ShEXvXdrKbuW86c7x7eVO9lwdbu1iEC8qvE/PD/ghjwkrsg7eNkEPGYuzDtwiUE8k7M6vOUsGDuaKx47HTkVPH6jEjzlXO47+/IhvH5bwjqlH4e8uFK3vC3rojskO4Q8ti0ROR+7y7zzjqK8nCpTO4QuQLwfhCG81lWovBl8L7w7kJk8KPiCvL+BI7xF+rc76lrKvAU22DvLHrC7UqHCvEy+hTt96N+7yV8Juw==
+ index: 0
+ object: embedding
+ model: qwen3-embedding:4b
+ object: list
+ usage:
+ prompt_tokens: 6
+ total_tokens: 6
+ status:
+ code: 200
+ message: OK
+- request:
+ headers:
+ accept:
+ - application/json
+ accept-encoding:
+ - gzip, deflate, zstd
+ connection:
+ - keep-alive
+ content-length:
+ - '97'
+ content-type:
+ - application/json
+ host:
+ - localhost:11434
+ method: POST
+ parsed_body:
+ encoding_format: base64
+ input:
+ - Third document about birds.
+ model: qwen3-embedding:4b
+ uri: http://localhost:11434/v1/embeddings
+ response:
+ headers:
+ content-type:
+ - application/json
+ transfer-encoding:
+ - chunked
+ parsed_body:
+ data:
+ - embedding: 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
+ index: 0
+ object: embedding
+ model: qwen3-embedding:4b
+ object: list
+ usage:
+ prompt_tokens: 6
+ total_tokens: 6
+ status:
+ code: 200
+ message: OK
+- request:
+ headers:
+ accept:
+ - application/json
+ accept-encoding:
+ - gzip, deflate, zstd
+ connection:
+ - keep-alive
+ content-length:
+ - '7686'
+ content-type:
+ - application/json
+ host:
+ - localhost:11434
+ method: POST
+ parsed_body:
+ messages:
+ - content: |-
+ You are a Recursive Language Model (RLM) agent that solves complex research questions by writing and executing Python code.
+
+ IMPORTANT: You MUST use the `execute_code` tool to run Python code. The functions described below are ONLY available inside the execute_code tool - you cannot access them any other way. Always execute code to answer questions; do not just describe what code would do.
+
+ CRITICAL: Inside execute_code, these functions are ALREADY available in the namespace. Do NOT import them - just use them directly:
+ - search("query") ✓ CORRECT
+ - from haiku.rag import search ✗ WRONG - will fail
+
+ You have access to a sandboxed Python environment with these haiku.rag functions (use them directly, no imports needed):
+
+ ## Available Functions
+
+ ### search(query, limit=10) -> list[dict]
+ Search the knowledge base using hybrid search (vector + full-text).
+ Returns list of dicts with keys: chunk_id, content, document_id, document_title, document_uri, score, page_numbers, headings
+
+ ### list_documents(limit=10, offset=0) -> list[dict]
+ List available documents in the knowledge base.
+ Returns list of dicts with keys: id, title, uri, created_at
+
+ ### get_document(id_or_title) -> str | None
+ Get the full text content of a document by ID, title, or URI.
+ Returns the document content as a string, or None if not found.
+
+ ### get_docling_document(id_or_title) -> DoclingDocument | None
+ Get the structured DoclingDocument object for advanced analysis.
+ Returns a DoclingDocument object, or None if not found.
+ See "DoclingDocument API" section below for how to use it.
+
+ ### ask(question) -> str
+ Ask a question using the QA agent with RAG. Returns the answer as a string.
+ Use this for semantic analysis that benefits from LLM reasoning.
+
+ ## Standard Library Modules
+ You can import: json, re, collections, math, statistics, itertools, functools, datetime, typing
+
+ ## Strategy Guide
+
+ 1. **Explore First**: Start by listing documents or searching to understand what's available. Document names may differ from filenames (e.g., "tbmed593.pdf" might be stored as "TB MED 593" or similar).
+ 2. **If get_document returns None**: Use `list_documents()` to see actual document titles, or `search()` to find relevant content.
+ 3. **Iterative Refinement**: Run code, examine results, adjust your approach based on what you find.
+ 4. **Use print() Liberally**: The REPL captures stdout - print intermediate results to see what you're working with.
+ 5. **Aggregate with Code**: For counting, averaging, or comparing across documents, write loops and use collections.
+ 6. **Use ask() for Semantic Analysis**: When you need to understand meaning or interpret content, use the ask() function.
+ 7. **Cite Your Sources**: Track which documents/chunks informed your answer for citation.
+
+ ## DoclingDocument API
+
+ When you call `get_docling_document(id_or_title)`, you get a DoclingDocument object for structured document analysis.
+
+ ### Properties
+ - `doc.texts` - List of all text items (paragraphs, headings, etc.)
+ - `doc.tables` - List of all tables
+ - `doc.pictures` - List of all pictures/figures
+ - `doc.name` - Document name
+
+ ### Methods
+ - `doc.iterate_items(with_groups=False)` - Iterate all items with hierarchy level
+ Returns tuples of (item, level) where level is nesting depth
+ - `doc.export_to_markdown()` - Export entire document as markdown string
+
+ ### Text Item Properties
+ - `item.text` - The text content
+ - `item.label` - Type: TITLE, PARAGRAPH, SECTION_HEADER, LIST_ITEM, etc.
+ - `item.prov` - Provenance (page numbers, bounding boxes)
+
+ ### Table Access
+ - `table.data.num_rows`, `table.data.num_cols` - Dimensions
+ - `table.data.table_cells` - List of TableCell objects
+ - `cell.text`, `cell.start_row_offset_idx`, `cell.start_col_offset_idx`
+
+ ### Example Usage
+ ```python
+ doc = get_docling_document("My Document")
+
+ # Get all headings
+ headings = [t.text for t in doc.texts if "HEADER" in str(t.label)]
+
+ # Iterate with structure
+ for item, level in doc.iterate_items():
+ print(" " * level + item.text[:50])
+
+ # Extract table data
+ for table in doc.tables:
+ for cell in table.data.table_cells:
+ print(f"Row {cell.start_row_offset_idx}, Col {cell.start_col_offset_idx}: {cell.text}")
+ ```
+
+ ## Example Patterns
+
+ ### Counting documents matching a condition
+ ```python
+ docs = list_documents(limit=100)
+ count = 0
+ for doc in docs:
+ content = get_document(doc['id'])
+ if content and 'keyword' in content.lower():
+ count += 1
+ print(f"Found in: {doc['title']}")
+ print(f"Total: {count}")
+ ```
+
+ ### Aggregating data across documents
+ ```python
+ import re
+ numbers = []
+ results = search("financial data", limit=20)
+ for r in results:
+ matches = re.findall(r'\$([\d,]+)', r['content'])
+ for m in matches:
+ numbers.append(int(m.replace(',', '')))
+ print(f"Average: ${sum(numbers)/len(numbers):,.2f}")
+ ```
+
+ ### Using ask() for semantic analysis
+ ```python
+ # First search to find relevant content
+ results = search("machine learning approaches")
+ # Then use ask() to synthesize an answer
+ summary = ask("What are the main machine learning approaches discussed?")
+ print(summary)
+ ```
+
+ ## Workflow
+
+ 1. **ALWAYS start by using execute_code** to explore the knowledge base
+ 2. Run multiple code blocks as needed to gather information
+ 3. After collecting data, provide your final answer
+
+ ## Output Format
+
+ After executing code and gathering information, provide:
+ 1. A clear answer to the user's question
+ 2. Key findings from your analysis
+ 3. References to specific documents/chunks that informed your answer
+
+ CRITICAL: You MUST call execute_code at least once before providing your answer. Never give up without trying to execute code first.
+ role: system
+ - content: How many documents are in the database?
+ role: user
+ model: gpt-oss
+ reasoning_effort: low
+ stream: false
+ tool_choice: auto
+ tools:
+ - function:
+ description: |-
+ Execute Python code in the sandboxed environment.
+
+ The code has access to haiku.rag functions (search, list_documents,
+ get_document, get_docling_document, ask) and safe standard library
+ modules (json, re, collections, math, statistics, itertools,
+ functools, datetime, typing).
+
+ Use print() to output results. Variables persist between executions.
+
+ Structured result with success status, stdout, and stderr.
+
+ name: execute_code
+ parameters:
+ additionalProperties: false
+ properties:
+ code:
+ description: Python code to execute.
+ type: string
+ required:
+ - code
+ type: object
+ strict: true
+ type: function
+ - function:
+ description: Result from RLM agent execution.
+ name: final_result
+ parameters:
+ $defs:
+ CodeExecution:
+ additionalProperties: false
+ description: Result of executing a code block in the RLM sandbox.
+ properties:
+ code:
+ description: The Python code that was executed
+ type: string
+ stderr:
+ description: Standard error captured during execution
+ type: string
+ stdout:
+ description: Standard output captured during execution
+ type: string
+ success:
+ description: Whether execution completed without error
+ type: boolean
+ required:
+ - code
+ - stdout
+ - stderr
+ - success
+ type: object
+ additionalProperties: false
+ properties:
+ answer:
+ description: The answer to the user's question
+ type: string
+ code_executions:
+ description: History of code executions during the RLM session
+ items:
+ $ref: '#/$defs/CodeExecution'
+ type: array
+ required:
+ - answer
+ type: object
+ type: function
+ uri: http://localhost:11434/v1/chat/completions
+ response:
+ headers:
+ content-length:
+ - '519'
+ content-type:
+ - application/json
+ parsed_body:
+ choices:
+ - finish_reason: tool_calls
+ index: 0
+ message:
+ content: ''
+ reasoning: We need to list documents.
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"docs = list_documents(limit=1000)\nprint(len(docs))\n"}'
+ name: execute_code
+ id: call_hk3j646j
+ index: 0
+ type: function
+ created: 1769703338
+ id: chatcmpl-806
+ model: gpt-oss
+ object: chat.completion
+ system_fingerprint: fp_ollama
+ usage:
+ completion_tokens: 46
+ prompt_tokens: 1599
+ total_tokens: 1645
+ status:
+ code: 200
+ message: OK
+- request:
+ headers:
+ accept:
+ - application/json
+ accept-encoding:
+ - gzip, deflate, zstd
+ connection:
+ - keep-alive
+ content-length:
+ - '8124'
+ content-type:
+ - application/json
+ host:
+ - localhost:11434
+ method: POST
+ parsed_body:
+ messages:
+ - content: |-
+ You are a Recursive Language Model (RLM) agent that solves complex research questions by writing and executing Python code.
+
+ IMPORTANT: You MUST use the `execute_code` tool to run Python code. The functions described below are ONLY available inside the execute_code tool - you cannot access them any other way. Always execute code to answer questions; do not just describe what code would do.
+
+ CRITICAL: Inside execute_code, these functions are ALREADY available in the namespace. Do NOT import them - just use them directly:
+ - search("query") ✓ CORRECT
+ - from haiku.rag import search ✗ WRONG - will fail
+
+ You have access to a sandboxed Python environment with these haiku.rag functions (use them directly, no imports needed):
+
+ ## Available Functions
+
+ ### search(query, limit=10) -> list[dict]
+ Search the knowledge base using hybrid search (vector + full-text).
+ Returns list of dicts with keys: chunk_id, content, document_id, document_title, document_uri, score, page_numbers, headings
+
+ ### list_documents(limit=10, offset=0) -> list[dict]
+ List available documents in the knowledge base.
+ Returns list of dicts with keys: id, title, uri, created_at
+
+ ### get_document(id_or_title) -> str | None
+ Get the full text content of a document by ID, title, or URI.
+ Returns the document content as a string, or None if not found.
+
+ ### get_docling_document(id_or_title) -> DoclingDocument | None
+ Get the structured DoclingDocument object for advanced analysis.
+ Returns a DoclingDocument object, or None if not found.
+ See "DoclingDocument API" section below for how to use it.
+
+ ### ask(question) -> str
+ Ask a question using the QA agent with RAG. Returns the answer as a string.
+ Use this for semantic analysis that benefits from LLM reasoning.
+
+ ## Standard Library Modules
+ You can import: json, re, collections, math, statistics, itertools, functools, datetime, typing
+
+ ## Strategy Guide
+
+ 1. **Explore First**: Start by listing documents or searching to understand what's available. Document names may differ from filenames (e.g., "tbmed593.pdf" might be stored as "TB MED 593" or similar).
+ 2. **If get_document returns None**: Use `list_documents()` to see actual document titles, or `search()` to find relevant content.
+ 3. **Iterative Refinement**: Run code, examine results, adjust your approach based on what you find.
+ 4. **Use print() Liberally**: The REPL captures stdout - print intermediate results to see what you're working with.
+ 5. **Aggregate with Code**: For counting, averaging, or comparing across documents, write loops and use collections.
+ 6. **Use ask() for Semantic Analysis**: When you need to understand meaning or interpret content, use the ask() function.
+ 7. **Cite Your Sources**: Track which documents/chunks informed your answer for citation.
+
+ ## DoclingDocument API
+
+ When you call `get_docling_document(id_or_title)`, you get a DoclingDocument object for structured document analysis.
+
+ ### Properties
+ - `doc.texts` - List of all text items (paragraphs, headings, etc.)
+ - `doc.tables` - List of all tables
+ - `doc.pictures` - List of all pictures/figures
+ - `doc.name` - Document name
+
+ ### Methods
+ - `doc.iterate_items(with_groups=False)` - Iterate all items with hierarchy level
+ Returns tuples of (item, level) where level is nesting depth
+ - `doc.export_to_markdown()` - Export entire document as markdown string
+
+ ### Text Item Properties
+ - `item.text` - The text content
+ - `item.label` - Type: TITLE, PARAGRAPH, SECTION_HEADER, LIST_ITEM, etc.
+ - `item.prov` - Provenance (page numbers, bounding boxes)
+
+ ### Table Access
+ - `table.data.num_rows`, `table.data.num_cols` - Dimensions
+ - `table.data.table_cells` - List of TableCell objects
+ - `cell.text`, `cell.start_row_offset_idx`, `cell.start_col_offset_idx`
+
+ ### Example Usage
+ ```python
+ doc = get_docling_document("My Document")
+
+ # Get all headings
+ headings = [t.text for t in doc.texts if "HEADER" in str(t.label)]
+
+ # Iterate with structure
+ for item, level in doc.iterate_items():
+ print(" " * level + item.text[:50])
+
+ # Extract table data
+ for table in doc.tables:
+ for cell in table.data.table_cells:
+ print(f"Row {cell.start_row_offset_idx}, Col {cell.start_col_offset_idx}: {cell.text}")
+ ```
+
+ ## Example Patterns
+
+ ### Counting documents matching a condition
+ ```python
+ docs = list_documents(limit=100)
+ count = 0
+ for doc in docs:
+ content = get_document(doc['id'])
+ if content and 'keyword' in content.lower():
+ count += 1
+ print(f"Found in: {doc['title']}")
+ print(f"Total: {count}")
+ ```
+
+ ### Aggregating data across documents
+ ```python
+ import re
+ numbers = []
+ results = search("financial data", limit=20)
+ for r in results:
+ matches = re.findall(r'\$([\d,]+)', r['content'])
+ for m in matches:
+ numbers.append(int(m.replace(',', '')))
+ print(f"Average: ${sum(numbers)/len(numbers):,.2f}")
+ ```
+
+ ### Using ask() for semantic analysis
+ ```python
+ # First search to find relevant content
+ results = search("machine learning approaches")
+ # Then use ask() to synthesize an answer
+ summary = ask("What are the main machine learning approaches discussed?")
+ print(summary)
+ ```
+
+ ## Workflow
+
+ 1. **ALWAYS start by using execute_code** to explore the knowledge base
+ 2. Run multiple code blocks as needed to gather information
+ 3. After collecting data, provide your final answer
+
+ ## Output Format
+
+ After executing code and gathering information, provide:
+ 1. A clear answer to the user's question
+ 2. Key findings from your analysis
+ 3. References to specific documents/chunks that informed your answer
+
+ CRITICAL: You MUST call execute_code at least once before providing your answer. Never give up without trying to execute code first.
+ role: system
+ - content: How many documents are in the database?
+ role: user
+ - content: |-
+
+ We need to list documents.
+
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"docs = list_documents(limit=1000)\nprint(len(docs))\n"}'
+ name: execute_code
+ id: call_hk3j646j
+ type: function
+ - content: '{"code":"docs = list_documents(limit=1000)\nprint(len(docs))\n","stdout":"3\n","stderr":"","success":true}'
+ role: tool
+ tool_call_id: call_hk3j646j
+ model: gpt-oss
+ reasoning_effort: low
+ stream: false
+ tool_choice: auto
+ tools:
+ - function:
+ description: |-
+ Execute Python code in the sandboxed environment.
+
+ The code has access to haiku.rag functions (search, list_documents,
+ get_document, get_docling_document, ask) and safe standard library
+ modules (json, re, collections, math, statistics, itertools,
+ functools, datetime, typing).
+
+ Use print() to output results. Variables persist between executions.
+
+ Structured result with success status, stdout, and stderr.
+
+ name: execute_code
+ parameters:
+ additionalProperties: false
+ properties:
+ code:
+ description: Python code to execute.
+ type: string
+ required:
+ - code
+ type: object
+ strict: true
+ type: function
+ - function:
+ description: Result from RLM agent execution.
+ name: final_result
+ parameters:
+ $defs:
+ CodeExecution:
+ additionalProperties: false
+ description: Result of executing a code block in the RLM sandbox.
+ properties:
+ code:
+ description: The Python code that was executed
+ type: string
+ stderr:
+ description: Standard error captured during execution
+ type: string
+ stdout:
+ description: Standard output captured during execution
+ type: string
+ success:
+ description: Whether execution completed without error
+ type: boolean
+ required:
+ - code
+ - stdout
+ - stderr
+ - success
+ type: object
+ additionalProperties: false
+ properties:
+ answer:
+ description: The answer to the user's question
+ type: string
+ code_executions:
+ description: History of code executions during the RLM session
+ items:
+ $ref: '#/$defs/CodeExecution'
+ type: array
+ required:
+ - answer
+ type: object
+ type: function
+ uri: http://localhost:11434/v1/chat/completions
+ response:
+ headers:
+ content-length:
+ - '706'
+ content-type:
+ - application/json
+ parsed_body:
+ choices:
+ - finish_reason: stop
+ index: 0
+ message:
+ content: '{"answer":"There are **3 documents** in the database.\n\nKey findings:\n- The `list_documents` function
+ returned a list of 3 entries.\n- No further pagination or filtering was required.\n\nReference: The result from
+ `list_documents(limit=1000)` showing 3 items.","code_executions":[{"code":"docs = list_documents(limit=1000)\nprint(len(docs))\n","stdout":"3\n","stderr":"","success":true}]}'
+ role: assistant
+ created: 1769703340
+ id: chatcmpl-326
+ model: gpt-oss
+ object: chat.completion
+ system_fingerprint: fp_ollama
+ usage:
+ completion_tokens: 117
+ prompt_tokens: 1694
+ total_tokens: 1811
+ status:
+ code: 200
+ message: OK
+version: 1
diff --git a/tests/cassettes/test_rlm/TestClientRLMIntegration.test_rlm_with_filter.yaml b/tests/cassettes/test_rlm/TestClientRLMIntegration.test_rlm_with_filter.yaml
new file mode 100644
index 00000000..27ad243d
--- /dev/null
+++ b/tests/cassettes/test_rlm/TestClientRLMIntegration.test_rlm_with_filter.yaml
@@ -0,0 +1,2768 @@
+interactions:
+- request:
+ headers:
+ accept:
+ - application/json
+ accept-encoding:
+ - gzip, deflate, zstd
+ connection:
+ - keep-alive
+ content-length:
+ - '83'
+ content-type:
+ - application/json
+ host:
+ - localhost:11434
+ method: POST
+ parsed_body:
+ encoding_format: base64
+ input:
+ - Cat document.
+ model: qwen3-embedding:4b
+ uri: http://localhost:11434/v1/embeddings
+ response:
+ headers:
+ content-type:
+ - application/json
+ transfer-encoding:
+ - chunked
+ parsed_body:
+ data:
+ - embedding: wPoaOASvpDtAjuI5KTIFvaO4PTn5Lg89Ub2HPaRiD7nEg5c8Vw7+Oyf0wryoVyg9+X0NO0nInLyEFJY7/Et7vRGjqzsDQTi9czawPJV6FTrbXJ68zj75O3CEuzyMg5u8El0ePBfJqjrshsC8atZ4vQeuID0e8na7CSD5um/Lmb3Be+486YyTOq2DcTvcrzG69ZTTvK8SObsIcf46SdwxO3M2p7ySTCs866vWPAFIKjvHgcu6Dl4Mvab3ATx2hUM9xJInvSEfrrwxDze7XYGqPF2OB7yPtiO8qqooPJI4q7tI0gU8U3o/O/IzNLwXXoO8ZFeVu/4LWztGsAe8HH/iuqtewrs0Pky8e1WJvBuvmrzfcxI8EhBtvAjkhTsq4T49ra/buVQwrjtai4K8OdofvZKdaDns0yA9KK7lvK84tzxbQjQ8LBYlumTMabx0z0E9IOmsO1vZkzxCmE47KLysPBqHvLzuEdK6pFJ7O3MYmzwB9mM7ppEfuhBp1DsF0bO7eRN7vNmChrwOsJG7KNqKOlyet7uVR3o8VbwWPYEw1LuiHpK8D/jYvLzaVLzjQ5A7my2IO/F22TtCrLG7ZadUO0YR27xFrhU8Tg6AvMag9LyKZAS8zd+yPL+vgjvfeJk8WihzOsIyfzwbF3O7qbeWu6OfjDzhs6C8HwtqvOVhXrzBpFE6vG5oPJ3wgjwxZZi8QK8MPVR1b7u6+q48iPexOzdSfDoLUSm8mn2fvJYPZDxvIEu8fWanvMExAjwErf08GjGuvKRXmrwV0Ku8V1+1O3Sb7zqFHDK7hp0YPKDaX7y168Q7oozrO50UJTzGx5g8YN9ju36R4DtlBr47lOsfPKkQOjtoF1c8bTYUPJuG4TzuIKg8JiuVPIfSrTvsJK+6bhUPuhnpVLytqxy8YwUSvMON5zs1AoO7PkGAvHhjjbuiaB69oNRMvH4rhTktLPE8iHlBvCmKIT2YNGm8frfqO+G2Wzwh0XQ7AvCMvAsExTtkX+27z3dfuuOPjLxF4+Q8dD4BvHbV3bvQ9Eu8l8DFuwm4qbxI7s27ERoVPNLH7TzVjYI7gB4aPGWmCbtOcEu83LoRPFIgCryMlGK7MV0tvHiLVjyCOC28EKnDO9r6gzxuklS8oBGxuIhBqTwDeoE8/htEvLrokbzQ25I8o5HuPOXa/znX1iK8n5LEvA4BDDyDRcm8eNVRPEJXMTztdwI5N2TyO/r8q7x0Idk7DOCgO1y1orsFcYG8LpyvuZUaCjwMLN87PMeSPFizNTyNCxa9lmVbvObgsbxCk5m7BfhoPF2OwjweNgw7xRXPu+dOiLuo4Ta8txcCvcEwabutt5k8jqYVOWhNZrwWYca8qCAMPIfzCrxlHgq819TAPMiphjzbNsQ5Z9cju6qm4zvxaHa8Co8RvIrJEbzdGOg7DllJvNUvljtpyEW8t90SPf5gKzwuunA8qD/nO/LhzzyoREI8lvgQuoYrJbo2/OU7F3kOPVoMy7w768878f2ZvMwuajpUhIg73P+ru3lcVLxLOyM7Cv95u20YYLsVpMo88Iq5vB4ltjsJjma8YexgvLxxBTwTg6Q7lTlaPEwoqLxBXVK8GGEQO/6nRDw0rmy6NBywPCZEDD3JdI28q6QBvPD32TvQvIW8S8n6u+zKyDu1mno6j7jCOyPZtLsl15w74R38vL1qkjxArWs8nTurunzFGb21//a6+wAqvXFJAL1c7ZM7OZObu1RPjLsNbgY8BwrRPPsYxzzK15Q8QJO0uQnUnzw3X8+8dNmHvHzutzo2glA8CTgRvHoo3Dxi5SM9XS8FPCjBHr1tylg67RMCPOaRr7xIfHC9czjTuV7SSz1ilcI7Tmp3vIB8OL3W9KS8DHYCvXuLI71QnZ+7rmWnPF5c/jw7E+q7dtuvPKkCvzvJLVW8H05WO86z5TqrxbY78ffePMcb0byUlGM7wG8evNYxET0j7ya9dZ2au3M0rbuOf+I6nOH+PObMkzxwfJE729OVvPmK0bs+VVi6Nh/yvF8OC7yjBRG7SStzPIdJqDtimY08V6w7O0KqtTxg32y6YBnKvKH8kzmmzxg8jddUPKNVL7xNgDo7yE2jPIPqCrtvRwO8ygBYOmlK5zzPthM96dnPOwoQLryqsg68gXOIvKAWyLp1yKk7K/fivMCtuby4gWg9lm5wPPsyjLt+nUa7O88WvHv8EDyTbbG8t2csvWIHCjwt+vQ89pHHvOML57wdUgc8nKXhO51dG7yBjpo7oSWtvBovRjyJEh68M5MIvcnJNTzQ9Mm857yNvGt2OLzi8Qo9YN+0u7YmQj39S/S76jAjPP6ex7w7lgy8QsTuOwAqLr2RSL88fuH3vGLHsbo8s988TolJuuu9rzwddUw8dmURPNL51TylaF692kPIvAhuvbvDSTI6pwmUutiPU7xgTlu8+m+dPDF1kbyG8C29Czn3vKKPVL3gqpU5lDTLvCSlorzpshk8Ag4hvS3iRbw96r47zITTPETOJz1YJ6a8FpoOuxorU73tlpU8sZWUu85LpDw/sIk8qPdaO/fBEryOgZs740FcO06fq7xGfQw9ZUpdPGV/RLwZt8U8ffcIPYyM5zr0qA46BpL7vLw3+jwfko672/OOvFHMdjtlUdG7tKSAPKS7Pjw4YCa8+I5JPGM0+LsULZ+8DbJHPR56bjxbvsO8vAQkvRy05Tyo+Ty753V9upYwZTprfCc9U3IePRZNl7uY6JS8xbSjvDfc3jsAtUa88j7yvPTuFrxl+Kq7ppYPvM8Svjvn1Vg8A68aPbtbvLzwqZS6U3Vsu4lhlDxirCW81p1tvAfOyTvVBZs77rIfvGAJlDzWhoG8z0dtvUvkkLw2wwy7HuyePBXo3jzR84c6dAEnO4ch6bz/x2g7tAbbOwGzOryZiHy84eIlu+eazDyz6dO7kVyAvPc/sjkwmv+8cOnDuQL3p7x6Bjk8o7vnPE2hfbxrQpg8y6DlOweLvjxsiXI8GXSIPNpWQ7zXKK08fYzTPN6OybxXvJ68Bdktu2iBrrwWQA68cVIevMahcjwc94E8iifFvOPQOr3NhjC8O4gFvNlEXDzoOdy85SVhPHxwcTz1i8A7/FBSuuuAgrtBWik8HiTmPC5WETz7UjS5MehiPLQhTLxogYi8h044u/jX9bx7Nvq8LerZPMCHvLrJ3yW8WqAuvaNdxDu1Fl68iKGpPH4nAL1Cu4a7e+RSPM8DAbylL2k8TtITPfbu9rt0VkS9vwKjO235k7sT0Xe8pu1qvE64jjmQ3sg8PcoHvU4O/LxnCMO8i6gKvYX+m7zeXLS83k6mPJB5gbz3e5w7o2b3OnqJJr1y17y8fMn/OxM9mDxvDkK83Cm0vMpQF7pqbiU9Ef8BO5Fa9zyp/Xm8YSuRvM21oDzOteE7NIfWu2hI7jyBtBA8yTm7PH1DUjw+lD89otNWvAjp+7wabgC82kh/PA60tDuboMG6ZCbYO0EbabtzRnk7lIACvHTwCD0s4mo9mnReuus1eTwIdwI8JRQ/vOgaNzxJ8767zFNJvPccqbvOXsy80TulvNvsjbsXzb88h/4HvHR0GzyiwIO5fkg/vD/VzrtIx8c85BRgvSgs1DvT2EE8SufVvCEoPDzxbR46TMYpPPcSPDynqdK8GJWYPCk+GrwKYwE9Uyq2ulb7BDwLZs88gSgTPANwJbyyazg86JHXPG2y1Dxrwl093AE2vIP0QDyT2yi9AmfivClc0rza3+A8y/IAvJLgM7wwzvu8SfaKPDTak7sEbrY6TVktO5WV7DwLlXI8Y5wBvW/egbs6dma8+ibovPOlHrxeyQm9OsG8POu1jbx83GU7c2XGPNiXDj3e+qa87I1IPNYuvLx1DTS8pB4jPXM+0jrAUwa8kEo8PVYLQjrdc7U8AtL+vHB0jDxg4Mi8GqX+O+etvbsfmwa8CUd8PBQE1Dxkmd66p5mTO2MbyDzwWtG7JKR2vcUPEzzJvsW8GOxiPOuMcDw0rcQ7pbKNuxR2QTxKqyI8tq4fPHbUqbxDl2G7dRfnPJT+SDzva6Q8cLatO7+gSDsCuxa8UgoAu6x0FL1qHpK8OMszOoaK5zuKFM28OuzGvHTvxTy7Kxi828NHvEJNGbsZZGK8RnASPT0WALccmhS78BcmPM7YbDuWOKi7llivPOFJ5rtV6vw8om6Bu6qpgrwlSmk88tbkvKwL3js3aq27O5SgvPDzRjsiswY7qmfUvLADYjyC/jE8MtmbvNft7rqEYce83WYMvU3Brbz7h6y8TzqrvG+yBz2KQ/g8QFLKOwA8tjzec3y8vbj8PELUCrwnN+K7ZSIRPJfMjrxbaZE8+3WkO/c2DLsmyu68DdzmPEzIvbwHNFw6oq42PO80jzr59OU7HrQHvMKcnjsUpps8Y0o+PHIPQD1wexW9OAz+u2OUzjzofkE8771Xu5qpJTwn+387LLBJvDWWj7yoheI8vqirvOjjnLy9ihW9uu/mvCdO5rovynM8UMYiOjCnlbvQ8nE4HHrPOoXUwTuLkg66f92iOxqprjyKqow8gZCQPPW/pTuR2xE8j6WRPFfn4DunTZI7dc4YPHLltrzBEsM8t2aeu8EphbyNIBa98/61u7OSWrq9Lp877doAvGsjDTzCYgK9GmgOPXODLzwZ+hQ74pc1PARKjTyUQKO7Hzg4vNkMxDuAAZi8mfMcPM7lvLsZUC68jPmVPFDMGbub48C8ZdjcPPszdLu9izc7oJZaPPBOLrwX2Sg87NQcO38p6ryWFmM8VgV4vKcsIDvMeyI86gN0vJECo7knFxO9iPrnuq7mnjxDfho8KbsSPQ59Sjpk5fU7hTAtvZFQczz3YLw6O3GrPEw85by5KxG8S2StPIqFJrxYtwm9i1sVvFYuHLyCA+Q87cqhvD3dDr1V5gs9/nVOPOLfobzB9NW8NM0cPYcKEjxOa4m8zZbjvKiw9Lxleo87R2Dfuy9v1TueZyy89UfYPDzRgjtWVJ48PrD+uqIaYD06Uxk9FlkCvZPayby6Nt46dmduvAYKRDz9NxS9kTuHPBV9yTyxHS05Hd96PBCNQDpEkY88Lyd8vKEchbyPR9K7jkGOPKr8B73xD6q89ZNAPJ147rxkzjk8L6hEvCeCGzzLRV47MrynO4vZHjuQ0l48bjiJux4k7LzUp7Y7GE7yvCD4Trrto5u65hjbOzKQgzzlOdu8CmRRu/FzTjwU4Qg9hXcJPfuD2DzcDo284LErPLsO8zwwCwW9//UcOzU9RLwG5bE8W8CbvJOde7xAaek7RY4dPJqleLy2hN485lRfu+NjM7tSrew8U+/6vEuVDD2nqAo9+TFPOx53irw/bu88hffNOvTU3zrLkj87/Ba1O8r8Hj3+tEG8kLa+PObeJrw9nhe99A5au2NysbwyoIU7GZKfu/YmgLtRGS27w0vqPHDGOb3pI8o8ObyevHlqpbwfx2M8Y5M3PHUA5Dxko/47UwPZPOIrnjuuwKa8YD2CO9EORzwcx+28W1wQvexu/TvwPkW8c5rivAh7/Ly8jwG7h2UjvUwbnLyb8EC83LGzO3surLygTY48BUOzvP6Gjbw0D288GZGLPIUrMr2U5iW9IxrTPN10lTx/1I47eIFPPOssUbxqwxg8wNioPMzMhLxjM5g8Cp+wPKWbPjzjCtG83xsRO0Upn7zusJq8XPPBu9J1qLwniE48uZNzPCKXCzyESGy80GlrPE+RdrwqwZa73yzqO7YPpTuFrE080FlsvA4+o7ywj108wng2vVDW0LxHQ7S8kYsWO6PzfbsQ3f27f9slPWcIFjv5B4u8XoIlPQxenzwPGKe8dNHbPK7Jejz55jc9QDwePMxZYrwLgaW8G/2FPDy9wjkFa4E89T8XvL6dy7ofQei64ZEYvTsPtLyvcHc6AU29uxteaLw6sUw9hbTLvHPd8rskelO865k1u7JZ6LzbY288f6g9PPM/iLtbZsC7P3/ku5yUnryUEWs8sl9EOxbsAz3Dkom6UVHGO1vPkjzB/Ju8KEILvVcG4bw9EZa8EN2Uu0NI4zqbPSc7j8URPSQgvDx/XES80u5PPI8PpTyTnuO6VKT5vFSUBrxOWqM6FPwTvWTdlDzDGZ09ppWpu51hqzy2vYy8a1sCPXjkOrvCEwI8/LzvO8ugIDyVu547YfGAvC5r3ju507o8OOuXPGRZTDy75y0892A7PAECTbsbvim8k8govDJNVDx1twK6D58SuwCp+Tps/jK8h85iOjOMprwwjQA9YMMsPCCeizzwn/G7A3dZPbgXgbt9uEs8P1gcuJXgzLs5l9q7irhKPNCkm7xmIwW9OQMdPHkypzzgoSu87ETyu6UOljy++CM90oKou5KjC7z/RHq87ep/PH24BzxgYmI8iP+VvC4yyzzUpaa8hUwpOx4JQLykOIQ8GZEHvZVIvDwLMLQ6gpR1u2/tH7rlZA89DPSVPPtSIjjH9Y28SsptvAWdAz3cefm7WC2oO3XzgLvdVuc79oh7PO+DqjzK3JG81umzvLsUeDvqWOC8QS3Au2diLbxs4JU7zj3kO5jyxTv0ysE7Y7wKPQj7SDwU7Vs81fAHPSRh6LxD5B+7/IWgvJUzLr2ZRm481CtzPHonmLuQo807/PC4u1gqJDwjMzg9x2bDO8V8v7zZ97K7T6HFPHnpUjtCJzy8ukhjO6K2KL3y8UY7+biou/m3FrtjONA8myEnPJY2X7tldw09pZWmuzDtxrwbiBq98C6kvHCSizyFqOy8fnu9PHag0Lz8cg28g7MKu5/ZjzwN39I85fV6PNDXDzyIf5S7T8uHu7jsN7zUSEW7xMn+vJTwETzCy+48GQmzPNw6XLx1fX68tU8Zu8NzJL0euBi9DwbvPByLAL1MADi9N72yPNgGizyTUwu9L7khPCv+JjzNCQa9STFiunlLNLyvyN+7ZBCrPFQg5btjETa702L6OuR17Lunylc8PoGevPPSZbtIqw67dn6RvNhJBr3oUhO7u9KCOwRkgrxX5+47H7Eku8zqG7yBlzu8CYkgvaE597lRVm88hlgpPFobJjuQ2AY5+Smdu+ZibTy8KjK9rIVgOzBvubztwDw8uGRTu+y/gLtGo+c788/TPOPixjzsjV88nFvivNYEGD2fl448XFFIPWNOILxO35q8UnR0umw8y7zSAqQ8aB31PIpFvbufknu9DmdzPLuiczxOmMq89MqtPNoFFTym6r08lM7uuj7Cabsz1gg8zB1FPKV3a7v/CpO6CvPMOhBcpTysO4+8T/22vJ68bryXoKW8yndZuyLqRzxifAE99NxevMu6ETyQXTc8Ub7OPLh7rbyWAqu87o9JuwfFj7ztR8K8OZ2mu1He2Ly3dym7eek4u3XH07uJuay8w6ZGu4ELtzyQA9E8wsm4vCUG9DoaQmY8LFQRPEA5bryire06m42AvO1J0DwOOZw8YHsSO3KzAz3VID88ZvhTvKJqqLwRl4I8sBauPFxjEb2tRxK8jNsIPBZnRbx1eqo6Puv6O0a6irwL0PG88eSBu7+9Vj0DQ/m8pD0KvOog4rx8wUC8dzOEPJe0qrxEZJm79T8evJD2Pj1K0ri82WFYvL6y6LsnDss8No+cvPlyEj0mIpU8o3ltPAHMybtyFS+8/ynxOw4pvbutL8W8WiNzPJ6wHLgHArK7Kn+tPPsQPzzSVBQ8DdSRvL1jibyFuYG8p13Ju3JOp7v/Dam8GmatO247L7yw9ok6zz+3vAZmD732SG47DufgPCC3eLqaUxM7NELCPJ8Ld7wl7lO8aG/YObKEyjzPvJg81HQ+O+QrSrud3XW6YdUsPMGCDLxoU4e86gOkvAjeB7vNvgq9sHbLvDdsajzJpoW8zQWLvCr7wLtoV0k9M96VPBIi2buX8ng7IEFyvJ4++rtg/Xg8vMyOPAAifzzY5cy8pM8fPHDoCbzj2ri5NIMEPVKiXbzS5Bc6Db0Xu1EytzxXXYw7Tx48PUc7ujv9OpS8kutKOxg9l7yyJmC95q5QO6rr9rvHGvC8uxXIPGklGzwo7e+8Cg7GO9ujTLzVpXW76NM8PO01Az1W/Qu7Vw01PGUzKz09qrK8402FPPqQTTzGTZk8zVmnPLPWm7txwY486FzDvHzMIbzLw1G85bqJuy177jqodpM8KTHHPMWqBjxAnzA8DUkEvNTx67yg6zY9s5SIvCpYKr2uZCc9Q6U3vKsgLzqo8IE8hg3yu5L9/jvLx+g8ZR9BvK3ctTuFje48WkKNvFbzqzq8uJI8XCr6vFcezTw9wtm8dbojvGzMFTy1hj47SPQHvX2h8zx5oI48WDtiPDlparwKGIc71Q0+vDHpaj3Yska7qxPRO8536DqT8Cg8GqfOOlJUnjzXnty7DfKePKCc57ygIJA8wymxPE7U8zzpo328keNhuyCru7zU/sc8pzddvMDkjTy5RT08iHJIvOv/AjxB51i7oTs1O1SsXLyZgyG8zemoPIqew7u0L8O8SERuOxNUhDy5NGW8/JDgPEmnQbzdMYa8t/ZWPOcB9jw3eDc8tMvaO1AR0Lzmlqu8wrfHvPjuhTxP49y81HsuvBB5NDvTHsO8P8WAvHsFZTdKL9S7skIUPabuLbzhyXS7JCCZvECMk7zQigI77oilPKZXb7yogiI7EPsEPUmOjLyhujk7PgWLuyLs3DyjhUA9Cl0fvM4DNz1zbdk69QfKubfOpjxL4oW7egJTvEifOTzibBq94QsQu5IrPLwdkCE9Tgc8vOPYBb2CEYy8UzQQvSr4wDvbyRq94QkuOv0WFzv2sMk8OhyxPKS9sDyxHVe8a/IjPc3OYLxhoM87hS2BO/raEz3agrE8aLSAu9YUXjtkZsW8GWgAPbR9/byE3228GOj6PLd5frybT1a8tfUGPMAN6zvN4QM88T0zPJm9QTznQpC8w116vBfZMz3txis8c+jUOyBs47xdLIy8lGscPTtL3ru659m8kVk7vIBjt7y5T648cPDfPGEtC7zaJYe88RUiPKYRxztoMLa8QX4xvYB44Lyr0Y281jeRvMMsMz2yXq+77XPyPG00GjyOdZe8cUg4vOIUVLwi5fW8xWExPAf3ADw8vuS7FRT9PJoCl7tDRN670YeivFr41rypZR6742mOPMY7Aj3wvbS8+S84vejXYTwBZko8It8LvBz34TszcT08iDADvZ+fyrx6Anc8mW1KvVzGTTsXita7nOqEOjhO6zu8qCg8KuroOxF/xTvR56e7j7ywuyzWjDxKYP27b5xBO0m5wbqcAci871GXvNQg+7txwHa8xCeNO2xtcrzKJrO8Im2/PGw7Urw234O8/pYBu5jsebzkndg8eo2GvIONB7yQm6k6jggvPI6J4rxMKqq88W5YPNYVIjxdeQ4749zdPL7wXrytg5y8MjqNvOwx6rztDgW8NobBvDFrSbuwR6e80D7MPHo7Q7weG6a8ruCWPAAGjjszgTE7c7ZwPA2awTxah5O72/Rlu80kYDxmPEA8EBY+vENkaLtxL9K8kHIwvDCjlDwTwSo8E62yPDmXg7zLjGc7N3ycPD9dsrtKVu264JLDOgSaN7z7/K28df6FPHPKPT1kL+28eiMoPQFqx7yJtpU4IOJyOpHIybz14uW65zfVvLjr6jzSp708gyo9PCA5kLvOJbA8DhMVOwInDz3s3XI8hx2BPP7zwTwdf2M7gXbgPJskiLywjU08sZvpO7ho2zxPwaI7vowDveCTIr3WFr27i5lgvFwCJr1kTS47Rv6iOvhhd7yXDNS8E3urvAEs8Tv7bSi9jRH8vAMvjzxeBJ65WE1iPJ3d/Lw3YSA8AiD0vNQLWDynVny8X7QevflMizxvIWe814VTO5EmoDwVpSc6QQPLvF2ahjxPN2c9PNEtvdhTZbzV5iY8OOYiO3gazbxe8Ys8Q92YvE4HWLxJqai8axruu3JEvzrPkaa7PNBLOz2jhDul/Oi8yI29OpGoyjw08AS91qE8vFrMVDxGEtg2a+GSO96C5zkdoiI73h+WPL5XSzyo7Ei8puIdvPlGk7xRExi8cPRuPDlWp7wyCYo83jYXPehQkbswXYk83JJYPOaZAz0bQSQ8hiuevMOjAzyLgK48kjXRu4UEObkHsJ07s//hPIBUoDwXpW07Zd7WPEN2s7zuSQq9bXq2PA1SxzqP0Ai7uDfGPJMYvzrFyTU8wBuWu4ojqDxuSpY8It2Wu8kSTDzpc2C8tjEFO9qyxzo6QKm7bc2tO+Kc6rwH3Hk8JohBvPfr4TyU6/85dwGXO9GL+TwP+rG7u4lUvKEimTwnlfw8icpTu4aqaTtBrd68jHTHuy7KNTwTBQo8HaxAPM0fDT1egaQ85ihZvBvQ6zzGL/c5ahUePd0/JLzVVhQ8h4EHPfZsBL19Pxa7QASKu+4O/DscT4e5FUMvPMZzm7xjNiM8QRtDvEab4Lz+eqW7ICRevDFu8bsiMge7CTUiPZxmhzzFUCK81+smvTze6rz8AsC777GsPBaHAj1pKec6idFNPIYWyLwqm6849//uOmzQCbwbIc86o+6PPBCHYLzA8Bq8SBwvPMKFQrxEd/y81YLqPLLIK7y6ZQW84g6DvNtFjbp+vHm89SyDPeZQGjzlfF48W5oaPdHtJ7wK5rw7N4rhvI2bwzt0bzI80a0zvLr7zjt3JJs85JBgO80tnzznBBM9THvXum7baT0Iqf27qhuSvBwDAbzrb1K8lFePvHJiNrylk628KagEvYSuC732ZX88gTL2vK6lW71y2j+8frsIvEKYdTxBZ5k8Oh8nvAJYgLxVChI9PJ8RPFjTeDxOavY8kMJNvQnPjTxIXLg7+3+NvKjMDDs4lcu8+FInvP2ZAL2pnsW4cu6eO+lC/Dtryj69+JBPuxtg0LwfXX+6mtu1u6BCa7vzviG85jeeu/YwEDz/mei8R3zhu3FTmLyfgrK8HPxLvMesCr1rri89cOSIO92vijxPEnC8RLOQu9Lz6Dy2sLE5DwGUu/xkmDpZYNa8/TOiPHNqtzxxolC8e8q1ukFdgrzyVM079z/YvD350jwLvNG8pFcFvbj81budOy29tRMiPTIyHDxpmSG7Ol1lPJA7r7vhmMo87sGKPJ2CMLxnxWy88xitvF5I8jw5x4G8ME2MvOpUazyj2+I7nQM/PLQWkLySJAO8fVu2PNp9BzwRbiw8H3BfuZ4tHDye8zg8KHbvPGsnYLyWLAs8C+UhPB83dLr1BNg7hbmXPD7+/LseTN27VAjUPIC3j7wED1Y7Pm5xvCQzwbuto7S8ehN9PFtOOT0tk1k6M0eEPK1FajxUcMC8RmPhPP8prjwVaLE8xqC9uwsbxjviZwY9nfODPN7n5DshNjA8dnGYPNtOIrx3CIm8p711vPlNCr3o6ko7P8aZvKcpxTxZTJg8wzg0PHoBhDwxQ2q81oVzPHCC2ToXrI47HX1sPHBzBD0RagQ7zUsJPf9JfTyY+aC7QQr8PNqkCjwGl/S8vp74OiQktzuj5wm7y5RVvA48u7sB4dQ8qQgkPD5mlztVi3e7gMaPuwRw1Lzc+JY8OY0AvW+9LD38Od+8leSKu07r4LydFVe7NHFzPBcbnTv2lxG7yeKYPLHCm7pNUD289ULquSR4Obw4CRM7dvVjOn4cqjsduLW8X0IVvOMFZr2wgyK7VQYcvc4cMb28BxA82guIu8URJD3JgLY8nYnnvMA77bzbCXe7nj7LvAJy7bosW9Q7lMCqPKZEH7xSJhO9T/bauxUmJ7200HY8ksPAOm+TLzzYw7o8Oyu6uxS7Aj1K1w29k8GZO/I06bthyIo8OKQWOvmOab3MZAA9IjsRPKbdzzxnIUM8RYZmvCV9QDypZbs7tU0APRo2CjwhrXw8wcC1vLsWTrxiqYi7pTtCu/v/LD32OuE42Xr3PBeQRru6KaC655UEPa/cwbyafgY99vsBPI/+ObytxJG880yNvGJ1vjzzX2k8IO2Lu/rXt7x1Sa+89O83vEfn/juyHVG88VetOyK3CL05vGm80jL7vIYp07xqxDy8MoyuvGC6HTwn9g68AX4QvN3ZNbtMmCg8nsrQO3UtArxkk4o85AfUPLqrDT02p6K8WSWvvHZDaTzoTma9T6LwvLdAhzsnXTe8dOWBPBxzHDtyAnC6koabO22gAD0K2nG862movPWHHTyQg9k8ToMTPLDTRrxdKfs8SHGmO/TfAb2I1He9+cLqO9lBO7xXqSQ6s/PNPPXUKr1Uj0I8lCK+POOQpzw+gTc6mcO+vPMy3Dw1pg48cUEZO+MPjzx1mLe7jv0xvHvqqjyP6JW8kpmsO8hvyztqrTC8i0ViPLZB0rzJsgA9+zbLPD/9QDzd2lw8omEOvQD5vLyljnc7c/LWvOrv9zvXQbI6G89dPI9CZrx8B/s7V5O0OXmn47s93qi88A20vEp3+bYieoY8EzaXvOF9gjvFgxW9wxoXvZfAuLqjRpo8Vl0PPIrmSTwc/gi8Az4LvdtP6Dw5rre7Vm0zvJ3hojrJPdk8s09bPKW96Lw0ytq8LUS8vIZsCLzAPTa9RAuCPEc/PTtZafe7e9CSPFzTFj3SnrI7MEyvvLtLFj0cobm7EOkgveqdgTxm7A+9szvZOnijqLtOZIi8hHYTu38yKDvZK7a8WdvgOjYxGL1Gp6W8XD7PPCFkmbtfbBK9Y1A6PE/WlDtDX4k62FQEOzPy1DzaxbY8x6T6PH9h9DmwXT47zvQoPMVkajx9I1q8tayqvDTNCLzJkgG8HI4Au5muOTvK4tS7UIXJuy7eEL0hcQs7+TRyPO4ruzz/QFA8AMuZvIWEV7x/lpC7E2p/PVckvDwacUM55u0hvDAPUbvaneg5esALvc2J1jyz2yw7D5lSvAfGlzwhvoI8q9+rO9OPB7y5Wga9oNfCOogojDxz48s6K50HvHBy0Loe5qO800iSu6VA9Lun5xQ9eow2vS1G7bzAIpQ8KRUzvaOXgbmTELw8EHWDPBzHHDwylU08YK1avCLWBzuO7qS8j4KKu1lRfLwKEvE7apFnPLIQTLxlzFS8/OyEu4sYqjyJhnw6bei5POWrz7zLK/k8WcgVu+Pg2Ds6IOi8At2hPHtZursKqwU8Z0laOpuNSrla1xA9CFj5umJWVLortZE8Ty1Xu5MWgbyX1Ia8bpvjO8AIf7wTFQQ8Z8OcOwl7rLuAIiA713FKvO2U5ru2ev88pipTvK+9zTx9KMC8S5f5O+e1ITvyjfu8Z5/hu8Apxzy/BAW8+F8rPVBlwLq1Ndi68QR1uz9AN720nOy81vp0u9dAcjxn1Iy8F1XsPBUQMjwBkBc9qsABPbyckzwg5jc7hnX2vNbqMTu9PSe8sIUFvK7kD7tmUI88BsKLPJ+YXD2oXvW7rlYlvA2HaLyj1Ca8E9NBPFctSjxLafm49Iw8PPCgBDyTAW08MtebOxAjfTxN/2w8tdFVPMF8Tjzh26a8FIZfvAiAWjxpCrY7JQrjPO1WLLvaEw09wCcgupdFxLz0KG48TU36O/TPSzw1nR26PSaIurTrCD1g6O687L+buSIJuDumzRW9J+D5vAptMr2bXLk8dLkrPDhh4LwJ5gW7DtMrvJvFHzuVbvG8r8i8us+d7Trbxce7eON0vSYCF73mb0+75lV1Om8taDxk07G8gSW3vLio+bxStKm7EmyCOw==
+ index: 0
+ object: embedding
+ model: qwen3-embedding:4b
+ object: list
+ usage:
+ prompt_tokens: 4
+ total_tokens: 4
+ status:
+ code: 200
+ message: OK
+- request:
+ headers:
+ accept:
+ - application/json
+ accept-encoding:
+ - gzip, deflate, zstd
+ connection:
+ - keep-alive
+ content-length:
+ - '83'
+ content-type:
+ - application/json
+ host:
+ - localhost:11434
+ method: POST
+ parsed_body:
+ encoding_format: base64
+ input:
+ - Dog document.
+ model: qwen3-embedding:4b
+ uri: http://localhost:11434/v1/embeddings
+ response:
+ headers:
+ content-type:
+ - application/json
+ transfer-encoding:
+ - chunked
+ parsed_body:
+ data:
+ - embedding: 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
+ index: 0
+ object: embedding
+ model: qwen3-embedding:4b
+ object: list
+ usage:
+ prompt_tokens: 4
+ total_tokens: 4
+ status:
+ code: 200
+ message: OK
+- request:
+ headers:
+ accept:
+ - application/json
+ accept-encoding:
+ - gzip, deflate, zstd
+ connection:
+ - keep-alive
+ content-length:
+ - '84'
+ content-type:
+ - application/json
+ host:
+ - localhost:11434
+ method: POST
+ parsed_body:
+ encoding_format: base64
+ input:
+ - Bird document.
+ model: qwen3-embedding:4b
+ uri: http://localhost:11434/v1/embeddings
+ response:
+ headers:
+ content-type:
+ - application/json
+ transfer-encoding:
+ - chunked
+ parsed_body:
+ data:
+ - embedding: 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
+ index: 0
+ object: embedding
+ model: qwen3-embedding:4b
+ object: list
+ usage:
+ prompt_tokens: 4
+ total_tokens: 4
+ status:
+ code: 200
+ message: OK
+- request:
+ headers:
+ accept:
+ - application/json
+ accept-encoding:
+ - gzip, deflate, zstd
+ connection:
+ - keep-alive
+ content-length:
+ - '7680'
+ content-type:
+ - application/json
+ host:
+ - localhost:11434
+ method: POST
+ parsed_body:
+ messages:
+ - content: |-
+ You are a Recursive Language Model (RLM) agent that solves complex research questions by writing and executing Python code.
+
+ IMPORTANT: You MUST use the `execute_code` tool to run Python code. The functions described below are ONLY available inside the execute_code tool - you cannot access them any other way. Always execute code to answer questions; do not just describe what code would do.
+
+ CRITICAL: Inside execute_code, these functions are ALREADY available in the namespace. Do NOT import them - just use them directly:
+ - search("query") ✓ CORRECT
+ - from haiku.rag import search ✗ WRONG - will fail
+
+ You have access to a sandboxed Python environment with these haiku.rag functions (use them directly, no imports needed):
+
+ ## Available Functions
+
+ ### search(query, limit=10) -> list[dict]
+ Search the knowledge base using hybrid search (vector + full-text).
+ Returns list of dicts with keys: chunk_id, content, document_id, document_title, document_uri, score, page_numbers, headings
+
+ ### list_documents(limit=10, offset=0) -> list[dict]
+ List available documents in the knowledge base.
+ Returns list of dicts with keys: id, title, uri, created_at
+
+ ### get_document(id_or_title) -> str | None
+ Get the full text content of a document by ID, title, or URI.
+ Returns the document content as a string, or None if not found.
+
+ ### get_docling_document(id_or_title) -> DoclingDocument | None
+ Get the structured DoclingDocument object for advanced analysis.
+ Returns a DoclingDocument object, or None if not found.
+ See "DoclingDocument API" section below for how to use it.
+
+ ### ask(question) -> str
+ Ask a question using the QA agent with RAG. Returns the answer as a string.
+ Use this for semantic analysis that benefits from LLM reasoning.
+
+ ## Standard Library Modules
+ You can import: json, re, collections, math, statistics, itertools, functools, datetime, typing
+
+ ## Strategy Guide
+
+ 1. **Explore First**: Start by listing documents or searching to understand what's available. Document names may differ from filenames (e.g., "tbmed593.pdf" might be stored as "TB MED 593" or similar).
+ 2. **If get_document returns None**: Use `list_documents()` to see actual document titles, or `search()` to find relevant content.
+ 3. **Iterative Refinement**: Run code, examine results, adjust your approach based on what you find.
+ 4. **Use print() Liberally**: The REPL captures stdout - print intermediate results to see what you're working with.
+ 5. **Aggregate with Code**: For counting, averaging, or comparing across documents, write loops and use collections.
+ 6. **Use ask() for Semantic Analysis**: When you need to understand meaning or interpret content, use the ask() function.
+ 7. **Cite Your Sources**: Track which documents/chunks informed your answer for citation.
+
+ ## DoclingDocument API
+
+ When you call `get_docling_document(id_or_title)`, you get a DoclingDocument object for structured document analysis.
+
+ ### Properties
+ - `doc.texts` - List of all text items (paragraphs, headings, etc.)
+ - `doc.tables` - List of all tables
+ - `doc.pictures` - List of all pictures/figures
+ - `doc.name` - Document name
+
+ ### Methods
+ - `doc.iterate_items(with_groups=False)` - Iterate all items with hierarchy level
+ Returns tuples of (item, level) where level is nesting depth
+ - `doc.export_to_markdown()` - Export entire document as markdown string
+
+ ### Text Item Properties
+ - `item.text` - The text content
+ - `item.label` - Type: TITLE, PARAGRAPH, SECTION_HEADER, LIST_ITEM, etc.
+ - `item.prov` - Provenance (page numbers, bounding boxes)
+
+ ### Table Access
+ - `table.data.num_rows`, `table.data.num_cols` - Dimensions
+ - `table.data.table_cells` - List of TableCell objects
+ - `cell.text`, `cell.start_row_offset_idx`, `cell.start_col_offset_idx`
+
+ ### Example Usage
+ ```python
+ doc = get_docling_document("My Document")
+
+ # Get all headings
+ headings = [t.text for t in doc.texts if "HEADER" in str(t.label)]
+
+ # Iterate with structure
+ for item, level in doc.iterate_items():
+ print(" " * level + item.text[:50])
+
+ # Extract table data
+ for table in doc.tables:
+ for cell in table.data.table_cells:
+ print(f"Row {cell.start_row_offset_idx}, Col {cell.start_col_offset_idx}: {cell.text}")
+ ```
+
+ ## Example Patterns
+
+ ### Counting documents matching a condition
+ ```python
+ docs = list_documents(limit=100)
+ count = 0
+ for doc in docs:
+ content = get_document(doc['id'])
+ if content and 'keyword' in content.lower():
+ count += 1
+ print(f"Found in: {doc['title']}")
+ print(f"Total: {count}")
+ ```
+
+ ### Aggregating data across documents
+ ```python
+ import re
+ numbers = []
+ results = search("financial data", limit=20)
+ for r in results:
+ matches = re.findall(r'\$([\d,]+)', r['content'])
+ for m in matches:
+ numbers.append(int(m.replace(',', '')))
+ print(f"Average: ${sum(numbers)/len(numbers):,.2f}")
+ ```
+
+ ### Using ask() for semantic analysis
+ ```python
+ # First search to find relevant content
+ results = search("machine learning approaches")
+ # Then use ask() to synthesize an answer
+ summary = ask("What are the main machine learning approaches discussed?")
+ print(summary)
+ ```
+
+ ## Workflow
+
+ 1. **ALWAYS start by using execute_code** to explore the knowledge base
+ 2. Run multiple code blocks as needed to gather information
+ 3. After collecting data, provide your final answer
+
+ ## Output Format
+
+ After executing code and gathering information, provide:
+ 1. A clear answer to the user's question
+ 2. Key findings from your analysis
+ 3. References to specific documents/chunks that informed your answer
+
+ CRITICAL: You MUST call execute_code at least once before providing your answer. Never give up without trying to execute code first.
+ role: system
+ - content: How many documents are available?
+ role: user
+ model: gpt-oss
+ reasoning_effort: low
+ stream: false
+ tool_choice: auto
+ tools:
+ - function:
+ description: |-
+ Execute Python code in the sandboxed environment.
+
+ The code has access to haiku.rag functions (search, list_documents,
+ get_document, get_docling_document, ask) and safe standard library
+ modules (json, re, collections, math, statistics, itertools,
+ functools, datetime, typing).
+
+ Use print() to output results. Variables persist between executions.
+
+ Structured result with success status, stdout, and stderr.
+
+ name: execute_code
+ parameters:
+ additionalProperties: false
+ properties:
+ code:
+ description: Python code to execute.
+ type: string
+ required:
+ - code
+ type: object
+ strict: true
+ type: function
+ - function:
+ description: Result from RLM agent execution.
+ name: final_result
+ parameters:
+ $defs:
+ CodeExecution:
+ additionalProperties: false
+ description: Result of executing a code block in the RLM sandbox.
+ properties:
+ code:
+ description: The Python code that was executed
+ type: string
+ stderr:
+ description: Standard error captured during execution
+ type: string
+ stdout:
+ description: Standard output captured during execution
+ type: string
+ success:
+ description: Whether execution completed without error
+ type: boolean
+ required:
+ - code
+ - stdout
+ - stderr
+ - success
+ type: object
+ additionalProperties: false
+ properties:
+ answer:
+ description: The answer to the user's question
+ type: string
+ code_executions:
+ description: History of code executions during the RLM session
+ items:
+ $ref: '#/$defs/CodeExecution'
+ type: array
+ required:
+ - answer
+ type: object
+ type: function
+ uri: http://localhost:11434/v1/chat/completions
+ response:
+ headers:
+ content-length:
+ - '534'
+ content-type:
+ - application/json
+ parsed_body:
+ choices:
+ - finish_reason: tool_calls
+ index: 0
+ message:
+ content: ''
+ reasoning: We need to list documents.
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"docs = list_documents(limit=1000)\nprint(len(docs))\nprint(docs[:5])"}'
+ name: execute_code
+ id: call_9z1yyz67
+ index: 0
+ type: function
+ created: 1769703392
+ id: chatcmpl-454
+ model: gpt-oss
+ object: chat.completion
+ system_fingerprint: fp_ollama
+ usage:
+ completion_tokens: 52
+ prompt_tokens: 1597
+ total_tokens: 1649
+ status:
+ code: 200
+ message: OK
+- request:
+ headers:
+ accept:
+ - application/json
+ accept-encoding:
+ - gzip, deflate, zstd
+ connection:
+ - keep-alive
+ content-length:
+ - '8273'
+ content-type:
+ - application/json
+ host:
+ - localhost:11434
+ method: POST
+ parsed_body:
+ messages:
+ - content: |-
+ You are a Recursive Language Model (RLM) agent that solves complex research questions by writing and executing Python code.
+
+ IMPORTANT: You MUST use the `execute_code` tool to run Python code. The functions described below are ONLY available inside the execute_code tool - you cannot access them any other way. Always execute code to answer questions; do not just describe what code would do.
+
+ CRITICAL: Inside execute_code, these functions are ALREADY available in the namespace. Do NOT import them - just use them directly:
+ - search("query") ✓ CORRECT
+ - from haiku.rag import search ✗ WRONG - will fail
+
+ You have access to a sandboxed Python environment with these haiku.rag functions (use them directly, no imports needed):
+
+ ## Available Functions
+
+ ### search(query, limit=10) -> list[dict]
+ Search the knowledge base using hybrid search (vector + full-text).
+ Returns list of dicts with keys: chunk_id, content, document_id, document_title, document_uri, score, page_numbers, headings
+
+ ### list_documents(limit=10, offset=0) -> list[dict]
+ List available documents in the knowledge base.
+ Returns list of dicts with keys: id, title, uri, created_at
+
+ ### get_document(id_or_title) -> str | None
+ Get the full text content of a document by ID, title, or URI.
+ Returns the document content as a string, or None if not found.
+
+ ### get_docling_document(id_or_title) -> DoclingDocument | None
+ Get the structured DoclingDocument object for advanced analysis.
+ Returns a DoclingDocument object, or None if not found.
+ See "DoclingDocument API" section below for how to use it.
+
+ ### ask(question) -> str
+ Ask a question using the QA agent with RAG. Returns the answer as a string.
+ Use this for semantic analysis that benefits from LLM reasoning.
+
+ ## Standard Library Modules
+ You can import: json, re, collections, math, statistics, itertools, functools, datetime, typing
+
+ ## Strategy Guide
+
+ 1. **Explore First**: Start by listing documents or searching to understand what's available. Document names may differ from filenames (e.g., "tbmed593.pdf" might be stored as "TB MED 593" or similar).
+ 2. **If get_document returns None**: Use `list_documents()` to see actual document titles, or `search()` to find relevant content.
+ 3. **Iterative Refinement**: Run code, examine results, adjust your approach based on what you find.
+ 4. **Use print() Liberally**: The REPL captures stdout - print intermediate results to see what you're working with.
+ 5. **Aggregate with Code**: For counting, averaging, or comparing across documents, write loops and use collections.
+ 6. **Use ask() for Semantic Analysis**: When you need to understand meaning or interpret content, use the ask() function.
+ 7. **Cite Your Sources**: Track which documents/chunks informed your answer for citation.
+
+ ## DoclingDocument API
+
+ When you call `get_docling_document(id_or_title)`, you get a DoclingDocument object for structured document analysis.
+
+ ### Properties
+ - `doc.texts` - List of all text items (paragraphs, headings, etc.)
+ - `doc.tables` - List of all tables
+ - `doc.pictures` - List of all pictures/figures
+ - `doc.name` - Document name
+
+ ### Methods
+ - `doc.iterate_items(with_groups=False)` - Iterate all items with hierarchy level
+ Returns tuples of (item, level) where level is nesting depth
+ - `doc.export_to_markdown()` - Export entire document as markdown string
+
+ ### Text Item Properties
+ - `item.text` - The text content
+ - `item.label` - Type: TITLE, PARAGRAPH, SECTION_HEADER, LIST_ITEM, etc.
+ - `item.prov` - Provenance (page numbers, bounding boxes)
+
+ ### Table Access
+ - `table.data.num_rows`, `table.data.num_cols` - Dimensions
+ - `table.data.table_cells` - List of TableCell objects
+ - `cell.text`, `cell.start_row_offset_idx`, `cell.start_col_offset_idx`
+
+ ### Example Usage
+ ```python
+ doc = get_docling_document("My Document")
+
+ # Get all headings
+ headings = [t.text for t in doc.texts if "HEADER" in str(t.label)]
+
+ # Iterate with structure
+ for item, level in doc.iterate_items():
+ print(" " * level + item.text[:50])
+
+ # Extract table data
+ for table in doc.tables:
+ for cell in table.data.table_cells:
+ print(f"Row {cell.start_row_offset_idx}, Col {cell.start_col_offset_idx}: {cell.text}")
+ ```
+
+ ## Example Patterns
+
+ ### Counting documents matching a condition
+ ```python
+ docs = list_documents(limit=100)
+ count = 0
+ for doc in docs:
+ content = get_document(doc['id'])
+ if content and 'keyword' in content.lower():
+ count += 1
+ print(f"Found in: {doc['title']}")
+ print(f"Total: {count}")
+ ```
+
+ ### Aggregating data across documents
+ ```python
+ import re
+ numbers = []
+ results = search("financial data", limit=20)
+ for r in results:
+ matches = re.findall(r'\$([\d,]+)', r['content'])
+ for m in matches:
+ numbers.append(int(m.replace(',', '')))
+ print(f"Average: ${sum(numbers)/len(numbers):,.2f}")
+ ```
+
+ ### Using ask() for semantic analysis
+ ```python
+ # First search to find relevant content
+ results = search("machine learning approaches")
+ # Then use ask() to synthesize an answer
+ summary = ask("What are the main machine learning approaches discussed?")
+ print(summary)
+ ```
+
+ ## Workflow
+
+ 1. **ALWAYS start by using execute_code** to explore the knowledge base
+ 2. Run multiple code blocks as needed to gather information
+ 3. After collecting data, provide your final answer
+
+ ## Output Format
+
+ After executing code and gathering information, provide:
+ 1. A clear answer to the user's question
+ 2. Key findings from your analysis
+ 3. References to specific documents/chunks that informed your answer
+
+ CRITICAL: You MUST call execute_code at least once before providing your answer. Never give up without trying to execute code first.
+ role: system
+ - content: How many documents are available?
+ role: user
+ - content: |-
+
+ We need to list documents.
+
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"docs = list_documents(limit=1000)\nprint(len(docs))\nprint(docs[:5])"}'
+ name: execute_code
+ id: call_9z1yyz67
+ type: function
+ - content: '{"code":"docs = list_documents(limit=1000)\nprint(len(docs))\nprint(docs[:5])","stdout":"1\n[{''id'': ''6f417f83-6875-47c4-bce0-7a6e47454101'',
+ ''title'': ''Cats'', ''uri'': None, ''created_at'': ''2026-01-29 18:16:29.632357''}]\n","stderr":"","success":true}'
+ role: tool
+ tool_call_id: call_9z1yyz67
+ model: gpt-oss
+ reasoning_effort: low
+ stream: false
+ tool_choice: auto
+ tools:
+ - function:
+ description: |-
+ Execute Python code in the sandboxed environment.
+
+ The code has access to haiku.rag functions (search, list_documents,
+ get_document, get_docling_document, ask) and safe standard library
+ modules (json, re, collections, math, statistics, itertools,
+ functools, datetime, typing).
+
+ Use print() to output results. Variables persist between executions.
+
+ Structured result with success status, stdout, and stderr.
+
+ name: execute_code
+ parameters:
+ additionalProperties: false
+ properties:
+ code:
+ description: Python code to execute.
+ type: string
+ required:
+ - code
+ type: object
+ strict: true
+ type: function
+ - function:
+ description: Result from RLM agent execution.
+ name: final_result
+ parameters:
+ $defs:
+ CodeExecution:
+ additionalProperties: false
+ description: Result of executing a code block in the RLM sandbox.
+ properties:
+ code:
+ description: The Python code that was executed
+ type: string
+ stderr:
+ description: Standard error captured during execution
+ type: string
+ stdout:
+ description: Standard output captured during execution
+ type: string
+ success:
+ description: Whether execution completed without error
+ type: boolean
+ required:
+ - code
+ - stdout
+ - stderr
+ - success
+ type: object
+ additionalProperties: false
+ properties:
+ answer:
+ description: The answer to the user's question
+ type: string
+ code_executions:
+ description: History of code executions during the RLM session
+ items:
+ $ref: '#/$defs/CodeExecution'
+ type: array
+ required:
+ - answer
+ type: object
+ type: function
+ uri: http://localhost:11434/v1/chat/completions
+ response:
+ headers:
+ content-length:
+ - '680'
+ content-type:
+ - application/json
+ parsed_body:
+ choices:
+ - finish_reason: stop
+ index: 0
+ message:
+ content: |-
+ **Answer**
+
+ There is **1** document available in the knowledge base.
+
+ **Key findings**
+
+ - The call to `list_documents(limit=1000)` returned a single entry:
+ - ID: `6f417f83-6875-47c4-bce0-7a6e47454101`
+ - Title: **Cats**
+ - URI: `None`
+ - Created at: `2026-01-29 18:16:29.632357`
+
+ **Reference**
+
+ - The document metadata shown in the output of the `list_documents` call above.
+ role: assistant
+ created: 1769703395
+ id: chatcmpl-395
+ model: gpt-oss
+ object: chat.completion
+ system_fingerprint: fp_ollama
+ usage:
+ completion_tokens: 125
+ prompt_tokens: 1767
+ total_tokens: 1892
+ status:
+ code: 200
+ message: OK
+- request:
+ headers:
+ accept:
+ - application/json
+ accept-encoding:
+ - gzip, deflate, zstd
+ connection:
+ - keep-alive
+ content-length:
+ - '9357'
+ content-type:
+ - application/json
+ host:
+ - localhost:11434
+ method: POST
+ parsed_body:
+ messages:
+ - content: |-
+ You are a Recursive Language Model (RLM) agent that solves complex research questions by writing and executing Python code.
+
+ IMPORTANT: You MUST use the `execute_code` tool to run Python code. The functions described below are ONLY available inside the execute_code tool - you cannot access them any other way. Always execute code to answer questions; do not just describe what code would do.
+
+ CRITICAL: Inside execute_code, these functions are ALREADY available in the namespace. Do NOT import them - just use them directly:
+ - search("query") ✓ CORRECT
+ - from haiku.rag import search ✗ WRONG - will fail
+
+ You have access to a sandboxed Python environment with these haiku.rag functions (use them directly, no imports needed):
+
+ ## Available Functions
+
+ ### search(query, limit=10) -> list[dict]
+ Search the knowledge base using hybrid search (vector + full-text).
+ Returns list of dicts with keys: chunk_id, content, document_id, document_title, document_uri, score, page_numbers, headings
+
+ ### list_documents(limit=10, offset=0) -> list[dict]
+ List available documents in the knowledge base.
+ Returns list of dicts with keys: id, title, uri, created_at
+
+ ### get_document(id_or_title) -> str | None
+ Get the full text content of a document by ID, title, or URI.
+ Returns the document content as a string, or None if not found.
+
+ ### get_docling_document(id_or_title) -> DoclingDocument | None
+ Get the structured DoclingDocument object for advanced analysis.
+ Returns a DoclingDocument object, or None if not found.
+ See "DoclingDocument API" section below for how to use it.
+
+ ### ask(question) -> str
+ Ask a question using the QA agent with RAG. Returns the answer as a string.
+ Use this for semantic analysis that benefits from LLM reasoning.
+
+ ## Standard Library Modules
+ You can import: json, re, collections, math, statistics, itertools, functools, datetime, typing
+
+ ## Strategy Guide
+
+ 1. **Explore First**: Start by listing documents or searching to understand what's available. Document names may differ from filenames (e.g., "tbmed593.pdf" might be stored as "TB MED 593" or similar).
+ 2. **If get_document returns None**: Use `list_documents()` to see actual document titles, or `search()` to find relevant content.
+ 3. **Iterative Refinement**: Run code, examine results, adjust your approach based on what you find.
+ 4. **Use print() Liberally**: The REPL captures stdout - print intermediate results to see what you're working with.
+ 5. **Aggregate with Code**: For counting, averaging, or comparing across documents, write loops and use collections.
+ 6. **Use ask() for Semantic Analysis**: When you need to understand meaning or interpret content, use the ask() function.
+ 7. **Cite Your Sources**: Track which documents/chunks informed your answer for citation.
+
+ ## DoclingDocument API
+
+ When you call `get_docling_document(id_or_title)`, you get a DoclingDocument object for structured document analysis.
+
+ ### Properties
+ - `doc.texts` - List of all text items (paragraphs, headings, etc.)
+ - `doc.tables` - List of all tables
+ - `doc.pictures` - List of all pictures/figures
+ - `doc.name` - Document name
+
+ ### Methods
+ - `doc.iterate_items(with_groups=False)` - Iterate all items with hierarchy level
+ Returns tuples of (item, level) where level is nesting depth
+ - `doc.export_to_markdown()` - Export entire document as markdown string
+
+ ### Text Item Properties
+ - `item.text` - The text content
+ - `item.label` - Type: TITLE, PARAGRAPH, SECTION_HEADER, LIST_ITEM, etc.
+ - `item.prov` - Provenance (page numbers, bounding boxes)
+
+ ### Table Access
+ - `table.data.num_rows`, `table.data.num_cols` - Dimensions
+ - `table.data.table_cells` - List of TableCell objects
+ - `cell.text`, `cell.start_row_offset_idx`, `cell.start_col_offset_idx`
+
+ ### Example Usage
+ ```python
+ doc = get_docling_document("My Document")
+
+ # Get all headings
+ headings = [t.text for t in doc.texts if "HEADER" in str(t.label)]
+
+ # Iterate with structure
+ for item, level in doc.iterate_items():
+ print(" " * level + item.text[:50])
+
+ # Extract table data
+ for table in doc.tables:
+ for cell in table.data.table_cells:
+ print(f"Row {cell.start_row_offset_idx}, Col {cell.start_col_offset_idx}: {cell.text}")
+ ```
+
+ ## Example Patterns
+
+ ### Counting documents matching a condition
+ ```python
+ docs = list_documents(limit=100)
+ count = 0
+ for doc in docs:
+ content = get_document(doc['id'])
+ if content and 'keyword' in content.lower():
+ count += 1
+ print(f"Found in: {doc['title']}")
+ print(f"Total: {count}")
+ ```
+
+ ### Aggregating data across documents
+ ```python
+ import re
+ numbers = []
+ results = search("financial data", limit=20)
+ for r in results:
+ matches = re.findall(r'\$([\d,]+)', r['content'])
+ for m in matches:
+ numbers.append(int(m.replace(',', '')))
+ print(f"Average: ${sum(numbers)/len(numbers):,.2f}")
+ ```
+
+ ### Using ask() for semantic analysis
+ ```python
+ # First search to find relevant content
+ results = search("machine learning approaches")
+ # Then use ask() to synthesize an answer
+ summary = ask("What are the main machine learning approaches discussed?")
+ print(summary)
+ ```
+
+ ## Workflow
+
+ 1. **ALWAYS start by using execute_code** to explore the knowledge base
+ 2. Run multiple code blocks as needed to gather information
+ 3. After collecting data, provide your final answer
+
+ ## Output Format
+
+ After executing code and gathering information, provide:
+ 1. A clear answer to the user's question
+ 2. Key findings from your analysis
+ 3. References to specific documents/chunks that informed your answer
+
+ CRITICAL: You MUST call execute_code at least once before providing your answer. Never give up without trying to execute code first.
+ role: system
+ - content: How many documents are available?
+ role: user
+ - content: |-
+
+ We need to list documents.
+
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"docs = list_documents(limit=1000)\nprint(len(docs))\nprint(docs[:5])"}'
+ name: execute_code
+ id: call_9z1yyz67
+ type: function
+ - content: '{"code":"docs = list_documents(limit=1000)\nprint(len(docs))\nprint(docs[:5])","stdout":"1\n[{''id'': ''6f417f83-6875-47c4-bce0-7a6e47454101'',
+ ''title'': ''Cats'', ''uri'': None, ''created_at'': ''2026-01-29 18:16:29.632357''}]\n","stderr":"","success":true}'
+ role: tool
+ tool_call_id: call_9z1yyz67
+ - content: |-
+ **Answer**
+
+ There is **1** document available in the knowledge base.
+
+ **Key findings**
+
+ - The call to `list_documents(limit=1000)` returned a single entry:
+ - ID: `6f417f83-6875-47c4-bce0-7a6e47454101`
+ - Title: **Cats**
+ - URI: `None`
+ - Created at: `2026-01-29 18:16:29.632357`
+
+ **Reference**
+
+ - The document metadata shown in the output of the `list_documents` call above.
+ role: assistant
+ - content: |-
+ 1 validation error:
+ ```json
+ [
+ {
+ "type": "json_invalid",
+ "loc": [],
+ "msg": "Invalid JSON: expected value at line 1 column 1",
+ "input": "**Answer**\n\nThere is **1** document available in the knowledge base.\n\n**Key findings**\n\n- The call to `list_documents(limit=1000)` returned a single entry:\n - ID: `6f417f83-6875-47c4-bce0-7a6e47454101`\n - Title: **Cats**\n - URI: `None`\n - Created at: `2026-01-29 18:16:29.632357`\n\n**Reference**\n\n- The document metadata shown in the output of the `list_documents` call above."
+ }
+ ]
+ ```
+
+ Fix the errors and try again.
+ role: user
+ model: gpt-oss
+ reasoning_effort: low
+ stream: false
+ tool_choice: auto
+ tools:
+ - function:
+ description: |-
+ Execute Python code in the sandboxed environment.
+
+ The code has access to haiku.rag functions (search, list_documents,
+ get_document, get_docling_document, ask) and safe standard library
+ modules (json, re, collections, math, statistics, itertools,
+ functools, datetime, typing).
+
+ Use print() to output results. Variables persist between executions.
+
+ Structured result with success status, stdout, and stderr.
+
+ name: execute_code
+ parameters:
+ additionalProperties: false
+ properties:
+ code:
+ description: Python code to execute.
+ type: string
+ required:
+ - code
+ type: object
+ strict: true
+ type: function
+ - function:
+ description: Result from RLM agent execution.
+ name: final_result
+ parameters:
+ $defs:
+ CodeExecution:
+ additionalProperties: false
+ description: Result of executing a code block in the RLM sandbox.
+ properties:
+ code:
+ description: The Python code that was executed
+ type: string
+ stderr:
+ description: Standard error captured during execution
+ type: string
+ stdout:
+ description: Standard output captured during execution
+ type: string
+ success:
+ description: Whether execution completed without error
+ type: boolean
+ required:
+ - code
+ - stdout
+ - stderr
+ - success
+ type: object
+ additionalProperties: false
+ properties:
+ answer:
+ description: The answer to the user's question
+ type: string
+ code_executions:
+ description: History of code executions during the RLM session
+ items:
+ $ref: '#/$defs/CodeExecution'
+ type: array
+ required:
+ - answer
+ type: object
+ type: function
+ uri: http://localhost:11434/v1/chat/completions
+ response:
+ headers:
+ content-length:
+ - '692'
+ content-type:
+ - application/json
+ parsed_body:
+ error:
+ code: null
+ message: 'error parsing tool call: raw=''{"answer":"There is 1 document available in the knowledge base.\n\nThe document
+ has ID 6f417f83-6875-47c4-bce0-7a6e47454101, title \"Cats\", and was created on 2026-01-29 18:16:29.632357.","code_executions":[{"tool":"functions.execute_code","input":{"code":"docs
+ = list_documents(limit=1000)\nprint(len(docs))\nprint(docs[:5])"},"output":{"stdout":"1\n[{''id'': ''6f417f83-6875-47c4-bce0-7a6e47454101'',
+ ''title'': ''Cats'', ''uri'': None, ''created_at'': ''2026-01-29 18:16:29.632357''}]\n","stderr":"","success":true}}}'',
+ err=invalid character ''}'' after array element'
+ param: null
+ type: api_error
+ status:
+ code: 500
+ message: Internal Server Error
+- request:
+ headers:
+ accept:
+ - application/json
+ accept-encoding:
+ - gzip, deflate, zstd
+ connection:
+ - keep-alive
+ content-length:
+ - '9357'
+ content-type:
+ - application/json
+ host:
+ - localhost:11434
+ method: POST
+ parsed_body:
+ messages:
+ - content: |-
+ You are a Recursive Language Model (RLM) agent that solves complex research questions by writing and executing Python code.
+
+ IMPORTANT: You MUST use the `execute_code` tool to run Python code. The functions described below are ONLY available inside the execute_code tool - you cannot access them any other way. Always execute code to answer questions; do not just describe what code would do.
+
+ CRITICAL: Inside execute_code, these functions are ALREADY available in the namespace. Do NOT import them - just use them directly:
+ - search("query") ✓ CORRECT
+ - from haiku.rag import search ✗ WRONG - will fail
+
+ You have access to a sandboxed Python environment with these haiku.rag functions (use them directly, no imports needed):
+
+ ## Available Functions
+
+ ### search(query, limit=10) -> list[dict]
+ Search the knowledge base using hybrid search (vector + full-text).
+ Returns list of dicts with keys: chunk_id, content, document_id, document_title, document_uri, score, page_numbers, headings
+
+ ### list_documents(limit=10, offset=0) -> list[dict]
+ List available documents in the knowledge base.
+ Returns list of dicts with keys: id, title, uri, created_at
+
+ ### get_document(id_or_title) -> str | None
+ Get the full text content of a document by ID, title, or URI.
+ Returns the document content as a string, or None if not found.
+
+ ### get_docling_document(id_or_title) -> DoclingDocument | None
+ Get the structured DoclingDocument object for advanced analysis.
+ Returns a DoclingDocument object, or None if not found.
+ See "DoclingDocument API" section below for how to use it.
+
+ ### ask(question) -> str
+ Ask a question using the QA agent with RAG. Returns the answer as a string.
+ Use this for semantic analysis that benefits from LLM reasoning.
+
+ ## Standard Library Modules
+ You can import: json, re, collections, math, statistics, itertools, functools, datetime, typing
+
+ ## Strategy Guide
+
+ 1. **Explore First**: Start by listing documents or searching to understand what's available. Document names may differ from filenames (e.g., "tbmed593.pdf" might be stored as "TB MED 593" or similar).
+ 2. **If get_document returns None**: Use `list_documents()` to see actual document titles, or `search()` to find relevant content.
+ 3. **Iterative Refinement**: Run code, examine results, adjust your approach based on what you find.
+ 4. **Use print() Liberally**: The REPL captures stdout - print intermediate results to see what you're working with.
+ 5. **Aggregate with Code**: For counting, averaging, or comparing across documents, write loops and use collections.
+ 6. **Use ask() for Semantic Analysis**: When you need to understand meaning or interpret content, use the ask() function.
+ 7. **Cite Your Sources**: Track which documents/chunks informed your answer for citation.
+
+ ## DoclingDocument API
+
+ When you call `get_docling_document(id_or_title)`, you get a DoclingDocument object for structured document analysis.
+
+ ### Properties
+ - `doc.texts` - List of all text items (paragraphs, headings, etc.)
+ - `doc.tables` - List of all tables
+ - `doc.pictures` - List of all pictures/figures
+ - `doc.name` - Document name
+
+ ### Methods
+ - `doc.iterate_items(with_groups=False)` - Iterate all items with hierarchy level
+ Returns tuples of (item, level) where level is nesting depth
+ - `doc.export_to_markdown()` - Export entire document as markdown string
+
+ ### Text Item Properties
+ - `item.text` - The text content
+ - `item.label` - Type: TITLE, PARAGRAPH, SECTION_HEADER, LIST_ITEM, etc.
+ - `item.prov` - Provenance (page numbers, bounding boxes)
+
+ ### Table Access
+ - `table.data.num_rows`, `table.data.num_cols` - Dimensions
+ - `table.data.table_cells` - List of TableCell objects
+ - `cell.text`, `cell.start_row_offset_idx`, `cell.start_col_offset_idx`
+
+ ### Example Usage
+ ```python
+ doc = get_docling_document("My Document")
+
+ # Get all headings
+ headings = [t.text for t in doc.texts if "HEADER" in str(t.label)]
+
+ # Iterate with structure
+ for item, level in doc.iterate_items():
+ print(" " * level + item.text[:50])
+
+ # Extract table data
+ for table in doc.tables:
+ for cell in table.data.table_cells:
+ print(f"Row {cell.start_row_offset_idx}, Col {cell.start_col_offset_idx}: {cell.text}")
+ ```
+
+ ## Example Patterns
+
+ ### Counting documents matching a condition
+ ```python
+ docs = list_documents(limit=100)
+ count = 0
+ for doc in docs:
+ content = get_document(doc['id'])
+ if content and 'keyword' in content.lower():
+ count += 1
+ print(f"Found in: {doc['title']}")
+ print(f"Total: {count}")
+ ```
+
+ ### Aggregating data across documents
+ ```python
+ import re
+ numbers = []
+ results = search("financial data", limit=20)
+ for r in results:
+ matches = re.findall(r'\$([\d,]+)', r['content'])
+ for m in matches:
+ numbers.append(int(m.replace(',', '')))
+ print(f"Average: ${sum(numbers)/len(numbers):,.2f}")
+ ```
+
+ ### Using ask() for semantic analysis
+ ```python
+ # First search to find relevant content
+ results = search("machine learning approaches")
+ # Then use ask() to synthesize an answer
+ summary = ask("What are the main machine learning approaches discussed?")
+ print(summary)
+ ```
+
+ ## Workflow
+
+ 1. **ALWAYS start by using execute_code** to explore the knowledge base
+ 2. Run multiple code blocks as needed to gather information
+ 3. After collecting data, provide your final answer
+
+ ## Output Format
+
+ After executing code and gathering information, provide:
+ 1. A clear answer to the user's question
+ 2. Key findings from your analysis
+ 3. References to specific documents/chunks that informed your answer
+
+ CRITICAL: You MUST call execute_code at least once before providing your answer. Never give up without trying to execute code first.
+ role: system
+ - content: How many documents are available?
+ role: user
+ - content: |-
+
+ We need to list documents.
+
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"docs = list_documents(limit=1000)\nprint(len(docs))\nprint(docs[:5])"}'
+ name: execute_code
+ id: call_9z1yyz67
+ type: function
+ - content: '{"code":"docs = list_documents(limit=1000)\nprint(len(docs))\nprint(docs[:5])","stdout":"1\n[{''id'': ''6f417f83-6875-47c4-bce0-7a6e47454101'',
+ ''title'': ''Cats'', ''uri'': None, ''created_at'': ''2026-01-29 18:16:29.632357''}]\n","stderr":"","success":true}'
+ role: tool
+ tool_call_id: call_9z1yyz67
+ - content: |-
+ **Answer**
+
+ There is **1** document available in the knowledge base.
+
+ **Key findings**
+
+ - The call to `list_documents(limit=1000)` returned a single entry:
+ - ID: `6f417f83-6875-47c4-bce0-7a6e47454101`
+ - Title: **Cats**
+ - URI: `None`
+ - Created at: `2026-01-29 18:16:29.632357`
+
+ **Reference**
+
+ - The document metadata shown in the output of the `list_documents` call above.
+ role: assistant
+ - content: |-
+ 1 validation error:
+ ```json
+ [
+ {
+ "type": "json_invalid",
+ "loc": [],
+ "msg": "Invalid JSON: expected value at line 1 column 1",
+ "input": "**Answer**\n\nThere is **1** document available in the knowledge base.\n\n**Key findings**\n\n- The call to `list_documents(limit=1000)` returned a single entry:\n - ID: `6f417f83-6875-47c4-bce0-7a6e47454101`\n - Title: **Cats**\n - URI: `None`\n - Created at: `2026-01-29 18:16:29.632357`\n\n**Reference**\n\n- The document metadata shown in the output of the `list_documents` call above."
+ }
+ ]
+ ```
+
+ Fix the errors and try again.
+ role: user
+ model: gpt-oss
+ reasoning_effort: low
+ stream: false
+ tool_choice: auto
+ tools:
+ - function:
+ description: |-
+ Execute Python code in the sandboxed environment.
+
+ The code has access to haiku.rag functions (search, list_documents,
+ get_document, get_docling_document, ask) and safe standard library
+ modules (json, re, collections, math, statistics, itertools,
+ functools, datetime, typing).
+
+ Use print() to output results. Variables persist between executions.
+
+ Structured result with success status, stdout, and stderr.
+
+ name: execute_code
+ parameters:
+ additionalProperties: false
+ properties:
+ code:
+ description: Python code to execute.
+ type: string
+ required:
+ - code
+ type: object
+ strict: true
+ type: function
+ - function:
+ description: Result from RLM agent execution.
+ name: final_result
+ parameters:
+ $defs:
+ CodeExecution:
+ additionalProperties: false
+ description: Result of executing a code block in the RLM sandbox.
+ properties:
+ code:
+ description: The Python code that was executed
+ type: string
+ stderr:
+ description: Standard error captured during execution
+ type: string
+ stdout:
+ description: Standard output captured during execution
+ type: string
+ success:
+ description: Whether execution completed without error
+ type: boolean
+ required:
+ - code
+ - stdout
+ - stderr
+ - success
+ type: object
+ additionalProperties: false
+ properties:
+ answer:
+ description: The answer to the user's question
+ type: string
+ code_executions:
+ description: History of code executions during the RLM session
+ items:
+ $ref: '#/$defs/CodeExecution'
+ type: array
+ required:
+ - answer
+ type: object
+ type: function
+ uri: http://localhost:11434/v1/chat/completions
+ response:
+ headers:
+ content-length:
+ - '730'
+ content-type:
+ - application/json
+ parsed_body:
+ choices:
+ - finish_reason: stop
+ index: 0
+ message:
+ content: |-
+ **Answer**
+
+ There is **1** document available in the knowledge base.
+
+ **Key findings**
+
+ - The call to `list_documents(limit=1000)` returned a single entry:
+ - ID: `6f417f83-6875-47c4-bce0-7a6e47454101`
+ - Title: **Cats**
+ - URI: `None`
+ - Created at: `2026-01-29 18:16:29.632357`
+
+ **Reference**
+
+ - The document metadata shown in the output of the `list_documents` call above.
+ reasoning: We must output plain text, no JSON.
+ role: assistant
+ created: 1769703402
+ id: chatcmpl-345
+ model: gpt-oss
+ object: chat.completion
+ system_fingerprint: fp_ollama
+ usage:
+ completion_tokens: 140
+ prompt_tokens: 2094
+ total_tokens: 2234
+ status:
+ code: 200
+ message: OK
+- request:
+ headers:
+ accept:
+ - application/json
+ accept-encoding:
+ - gzip, deflate, zstd
+ connection:
+ - keep-alive
+ content-length:
+ - '10499'
+ content-type:
+ - application/json
+ host:
+ - localhost:11434
+ method: POST
+ parsed_body:
+ messages:
+ - content: |-
+ You are a Recursive Language Model (RLM) agent that solves complex research questions by writing and executing Python code.
+
+ IMPORTANT: You MUST use the `execute_code` tool to run Python code. The functions described below are ONLY available inside the execute_code tool - you cannot access them any other way. Always execute code to answer questions; do not just describe what code would do.
+
+ CRITICAL: Inside execute_code, these functions are ALREADY available in the namespace. Do NOT import them - just use them directly:
+ - search("query") ✓ CORRECT
+ - from haiku.rag import search ✗ WRONG - will fail
+
+ You have access to a sandboxed Python environment with these haiku.rag functions (use them directly, no imports needed):
+
+ ## Available Functions
+
+ ### search(query, limit=10) -> list[dict]
+ Search the knowledge base using hybrid search (vector + full-text).
+ Returns list of dicts with keys: chunk_id, content, document_id, document_title, document_uri, score, page_numbers, headings
+
+ ### list_documents(limit=10, offset=0) -> list[dict]
+ List available documents in the knowledge base.
+ Returns list of dicts with keys: id, title, uri, created_at
+
+ ### get_document(id_or_title) -> str | None
+ Get the full text content of a document by ID, title, or URI.
+ Returns the document content as a string, or None if not found.
+
+ ### get_docling_document(id_or_title) -> DoclingDocument | None
+ Get the structured DoclingDocument object for advanced analysis.
+ Returns a DoclingDocument object, or None if not found.
+ See "DoclingDocument API" section below for how to use it.
+
+ ### ask(question) -> str
+ Ask a question using the QA agent with RAG. Returns the answer as a string.
+ Use this for semantic analysis that benefits from LLM reasoning.
+
+ ## Standard Library Modules
+ You can import: json, re, collections, math, statistics, itertools, functools, datetime, typing
+
+ ## Strategy Guide
+
+ 1. **Explore First**: Start by listing documents or searching to understand what's available. Document names may differ from filenames (e.g., "tbmed593.pdf" might be stored as "TB MED 593" or similar).
+ 2. **If get_document returns None**: Use `list_documents()` to see actual document titles, or `search()` to find relevant content.
+ 3. **Iterative Refinement**: Run code, examine results, adjust your approach based on what you find.
+ 4. **Use print() Liberally**: The REPL captures stdout - print intermediate results to see what you're working with.
+ 5. **Aggregate with Code**: For counting, averaging, or comparing across documents, write loops and use collections.
+ 6. **Use ask() for Semantic Analysis**: When you need to understand meaning or interpret content, use the ask() function.
+ 7. **Cite Your Sources**: Track which documents/chunks informed your answer for citation.
+
+ ## DoclingDocument API
+
+ When you call `get_docling_document(id_or_title)`, you get a DoclingDocument object for structured document analysis.
+
+ ### Properties
+ - `doc.texts` - List of all text items (paragraphs, headings, etc.)
+ - `doc.tables` - List of all tables
+ - `doc.pictures` - List of all pictures/figures
+ - `doc.name` - Document name
+
+ ### Methods
+ - `doc.iterate_items(with_groups=False)` - Iterate all items with hierarchy level
+ Returns tuples of (item, level) where level is nesting depth
+ - `doc.export_to_markdown()` - Export entire document as markdown string
+
+ ### Text Item Properties
+ - `item.text` - The text content
+ - `item.label` - Type: TITLE, PARAGRAPH, SECTION_HEADER, LIST_ITEM, etc.
+ - `item.prov` - Provenance (page numbers, bounding boxes)
+
+ ### Table Access
+ - `table.data.num_rows`, `table.data.num_cols` - Dimensions
+ - `table.data.table_cells` - List of TableCell objects
+ - `cell.text`, `cell.start_row_offset_idx`, `cell.start_col_offset_idx`
+
+ ### Example Usage
+ ```python
+ doc = get_docling_document("My Document")
+
+ # Get all headings
+ headings = [t.text for t in doc.texts if "HEADER" in str(t.label)]
+
+ # Iterate with structure
+ for item, level in doc.iterate_items():
+ print(" " * level + item.text[:50])
+
+ # Extract table data
+ for table in doc.tables:
+ for cell in table.data.table_cells:
+ print(f"Row {cell.start_row_offset_idx}, Col {cell.start_col_offset_idx}: {cell.text}")
+ ```
+
+ ## Example Patterns
+
+ ### Counting documents matching a condition
+ ```python
+ docs = list_documents(limit=100)
+ count = 0
+ for doc in docs:
+ content = get_document(doc['id'])
+ if content and 'keyword' in content.lower():
+ count += 1
+ print(f"Found in: {doc['title']}")
+ print(f"Total: {count}")
+ ```
+
+ ### Aggregating data across documents
+ ```python
+ import re
+ numbers = []
+ results = search("financial data", limit=20)
+ for r in results:
+ matches = re.findall(r'\$([\d,]+)', r['content'])
+ for m in matches:
+ numbers.append(int(m.replace(',', '')))
+ print(f"Average: ${sum(numbers)/len(numbers):,.2f}")
+ ```
+
+ ### Using ask() for semantic analysis
+ ```python
+ # First search to find relevant content
+ results = search("machine learning approaches")
+ # Then use ask() to synthesize an answer
+ summary = ask("What are the main machine learning approaches discussed?")
+ print(summary)
+ ```
+
+ ## Workflow
+
+ 1. **ALWAYS start by using execute_code** to explore the knowledge base
+ 2. Run multiple code blocks as needed to gather information
+ 3. After collecting data, provide your final answer
+
+ ## Output Format
+
+ After executing code and gathering information, provide:
+ 1. A clear answer to the user's question
+ 2. Key findings from your analysis
+ 3. References to specific documents/chunks that informed your answer
+
+ CRITICAL: You MUST call execute_code at least once before providing your answer. Never give up without trying to execute code first.
+ role: system
+ - content: How many documents are available?
+ role: user
+ - content: |-
+
+ We need to list documents.
+
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"docs = list_documents(limit=1000)\nprint(len(docs))\nprint(docs[:5])"}'
+ name: execute_code
+ id: call_9z1yyz67
+ type: function
+ - content: '{"code":"docs = list_documents(limit=1000)\nprint(len(docs))\nprint(docs[:5])","stdout":"1\n[{''id'': ''6f417f83-6875-47c4-bce0-7a6e47454101'',
+ ''title'': ''Cats'', ''uri'': None, ''created_at'': ''2026-01-29 18:16:29.632357''}]\n","stderr":"","success":true}'
+ role: tool
+ tool_call_id: call_9z1yyz67
+ - content: |-
+ **Answer**
+
+ There is **1** document available in the knowledge base.
+
+ **Key findings**
+
+ - The call to `list_documents(limit=1000)` returned a single entry:
+ - ID: `6f417f83-6875-47c4-bce0-7a6e47454101`
+ - Title: **Cats**
+ - URI: `None`
+ - Created at: `2026-01-29 18:16:29.632357`
+
+ **Reference**
+
+ - The document metadata shown in the output of the `list_documents` call above.
+ role: assistant
+ - content: |-
+ 1 validation error:
+ ```json
+ [
+ {
+ "type": "json_invalid",
+ "loc": [],
+ "msg": "Invalid JSON: expected value at line 1 column 1",
+ "input": "**Answer**\n\nThere is **1** document available in the knowledge base.\n\n**Key findings**\n\n- The call to `list_documents(limit=1000)` returned a single entry:\n - ID: `6f417f83-6875-47c4-bce0-7a6e47454101`\n - Title: **Cats**\n - URI: `None`\n - Created at: `2026-01-29 18:16:29.632357`\n\n**Reference**\n\n- The document metadata shown in the output of the `list_documents` call above."
+ }
+ ]
+ ```
+
+ Fix the errors and try again.
+ role: user
+ - content: |-
+
+ We must output plain text, no JSON.
+
+
+ **Answer**
+
+ There is **1** document available in the knowledge base.
+
+ **Key findings**
+
+ - The call to `list_documents(limit=1000)` returned a single entry:
+ - ID: `6f417f83-6875-47c4-bce0-7a6e47454101`
+ - Title: **Cats**
+ - URI: `None`
+ - Created at: `2026-01-29 18:16:29.632357`
+
+ **Reference**
+
+ - The document metadata shown in the output of the `list_documents` call above.
+ role: assistant
+ - content: |-
+ 1 validation error:
+ ```json
+ [
+ {
+ "type": "json_invalid",
+ "loc": [],
+ "msg": "Invalid JSON: expected value at line 1 column 1",
+ "input": "**Answer**\n\nThere is **1** document available in the knowledge base.\n\n**Key findings**\n\n- The call to `list_documents(limit=1000)` returned a single entry:\n - ID: `6f417f83-6875-47c4-bce0-7a6e47454101`\n - Title: **Cats**\n - URI: `None`\n - Created at: `2026-01-29 18:16:29.632357`\n\n**Reference**\n\n- The document metadata shown in the output of the `list_documents` call above."
+ }
+ ]
+ ```
+
+ Fix the errors and try again.
+ role: user
+ model: gpt-oss
+ reasoning_effort: low
+ stream: false
+ tool_choice: auto
+ tools:
+ - function:
+ description: |-
+ Execute Python code in the sandboxed environment.
+
+ The code has access to haiku.rag functions (search, list_documents,
+ get_document, get_docling_document, ask) and safe standard library
+ modules (json, re, collections, math, statistics, itertools,
+ functools, datetime, typing).
+
+ Use print() to output results. Variables persist between executions.
+
+ Structured result with success status, stdout, and stderr.
+
+ name: execute_code
+ parameters:
+ additionalProperties: false
+ properties:
+ code:
+ description: Python code to execute.
+ type: string
+ required:
+ - code
+ type: object
+ strict: true
+ type: function
+ - function:
+ description: Result from RLM agent execution.
+ name: final_result
+ parameters:
+ $defs:
+ CodeExecution:
+ additionalProperties: false
+ description: Result of executing a code block in the RLM sandbox.
+ properties:
+ code:
+ description: The Python code that was executed
+ type: string
+ stderr:
+ description: Standard error captured during execution
+ type: string
+ stdout:
+ description: Standard output captured during execution
+ type: string
+ success:
+ description: Whether execution completed without error
+ type: boolean
+ required:
+ - code
+ - stdout
+ - stderr
+ - success
+ type: object
+ additionalProperties: false
+ properties:
+ answer:
+ description: The answer to the user's question
+ type: string
+ code_executions:
+ description: History of code executions during the RLM session
+ items:
+ $ref: '#/$defs/CodeExecution'
+ type: array
+ required:
+ - answer
+ type: object
+ type: function
+ uri: http://localhost:11434/v1/chat/completions
+ response:
+ headers:
+ content-length:
+ - '369'
+ content-type:
+ - application/json
+ parsed_body:
+ choices:
+ - finish_reason: stop
+ index: 0
+ message:
+ content: There is 1 document available in the knowledge base.
+ reasoning: Need plain text.
+ role: assistant
+ created: 1769703404
+ id: chatcmpl-571
+ model: gpt-oss
+ object: chat.completion
+ system_fingerprint: fp_ollama
+ usage:
+ completion_tokens: 25
+ prompt_tokens: 2436
+ total_tokens: 2461
+ status:
+ code: 200
+ message: OK
+- request:
+ headers:
+ accept:
+ - application/json
+ accept-encoding:
+ - gzip, deflate, zstd
+ connection:
+ - keep-alive
+ content-length:
+ - '10926'
+ content-type:
+ - application/json
+ host:
+ - localhost:11434
+ method: POST
+ parsed_body:
+ messages:
+ - content: |-
+ You are a Recursive Language Model (RLM) agent that solves complex research questions by writing and executing Python code.
+
+ IMPORTANT: You MUST use the `execute_code` tool to run Python code. The functions described below are ONLY available inside the execute_code tool - you cannot access them any other way. Always execute code to answer questions; do not just describe what code would do.
+
+ CRITICAL: Inside execute_code, these functions are ALREADY available in the namespace. Do NOT import them - just use them directly:
+ - search("query") ✓ CORRECT
+ - from haiku.rag import search ✗ WRONG - will fail
+
+ You have access to a sandboxed Python environment with these haiku.rag functions (use them directly, no imports needed):
+
+ ## Available Functions
+
+ ### search(query, limit=10) -> list[dict]
+ Search the knowledge base using hybrid search (vector + full-text).
+ Returns list of dicts with keys: chunk_id, content, document_id, document_title, document_uri, score, page_numbers, headings
+
+ ### list_documents(limit=10, offset=0) -> list[dict]
+ List available documents in the knowledge base.
+ Returns list of dicts with keys: id, title, uri, created_at
+
+ ### get_document(id_or_title) -> str | None
+ Get the full text content of a document by ID, title, or URI.
+ Returns the document content as a string, or None if not found.
+
+ ### get_docling_document(id_or_title) -> DoclingDocument | None
+ Get the structured DoclingDocument object for advanced analysis.
+ Returns a DoclingDocument object, or None if not found.
+ See "DoclingDocument API" section below for how to use it.
+
+ ### ask(question) -> str
+ Ask a question using the QA agent with RAG. Returns the answer as a string.
+ Use this for semantic analysis that benefits from LLM reasoning.
+
+ ## Standard Library Modules
+ You can import: json, re, collections, math, statistics, itertools, functools, datetime, typing
+
+ ## Strategy Guide
+
+ 1. **Explore First**: Start by listing documents or searching to understand what's available. Document names may differ from filenames (e.g., "tbmed593.pdf" might be stored as "TB MED 593" or similar).
+ 2. **If get_document returns None**: Use `list_documents()` to see actual document titles, or `search()` to find relevant content.
+ 3. **Iterative Refinement**: Run code, examine results, adjust your approach based on what you find.
+ 4. **Use print() Liberally**: The REPL captures stdout - print intermediate results to see what you're working with.
+ 5. **Aggregate with Code**: For counting, averaging, or comparing across documents, write loops and use collections.
+ 6. **Use ask() for Semantic Analysis**: When you need to understand meaning or interpret content, use the ask() function.
+ 7. **Cite Your Sources**: Track which documents/chunks informed your answer for citation.
+
+ ## DoclingDocument API
+
+ When you call `get_docling_document(id_or_title)`, you get a DoclingDocument object for structured document analysis.
+
+ ### Properties
+ - `doc.texts` - List of all text items (paragraphs, headings, etc.)
+ - `doc.tables` - List of all tables
+ - `doc.pictures` - List of all pictures/figures
+ - `doc.name` - Document name
+
+ ### Methods
+ - `doc.iterate_items(with_groups=False)` - Iterate all items with hierarchy level
+ Returns tuples of (item, level) where level is nesting depth
+ - `doc.export_to_markdown()` - Export entire document as markdown string
+
+ ### Text Item Properties
+ - `item.text` - The text content
+ - `item.label` - Type: TITLE, PARAGRAPH, SECTION_HEADER, LIST_ITEM, etc.
+ - `item.prov` - Provenance (page numbers, bounding boxes)
+
+ ### Table Access
+ - `table.data.num_rows`, `table.data.num_cols` - Dimensions
+ - `table.data.table_cells` - List of TableCell objects
+ - `cell.text`, `cell.start_row_offset_idx`, `cell.start_col_offset_idx`
+
+ ### Example Usage
+ ```python
+ doc = get_docling_document("My Document")
+
+ # Get all headings
+ headings = [t.text for t in doc.texts if "HEADER" in str(t.label)]
+
+ # Iterate with structure
+ for item, level in doc.iterate_items():
+ print(" " * level + item.text[:50])
+
+ # Extract table data
+ for table in doc.tables:
+ for cell in table.data.table_cells:
+ print(f"Row {cell.start_row_offset_idx}, Col {cell.start_col_offset_idx}: {cell.text}")
+ ```
+
+ ## Example Patterns
+
+ ### Counting documents matching a condition
+ ```python
+ docs = list_documents(limit=100)
+ count = 0
+ for doc in docs:
+ content = get_document(doc['id'])
+ if content and 'keyword' in content.lower():
+ count += 1
+ print(f"Found in: {doc['title']}")
+ print(f"Total: {count}")
+ ```
+
+ ### Aggregating data across documents
+ ```python
+ import re
+ numbers = []
+ results = search("financial data", limit=20)
+ for r in results:
+ matches = re.findall(r'\$([\d,]+)', r['content'])
+ for m in matches:
+ numbers.append(int(m.replace(',', '')))
+ print(f"Average: ${sum(numbers)/len(numbers):,.2f}")
+ ```
+
+ ### Using ask() for semantic analysis
+ ```python
+ # First search to find relevant content
+ results = search("machine learning approaches")
+ # Then use ask() to synthesize an answer
+ summary = ask("What are the main machine learning approaches discussed?")
+ print(summary)
+ ```
+
+ ## Workflow
+
+ 1. **ALWAYS start by using execute_code** to explore the knowledge base
+ 2. Run multiple code blocks as needed to gather information
+ 3. After collecting data, provide your final answer
+
+ ## Output Format
+
+ After executing code and gathering information, provide:
+ 1. A clear answer to the user's question
+ 2. Key findings from your analysis
+ 3. References to specific documents/chunks that informed your answer
+
+ CRITICAL: You MUST call execute_code at least once before providing your answer. Never give up without trying to execute code first.
+ role: system
+ - content: How many documents are available?
+ role: user
+ - content: |-
+
+ We need to list documents.
+
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"docs = list_documents(limit=1000)\nprint(len(docs))\nprint(docs[:5])"}'
+ name: execute_code
+ id: call_9z1yyz67
+ type: function
+ - content: '{"code":"docs = list_documents(limit=1000)\nprint(len(docs))\nprint(docs[:5])","stdout":"1\n[{''id'': ''6f417f83-6875-47c4-bce0-7a6e47454101'',
+ ''title'': ''Cats'', ''uri'': None, ''created_at'': ''2026-01-29 18:16:29.632357''}]\n","stderr":"","success":true}'
+ role: tool
+ tool_call_id: call_9z1yyz67
+ - content: |-
+ **Answer**
+
+ There is **1** document available in the knowledge base.
+
+ **Key findings**
+
+ - The call to `list_documents(limit=1000)` returned a single entry:
+ - ID: `6f417f83-6875-47c4-bce0-7a6e47454101`
+ - Title: **Cats**
+ - URI: `None`
+ - Created at: `2026-01-29 18:16:29.632357`
+
+ **Reference**
+
+ - The document metadata shown in the output of the `list_documents` call above.
+ role: assistant
+ - content: |-
+ 1 validation error:
+ ```json
+ [
+ {
+ "type": "json_invalid",
+ "loc": [],
+ "msg": "Invalid JSON: expected value at line 1 column 1",
+ "input": "**Answer**\n\nThere is **1** document available in the knowledge base.\n\n**Key findings**\n\n- The call to `list_documents(limit=1000)` returned a single entry:\n - ID: `6f417f83-6875-47c4-bce0-7a6e47454101`\n - Title: **Cats**\n - URI: `None`\n - Created at: `2026-01-29 18:16:29.632357`\n\n**Reference**\n\n- The document metadata shown in the output of the `list_documents` call above."
+ }
+ ]
+ ```
+
+ Fix the errors and try again.
+ role: user
+ - content: |-
+
+ We must output plain text, no JSON.
+
+
+ **Answer**
+
+ There is **1** document available in the knowledge base.
+
+ **Key findings**
+
+ - The call to `list_documents(limit=1000)` returned a single entry:
+ - ID: `6f417f83-6875-47c4-bce0-7a6e47454101`
+ - Title: **Cats**
+ - URI: `None`
+ - Created at: `2026-01-29 18:16:29.632357`
+
+ **Reference**
+
+ - The document metadata shown in the output of the `list_documents` call above.
+ role: assistant
+ - content: |-
+ 1 validation error:
+ ```json
+ [
+ {
+ "type": "json_invalid",
+ "loc": [],
+ "msg": "Invalid JSON: expected value at line 1 column 1",
+ "input": "**Answer**\n\nThere is **1** document available in the knowledge base.\n\n**Key findings**\n\n- The call to `list_documents(limit=1000)` returned a single entry:\n - ID: `6f417f83-6875-47c4-bce0-7a6e47454101`\n - Title: **Cats**\n - URI: `None`\n - Created at: `2026-01-29 18:16:29.632357`\n\n**Reference**\n\n- The document metadata shown in the output of the `list_documents` call above."
+ }
+ ]
+ ```
+
+ Fix the errors and try again.
+ role: user
+ - content: |-
+
+ Need plain text.
+
+
+ There is 1 document available in the knowledge base.
+ role: assistant
+ - content: |-
+ 1 validation error:
+ ```json
+ [
+ {
+ "type": "json_invalid",
+ "loc": [],
+ "msg": "Invalid JSON: expected value at line 1 column 1",
+ "input": "There is 1 document available in the knowledge base."
+ }
+ ]
+ ```
+
+ Fix the errors and try again.
+ role: user
+ model: gpt-oss
+ reasoning_effort: low
+ stream: false
+ tool_choice: auto
+ tools:
+ - function:
+ description: |-
+ Execute Python code in the sandboxed environment.
+
+ The code has access to haiku.rag functions (search, list_documents,
+ get_document, get_docling_document, ask) and safe standard library
+ modules (json, re, collections, math, statistics, itertools,
+ functools, datetime, typing).
+
+ Use print() to output results. Variables persist between executions.
+
+ Structured result with success status, stdout, and stderr.
+
+ name: execute_code
+ parameters:
+ additionalProperties: false
+ properties:
+ code:
+ description: Python code to execute.
+ type: string
+ required:
+ - code
+ type: object
+ strict: true
+ type: function
+ - function:
+ description: Result from RLM agent execution.
+ name: final_result
+ parameters:
+ $defs:
+ CodeExecution:
+ additionalProperties: false
+ description: Result of executing a code block in the RLM sandbox.
+ properties:
+ code:
+ description: The Python code that was executed
+ type: string
+ stderr:
+ description: Standard error captured during execution
+ type: string
+ stdout:
+ description: Standard output captured during execution
+ type: string
+ success:
+ description: Whether execution completed without error
+ type: boolean
+ required:
+ - code
+ - stdout
+ - stderr
+ - success
+ type: object
+ additionalProperties: false
+ properties:
+ answer:
+ description: The answer to the user's question
+ type: string
+ code_executions:
+ description: History of code executions during the RLM session
+ items:
+ $ref: '#/$defs/CodeExecution'
+ type: array
+ required:
+ - answer
+ type: object
+ type: function
+ uri: http://localhost:11434/v1/chat/completions
+ response:
+ headers:
+ content-length:
+ - '590'
+ content-type:
+ - application/json
+ parsed_body:
+ choices:
+ - finish_reason: tool_calls
+ index: 0
+ message:
+ content: ''
+ reasoning: We must output JSON. The response should be JSON object.
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"ans = {''answer'':''There is 1 document available in the knowledge base.''}\nprint(json.dumps(ans))"}'
+ name: execute_code
+ id: call_oz1gq2pl
+ index: 0
+ type: function
+ created: 1769703405
+ id: chatcmpl-692
+ model: gpt-oss
+ object: chat.completion
+ system_fingerprint: fp_ollama
+ usage:
+ completion_tokens: 58
+ prompt_tokens: 2536
+ total_tokens: 2594
+ status:
+ code: 200
+ message: OK
+- request:
+ headers:
+ accept:
+ - application/json
+ accept-encoding:
+ - gzip, deflate, zstd
+ connection:
+ - keep-alive
+ content-length:
+ - '11870'
+ content-type:
+ - application/json
+ host:
+ - localhost:11434
+ method: POST
+ parsed_body:
+ messages:
+ - content: |-
+ You are a Recursive Language Model (RLM) agent that solves complex research questions by writing and executing Python code.
+
+ IMPORTANT: You MUST use the `execute_code` tool to run Python code. The functions described below are ONLY available inside the execute_code tool - you cannot access them any other way. Always execute code to answer questions; do not just describe what code would do.
+
+ CRITICAL: Inside execute_code, these functions are ALREADY available in the namespace. Do NOT import them - just use them directly:
+ - search("query") ✓ CORRECT
+ - from haiku.rag import search ✗ WRONG - will fail
+
+ You have access to a sandboxed Python environment with these haiku.rag functions (use them directly, no imports needed):
+
+ ## Available Functions
+
+ ### search(query, limit=10) -> list[dict]
+ Search the knowledge base using hybrid search (vector + full-text).
+ Returns list of dicts with keys: chunk_id, content, document_id, document_title, document_uri, score, page_numbers, headings
+
+ ### list_documents(limit=10, offset=0) -> list[dict]
+ List available documents in the knowledge base.
+ Returns list of dicts with keys: id, title, uri, created_at
+
+ ### get_document(id_or_title) -> str | None
+ Get the full text content of a document by ID, title, or URI.
+ Returns the document content as a string, or None if not found.
+
+ ### get_docling_document(id_or_title) -> DoclingDocument | None
+ Get the structured DoclingDocument object for advanced analysis.
+ Returns a DoclingDocument object, or None if not found.
+ See "DoclingDocument API" section below for how to use it.
+
+ ### ask(question) -> str
+ Ask a question using the QA agent with RAG. Returns the answer as a string.
+ Use this for semantic analysis that benefits from LLM reasoning.
+
+ ## Standard Library Modules
+ You can import: json, re, collections, math, statistics, itertools, functools, datetime, typing
+
+ ## Strategy Guide
+
+ 1. **Explore First**: Start by listing documents or searching to understand what's available. Document names may differ from filenames (e.g., "tbmed593.pdf" might be stored as "TB MED 593" or similar).
+ 2. **If get_document returns None**: Use `list_documents()` to see actual document titles, or `search()` to find relevant content.
+ 3. **Iterative Refinement**: Run code, examine results, adjust your approach based on what you find.
+ 4. **Use print() Liberally**: The REPL captures stdout - print intermediate results to see what you're working with.
+ 5. **Aggregate with Code**: For counting, averaging, or comparing across documents, write loops and use collections.
+ 6. **Use ask() for Semantic Analysis**: When you need to understand meaning or interpret content, use the ask() function.
+ 7. **Cite Your Sources**: Track which documents/chunks informed your answer for citation.
+
+ ## DoclingDocument API
+
+ When you call `get_docling_document(id_or_title)`, you get a DoclingDocument object for structured document analysis.
+
+ ### Properties
+ - `doc.texts` - List of all text items (paragraphs, headings, etc.)
+ - `doc.tables` - List of all tables
+ - `doc.pictures` - List of all pictures/figures
+ - `doc.name` - Document name
+
+ ### Methods
+ - `doc.iterate_items(with_groups=False)` - Iterate all items with hierarchy level
+ Returns tuples of (item, level) where level is nesting depth
+ - `doc.export_to_markdown()` - Export entire document as markdown string
+
+ ### Text Item Properties
+ - `item.text` - The text content
+ - `item.label` - Type: TITLE, PARAGRAPH, SECTION_HEADER, LIST_ITEM, etc.
+ - `item.prov` - Provenance (page numbers, bounding boxes)
+
+ ### Table Access
+ - `table.data.num_rows`, `table.data.num_cols` - Dimensions
+ - `table.data.table_cells` - List of TableCell objects
+ - `cell.text`, `cell.start_row_offset_idx`, `cell.start_col_offset_idx`
+
+ ### Example Usage
+ ```python
+ doc = get_docling_document("My Document")
+
+ # Get all headings
+ headings = [t.text for t in doc.texts if "HEADER" in str(t.label)]
+
+ # Iterate with structure
+ for item, level in doc.iterate_items():
+ print(" " * level + item.text[:50])
+
+ # Extract table data
+ for table in doc.tables:
+ for cell in table.data.table_cells:
+ print(f"Row {cell.start_row_offset_idx}, Col {cell.start_col_offset_idx}: {cell.text}")
+ ```
+
+ ## Example Patterns
+
+ ### Counting documents matching a condition
+ ```python
+ docs = list_documents(limit=100)
+ count = 0
+ for doc in docs:
+ content = get_document(doc['id'])
+ if content and 'keyword' in content.lower():
+ count += 1
+ print(f"Found in: {doc['title']}")
+ print(f"Total: {count}")
+ ```
+
+ ### Aggregating data across documents
+ ```python
+ import re
+ numbers = []
+ results = search("financial data", limit=20)
+ for r in results:
+ matches = re.findall(r'\$([\d,]+)', r['content'])
+ for m in matches:
+ numbers.append(int(m.replace(',', '')))
+ print(f"Average: ${sum(numbers)/len(numbers):,.2f}")
+ ```
+
+ ### Using ask() for semantic analysis
+ ```python
+ # First search to find relevant content
+ results = search("machine learning approaches")
+ # Then use ask() to synthesize an answer
+ summary = ask("What are the main machine learning approaches discussed?")
+ print(summary)
+ ```
+
+ ## Workflow
+
+ 1. **ALWAYS start by using execute_code** to explore the knowledge base
+ 2. Run multiple code blocks as needed to gather information
+ 3. After collecting data, provide your final answer
+
+ ## Output Format
+
+ After executing code and gathering information, provide:
+ 1. A clear answer to the user's question
+ 2. Key findings from your analysis
+ 3. References to specific documents/chunks that informed your answer
+
+ CRITICAL: You MUST call execute_code at least once before providing your answer. Never give up without trying to execute code first.
+ role: system
+ - content: How many documents are available?
+ role: user
+ - content: |-
+
+ We need to list documents.
+
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"docs = list_documents(limit=1000)\nprint(len(docs))\nprint(docs[:5])"}'
+ name: execute_code
+ id: call_9z1yyz67
+ type: function
+ - content: '{"code":"docs = list_documents(limit=1000)\nprint(len(docs))\nprint(docs[:5])","stdout":"1\n[{''id'': ''6f417f83-6875-47c4-bce0-7a6e47454101'',
+ ''title'': ''Cats'', ''uri'': None, ''created_at'': ''2026-01-29 18:16:29.632357''}]\n","stderr":"","success":true}'
+ role: tool
+ tool_call_id: call_9z1yyz67
+ - content: |-
+ **Answer**
+
+ There is **1** document available in the knowledge base.
+
+ **Key findings**
+
+ - The call to `list_documents(limit=1000)` returned a single entry:
+ - ID: `6f417f83-6875-47c4-bce0-7a6e47454101`
+ - Title: **Cats**
+ - URI: `None`
+ - Created at: `2026-01-29 18:16:29.632357`
+
+ **Reference**
+
+ - The document metadata shown in the output of the `list_documents` call above.
+ role: assistant
+ - content: |-
+ 1 validation error:
+ ```json
+ [
+ {
+ "type": "json_invalid",
+ "loc": [],
+ "msg": "Invalid JSON: expected value at line 1 column 1",
+ "input": "**Answer**\n\nThere is **1** document available in the knowledge base.\n\n**Key findings**\n\n- The call to `list_documents(limit=1000)` returned a single entry:\n - ID: `6f417f83-6875-47c4-bce0-7a6e47454101`\n - Title: **Cats**\n - URI: `None`\n - Created at: `2026-01-29 18:16:29.632357`\n\n**Reference**\n\n- The document metadata shown in the output of the `list_documents` call above."
+ }
+ ]
+ ```
+
+ Fix the errors and try again.
+ role: user
+ - content: |-
+
+ We must output plain text, no JSON.
+
+
+ **Answer**
+
+ There is **1** document available in the knowledge base.
+
+ **Key findings**
+
+ - The call to `list_documents(limit=1000)` returned a single entry:
+ - ID: `6f417f83-6875-47c4-bce0-7a6e47454101`
+ - Title: **Cats**
+ - URI: `None`
+ - Created at: `2026-01-29 18:16:29.632357`
+
+ **Reference**
+
+ - The document metadata shown in the output of the `list_documents` call above.
+ role: assistant
+ - content: |-
+ 1 validation error:
+ ```json
+ [
+ {
+ "type": "json_invalid",
+ "loc": [],
+ "msg": "Invalid JSON: expected value at line 1 column 1",
+ "input": "**Answer**\n\nThere is **1** document available in the knowledge base.\n\n**Key findings**\n\n- The call to `list_documents(limit=1000)` returned a single entry:\n - ID: `6f417f83-6875-47c4-bce0-7a6e47454101`\n - Title: **Cats**\n - URI: `None`\n - Created at: `2026-01-29 18:16:29.632357`\n\n**Reference**\n\n- The document metadata shown in the output of the `list_documents` call above."
+ }
+ ]
+ ```
+
+ Fix the errors and try again.
+ role: user
+ - content: |-
+
+ Need plain text.
+
+
+ There is 1 document available in the knowledge base.
+ role: assistant
+ - content: |-
+ 1 validation error:
+ ```json
+ [
+ {
+ "type": "json_invalid",
+ "loc": [],
+ "msg": "Invalid JSON: expected value at line 1 column 1",
+ "input": "There is 1 document available in the knowledge base."
+ }
+ ]
+ ```
+
+ Fix the errors and try again.
+ role: user
+ - content: |-
+
+ We must output JSON. The response should be JSON object.
+
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"ans = {''answer'':''There is 1 document available in the knowledge base.''}\nprint(json.dumps(ans))"}'
+ name: execute_code
+ id: call_oz1gq2pl
+ type: function
+ - content: '{"code":"ans = {''answer'':''There is 1 document available in the knowledge base.''}\nprint(json.dumps(ans))","stdout":"","stderr":"Traceback
+ (most recent call last):\n File \"/Users/ggozad/dev/open-source/haiku.rag-feat-recursive-llm/haiku_rag_slim/haiku/rag/agents/rlm/sandbox.py\",
+ line 355, in _execute_sync\n exec(code, exec_globals, self.locals)\n ~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File
+ \"\", line 2, in \nNameError: name ''json'' is not defined. Did you forget to import ''json''?\n","success":false}'
+ role: tool
+ tool_call_id: call_oz1gq2pl
+ model: gpt-oss
+ reasoning_effort: low
+ stream: false
+ tool_choice: auto
+ tools:
+ - function:
+ description: |-
+ Execute Python code in the sandboxed environment.
+
+ The code has access to haiku.rag functions (search, list_documents,
+ get_document, get_docling_document, ask) and safe standard library
+ modules (json, re, collections, math, statistics, itertools,
+ functools, datetime, typing).
+
+ Use print() to output results. Variables persist between executions.
+
+ Structured result with success status, stdout, and stderr.
+
+ name: execute_code
+ parameters:
+ additionalProperties: false
+ properties:
+ code:
+ description: Python code to execute.
+ type: string
+ required:
+ - code
+ type: object
+ strict: true
+ type: function
+ - function:
+ description: Result from RLM agent execution.
+ name: final_result
+ parameters:
+ $defs:
+ CodeExecution:
+ additionalProperties: false
+ description: Result of executing a code block in the RLM sandbox.
+ properties:
+ code:
+ description: The Python code that was executed
+ type: string
+ stderr:
+ description: Standard error captured during execution
+ type: string
+ stdout:
+ description: Standard output captured during execution
+ type: string
+ success:
+ description: Whether execution completed without error
+ type: boolean
+ required:
+ - code
+ - stdout
+ - stderr
+ - success
+ type: object
+ additionalProperties: false
+ properties:
+ answer:
+ description: The answer to the user's question
+ type: string
+ code_executions:
+ description: History of code executions during the RLM session
+ items:
+ $ref: '#/$defs/CodeExecution'
+ type: array
+ required:
+ - answer
+ type: object
+ type: function
+ uri: http://localhost:11434/v1/chat/completions
+ response:
+ headers:
+ content-length:
+ - '565'
+ content-type:
+ - application/json
+ parsed_body:
+ choices:
+ - finish_reason: tool_calls
+ index: 0
+ message:
+ content: ''
+ reasoning: Need import json.
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"import json\nans = {''answer'':''There is 1 document available in the knowledge base.''}\nprint(json.dumps(ans))"}'
+ name: execute_code
+ id: call_auhgoe0p
+ index: 0
+ type: function
+ created: 1769703407
+ id: chatcmpl-215
+ model: gpt-oss
+ object: chat.completion
+ system_fingerprint: fp_ollama
+ usage:
+ completion_tokens: 53
+ prompt_tokens: 2772
+ total_tokens: 2825
+ status:
+ code: 200
+ message: OK
+- request:
+ headers:
+ accept:
+ - application/json
+ accept-encoding:
+ - gzip, deflate, zstd
+ connection:
+ - keep-alive
+ content-length:
+ - '12486'
+ content-type:
+ - application/json
+ host:
+ - localhost:11434
+ method: POST
+ parsed_body:
+ messages:
+ - content: |-
+ You are a Recursive Language Model (RLM) agent that solves complex research questions by writing and executing Python code.
+
+ IMPORTANT: You MUST use the `execute_code` tool to run Python code. The functions described below are ONLY available inside the execute_code tool - you cannot access them any other way. Always execute code to answer questions; do not just describe what code would do.
+
+ CRITICAL: Inside execute_code, these functions are ALREADY available in the namespace. Do NOT import them - just use them directly:
+ - search("query") ✓ CORRECT
+ - from haiku.rag import search ✗ WRONG - will fail
+
+ You have access to a sandboxed Python environment with these haiku.rag functions (use them directly, no imports needed):
+
+ ## Available Functions
+
+ ### search(query, limit=10) -> list[dict]
+ Search the knowledge base using hybrid search (vector + full-text).
+ Returns list of dicts with keys: chunk_id, content, document_id, document_title, document_uri, score, page_numbers, headings
+
+ ### list_documents(limit=10, offset=0) -> list[dict]
+ List available documents in the knowledge base.
+ Returns list of dicts with keys: id, title, uri, created_at
+
+ ### get_document(id_or_title) -> str | None
+ Get the full text content of a document by ID, title, or URI.
+ Returns the document content as a string, or None if not found.
+
+ ### get_docling_document(id_or_title) -> DoclingDocument | None
+ Get the structured DoclingDocument object for advanced analysis.
+ Returns a DoclingDocument object, or None if not found.
+ See "DoclingDocument API" section below for how to use it.
+
+ ### ask(question) -> str
+ Ask a question using the QA agent with RAG. Returns the answer as a string.
+ Use this for semantic analysis that benefits from LLM reasoning.
+
+ ## Standard Library Modules
+ You can import: json, re, collections, math, statistics, itertools, functools, datetime, typing
+
+ ## Strategy Guide
+
+ 1. **Explore First**: Start by listing documents or searching to understand what's available. Document names may differ from filenames (e.g., "tbmed593.pdf" might be stored as "TB MED 593" or similar).
+ 2. **If get_document returns None**: Use `list_documents()` to see actual document titles, or `search()` to find relevant content.
+ 3. **Iterative Refinement**: Run code, examine results, adjust your approach based on what you find.
+ 4. **Use print() Liberally**: The REPL captures stdout - print intermediate results to see what you're working with.
+ 5. **Aggregate with Code**: For counting, averaging, or comparing across documents, write loops and use collections.
+ 6. **Use ask() for Semantic Analysis**: When you need to understand meaning or interpret content, use the ask() function.
+ 7. **Cite Your Sources**: Track which documents/chunks informed your answer for citation.
+
+ ## DoclingDocument API
+
+ When you call `get_docling_document(id_or_title)`, you get a DoclingDocument object for structured document analysis.
+
+ ### Properties
+ - `doc.texts` - List of all text items (paragraphs, headings, etc.)
+ - `doc.tables` - List of all tables
+ - `doc.pictures` - List of all pictures/figures
+ - `doc.name` - Document name
+
+ ### Methods
+ - `doc.iterate_items(with_groups=False)` - Iterate all items with hierarchy level
+ Returns tuples of (item, level) where level is nesting depth
+ - `doc.export_to_markdown()` - Export entire document as markdown string
+
+ ### Text Item Properties
+ - `item.text` - The text content
+ - `item.label` - Type: TITLE, PARAGRAPH, SECTION_HEADER, LIST_ITEM, etc.
+ - `item.prov` - Provenance (page numbers, bounding boxes)
+
+ ### Table Access
+ - `table.data.num_rows`, `table.data.num_cols` - Dimensions
+ - `table.data.table_cells` - List of TableCell objects
+ - `cell.text`, `cell.start_row_offset_idx`, `cell.start_col_offset_idx`
+
+ ### Example Usage
+ ```python
+ doc = get_docling_document("My Document")
+
+ # Get all headings
+ headings = [t.text for t in doc.texts if "HEADER" in str(t.label)]
+
+ # Iterate with structure
+ for item, level in doc.iterate_items():
+ print(" " * level + item.text[:50])
+
+ # Extract table data
+ for table in doc.tables:
+ for cell in table.data.table_cells:
+ print(f"Row {cell.start_row_offset_idx}, Col {cell.start_col_offset_idx}: {cell.text}")
+ ```
+
+ ## Example Patterns
+
+ ### Counting documents matching a condition
+ ```python
+ docs = list_documents(limit=100)
+ count = 0
+ for doc in docs:
+ content = get_document(doc['id'])
+ if content and 'keyword' in content.lower():
+ count += 1
+ print(f"Found in: {doc['title']}")
+ print(f"Total: {count}")
+ ```
+
+ ### Aggregating data across documents
+ ```python
+ import re
+ numbers = []
+ results = search("financial data", limit=20)
+ for r in results:
+ matches = re.findall(r'\$([\d,]+)', r['content'])
+ for m in matches:
+ numbers.append(int(m.replace(',', '')))
+ print(f"Average: ${sum(numbers)/len(numbers):,.2f}")
+ ```
+
+ ### Using ask() for semantic analysis
+ ```python
+ # First search to find relevant content
+ results = search("machine learning approaches")
+ # Then use ask() to synthesize an answer
+ summary = ask("What are the main machine learning approaches discussed?")
+ print(summary)
+ ```
+
+ ## Workflow
+
+ 1. **ALWAYS start by using execute_code** to explore the knowledge base
+ 2. Run multiple code blocks as needed to gather information
+ 3. After collecting data, provide your final answer
+
+ ## Output Format
+
+ After executing code and gathering information, provide:
+ 1. A clear answer to the user's question
+ 2. Key findings from your analysis
+ 3. References to specific documents/chunks that informed your answer
+
+ CRITICAL: You MUST call execute_code at least once before providing your answer. Never give up without trying to execute code first.
+ role: system
+ - content: How many documents are available?
+ role: user
+ - content: |-
+
+ We need to list documents.
+
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"docs = list_documents(limit=1000)\nprint(len(docs))\nprint(docs[:5])"}'
+ name: execute_code
+ id: call_9z1yyz67
+ type: function
+ - content: '{"code":"docs = list_documents(limit=1000)\nprint(len(docs))\nprint(docs[:5])","stdout":"1\n[{''id'': ''6f417f83-6875-47c4-bce0-7a6e47454101'',
+ ''title'': ''Cats'', ''uri'': None, ''created_at'': ''2026-01-29 18:16:29.632357''}]\n","stderr":"","success":true}'
+ role: tool
+ tool_call_id: call_9z1yyz67
+ - content: |-
+ **Answer**
+
+ There is **1** document available in the knowledge base.
+
+ **Key findings**
+
+ - The call to `list_documents(limit=1000)` returned a single entry:
+ - ID: `6f417f83-6875-47c4-bce0-7a6e47454101`
+ - Title: **Cats**
+ - URI: `None`
+ - Created at: `2026-01-29 18:16:29.632357`
+
+ **Reference**
+
+ - The document metadata shown in the output of the `list_documents` call above.
+ role: assistant
+ - content: |-
+ 1 validation error:
+ ```json
+ [
+ {
+ "type": "json_invalid",
+ "loc": [],
+ "msg": "Invalid JSON: expected value at line 1 column 1",
+ "input": "**Answer**\n\nThere is **1** document available in the knowledge base.\n\n**Key findings**\n\n- The call to `list_documents(limit=1000)` returned a single entry:\n - ID: `6f417f83-6875-47c4-bce0-7a6e47454101`\n - Title: **Cats**\n - URI: `None`\n - Created at: `2026-01-29 18:16:29.632357`\n\n**Reference**\n\n- The document metadata shown in the output of the `list_documents` call above."
+ }
+ ]
+ ```
+
+ Fix the errors and try again.
+ role: user
+ - content: |-
+
+ We must output plain text, no JSON.
+
+
+ **Answer**
+
+ There is **1** document available in the knowledge base.
+
+ **Key findings**
+
+ - The call to `list_documents(limit=1000)` returned a single entry:
+ - ID: `6f417f83-6875-47c4-bce0-7a6e47454101`
+ - Title: **Cats**
+ - URI: `None`
+ - Created at: `2026-01-29 18:16:29.632357`
+
+ **Reference**
+
+ - The document metadata shown in the output of the `list_documents` call above.
+ role: assistant
+ - content: |-
+ 1 validation error:
+ ```json
+ [
+ {
+ "type": "json_invalid",
+ "loc": [],
+ "msg": "Invalid JSON: expected value at line 1 column 1",
+ "input": "**Answer**\n\nThere is **1** document available in the knowledge base.\n\n**Key findings**\n\n- The call to `list_documents(limit=1000)` returned a single entry:\n - ID: `6f417f83-6875-47c4-bce0-7a6e47454101`\n - Title: **Cats**\n - URI: `None`\n - Created at: `2026-01-29 18:16:29.632357`\n\n**Reference**\n\n- The document metadata shown in the output of the `list_documents` call above."
+ }
+ ]
+ ```
+
+ Fix the errors and try again.
+ role: user
+ - content: |-
+
+ Need plain text.
+
+
+ There is 1 document available in the knowledge base.
+ role: assistant
+ - content: |-
+ 1 validation error:
+ ```json
+ [
+ {
+ "type": "json_invalid",
+ "loc": [],
+ "msg": "Invalid JSON: expected value at line 1 column 1",
+ "input": "There is 1 document available in the knowledge base."
+ }
+ ]
+ ```
+
+ Fix the errors and try again.
+ role: user
+ - content: |-
+
+ We must output JSON. The response should be JSON object.
+
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"ans = {''answer'':''There is 1 document available in the knowledge base.''}\nprint(json.dumps(ans))"}'
+ name: execute_code
+ id: call_oz1gq2pl
+ type: function
+ - content: '{"code":"ans = {''answer'':''There is 1 document available in the knowledge base.''}\nprint(json.dumps(ans))","stdout":"","stderr":"Traceback
+ (most recent call last):\n File \"/Users/ggozad/dev/open-source/haiku.rag-feat-recursive-llm/haiku_rag_slim/haiku/rag/agents/rlm/sandbox.py\",
+ line 355, in _execute_sync\n exec(code, exec_globals, self.locals)\n ~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File
+ \"\", line 2, in \nNameError: name ''json'' is not defined. Did you forget to import ''json''?\n","success":false}'
+ role: tool
+ tool_call_id: call_oz1gq2pl
+ - content: |-
+
+ Need import json.
+
+ role: assistant
+ tool_calls:
+ - function:
+ arguments: '{"code":"import json\nans = {''answer'':''There is 1 document available in the knowledge base.''}\nprint(json.dumps(ans))"}'
+ name: execute_code
+ id: call_auhgoe0p
+ type: function
+ - content: '{"code":"import json\nans = {''answer'':''There is 1 document available in the knowledge base.''}\nprint(json.dumps(ans))","stdout":"{\"answer\":
+ \"There is 1 document available in the knowledge base.\"}\n","stderr":"","success":true}'
+ role: tool
+ tool_call_id: call_auhgoe0p
+ model: gpt-oss
+ reasoning_effort: low
+ stream: false
+ tool_choice: auto
+ tools:
+ - function:
+ description: |-
+ Execute Python code in the sandboxed environment.
+
+ The code has access to haiku.rag functions (search, list_documents,
+ get_document, get_docling_document, ask) and safe standard library
+ modules (json, re, collections, math, statistics, itertools,
+ functools, datetime, typing).
+
+ Use print() to output results. Variables persist between executions.
+
+ Structured result with success status, stdout, and stderr.
+
+ name: execute_code
+ parameters:
+ additionalProperties: false
+ properties:
+ code:
+ description: Python code to execute.
+ type: string
+ required:
+ - code
+ type: object
+ strict: true
+ type: function
+ - function:
+ description: Result from RLM agent execution.
+ name: final_result
+ parameters:
+ $defs:
+ CodeExecution:
+ additionalProperties: false
+ description: Result of executing a code block in the RLM sandbox.
+ properties:
+ code:
+ description: The Python code that was executed
+ type: string
+ stderr:
+ description: Standard error captured during execution
+ type: string
+ stdout:
+ description: Standard output captured during execution
+ type: string
+ success:
+ description: Whether execution completed without error
+ type: boolean
+ required:
+ - code
+ - stdout
+ - stderr
+ - success
+ type: object
+ additionalProperties: false
+ properties:
+ answer:
+ description: The answer to the user's question
+ type: string
+ code_executions:
+ description: History of code executions during the RLM session
+ items:
+ $ref: '#/$defs/CodeExecution'
+ type: array
+ required:
+ - answer
+ type: object
+ type: function
+ uri: http://localhost:11434/v1/chat/completions
+ response:
+ headers:
+ content-length:
+ - '355'
+ content-type:
+ - application/json
+ parsed_body:
+ choices:
+ - finish_reason: stop
+ index: 0
+ message:
+ content: '{"answer":"There is 1 document available in the knowledge base."}'
+ role: assistant
+ created: 1769703408
+ id: chatcmpl-950
+ model: gpt-oss
+ object: chat.completion
+ system_fingerprint: fp_ollama
+ usage:
+ completion_tokens: 19
+ prompt_tokens: 2898
+ total_tokens: 2917
+ status:
+ code: 200
+ message: OK
+version: 1