Merge pull request #308 from ggozad/feat/rlm-monty-update

RLM monty update.
This commit is contained in:
Yiorgis Gozadinos 2026-03-13 11:23:39 +02:00 committed by GitHub
commit b09b45e8fa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 2805 additions and 4690 deletions

View file

@ -1,6 +1,10 @@
# Changelog # Changelog
## [Unreleased] ## [Unreleased]
### Changed
- **RLM sandbox**: Bumped pydantic-monty to 0.0.8. Removed `regex_*` external functions — the sandbox now has native `re` and `math` modules via `import`. Also adds `filter()` and `getattr()` builtins.
## [0.33.3] - 2026-03-12 ## [0.33.3] - 2026-03-12
### Added ### Added

View file

@ -64,15 +64,14 @@ The agent's code runs in a sandboxed Python interpreter ([pydantic-monty](https:
| `get_chunk(chunk_id)` | Get a chunk with metadata (headings, page numbers, labels) for citations | | `get_chunk(chunk_id)` | Get a chunk with metadata (headings, page numbers, labels) for citations |
| `get_docling_document(document_id)` | Get the full DoclingDocument structure as a dict (texts, tables, pictures, pages) | | `get_docling_document(document_id)` | Get the full DoclingDocument structure as a dict (texts, tables, pictures, pages) |
| `llm(prompt)` | Call an LLM for classification, summarization, or extraction | | `llm(prompt)` | Call an LLM for classification, summarization, or extraction |
| `regex_findall(pattern, text)`, `regex_sub(pattern, repl, text)`, `regex_search(pattern, text)`, `regex_split(pattern, text)` | Regular expression matching via Python's `re` module |
When documents are pre-loaded via the `documents` parameter, they are injected as a `documents` variable accessible in the sandbox code. When documents are pre-loaded via the `documents` parameter, they are injected as a `documents` variable accessible in the sandbox code.
### Python Features ### Python Features
The interpreter supports a subset of Python: variables, arithmetic, strings, f-strings, lists, dicts, tuples, sets, loops, conditionals, comprehensions, functions, async/await, try/except, and the `json` module. The interpreter supports a subset of Python: variables, arithmetic, strings, f-strings, lists, dicts, tuples, sets, loops, conditionals, comprehensions, functions, async/await, `filter()`, `getattr()`, try/except, and the `json`, `re`, `math` modules.
Not supported: imports (other than `json`), class definitions, generators/yield, match statements, decorators, `with` statements. For pattern matching, the agent can use the `regex_*` functions, string methods, or the `llm()` function. Not supported: most imports (only `json`, `re`, `math` are available), class definitions, generators/yield, match statements, decorators, `with` statements. For pattern matching, the agent can use `import re`, string methods, or the `llm()` function.
### Security ### Security
@ -80,7 +79,7 @@ Code executes in an isolated interpreter with:
- **No filesystem access**: Code cannot read or write files - **No filesystem access**: Code cannot read or write files
- **No network access**: Code cannot make HTTP requests or open sockets - **No network access**: Code cannot make HTTP requests or open sockets
- **No imports**: Only the `json` module is available - **No imports**: Only `json`, `re`, and `math` modules are available
- **Execution timeout**: Configurable limit (default 60s) - **Execution timeout**: Configurable limit (default 60s)
- **Output truncation**: Large outputs are truncated to prevent memory issues - **Output truncation**: Large outputs are truncated to prevent memory issues

View file

@ -34,18 +34,6 @@ Use `list_documents()` or search results to get document IDs first.
- `pictures`: list of figures/images with metadata - `pictures`: list of figures/images with metadata
- `pages`: page dimensions and metadata - `pages`: page dimensions and metadata
### await regex_findall(pattern, text) -> list[str]
Find all non-overlapping matches of a regular expression pattern in text.
### await regex_sub(pattern, repl, text) -> str
Replace all occurrences of a regular expression pattern with a replacement string.
### await regex_search(pattern, text) -> dict | None
Search for the first match of a pattern. Returns a dict with keys: group, groups, start, end or None if no match.
### await regex_split(pattern, text) -> list[str]
Split text by a regular expression pattern.
### await llm(prompt) -> str ### await llm(prompt) -> str
Call an LLM directly with the given prompt. Returns the response as a string. Call an LLM directly with the given prompt. Returns the response as a string.
Use this for classification, summarization, extraction, or any task where you Use this for classification, summarization, extraction, or any task where you
@ -63,11 +51,11 @@ Check if it exists with: `try: documents ... except NameError: ...`
## Available Python Features ## Available Python Features
The interpreter supports: variables, arithmetic, strings, f-strings, lists, dicts, tuples, sets, loops, conditionals, comprehensions, functions, async/await, `map()`, `sorted()`/`.sort(key=...)`, try/except, and the `json` module. The interpreter supports: variables, arithmetic, strings, f-strings, lists, dicts, tuples, sets, loops, conditionals, comprehensions, functions, async/await, `map()`, `filter()`, `getattr()`, `sorted()`/`.sort(key=...)`, try/except, and the `json`, `re`, `math` modules.
Not supported: imports (other than `json`), class definitions, generators/yield, match statements, decorators, `with` statements. Not supported: most imports (only `json`, `re`, `math` are available), class definitions, generators/yield, match statements, decorators, `with` statements.
For pattern matching or text extraction, use the `regex_*` functions, string methods (`str.split`, `str.find`, `str.startswith`, `in` operator), or the `llm()` function. For pattern matching or text extraction, use `import re`, string methods (`str.split`, `str.find`, `str.startswith`, `in` operator), or the `llm()` function.
## Strategy Guide ## Strategy Guide
@ -93,10 +81,11 @@ print(f"Total: {count}")
### Extracting data with regex ### Extracting data with regex
```python ```python
import re
numbers = [] numbers = []
results = await search("financial data", limit=20) results = await search("financial data", limit=20)
for r in results: for r in results:
amounts = await regex_findall(r'\\$([\\d,]+)', r['content']) amounts = re.findall(r'\\$([\\d,]+)', r['content'])
for a in amounts: for a in amounts:
numbers.append(int(a.replace(',', ''))) numbers.append(int(a.replace(',', '')))
if numbers: if numbers:

View file

@ -1,5 +1,4 @@
import json import json
import re
from dataclasses import dataclass from dataclasses import dataclass
from typing import TYPE_CHECKING, Any, Literal from typing import TYPE_CHECKING, Any, Literal
@ -128,26 +127,6 @@ class Sandbox:
result = await agent.run(prompt) result = await agent.run(prompt)
return result.output return result.output
async def regex_findall(pattern: str, text: str) -> list[str]:
return re.findall(pattern, text)
async def regex_sub(pattern: str, repl: str, text: str) -> str:
return re.sub(pattern, repl, text)
async def regex_search(pattern: str, text: str) -> dict[str, Any] | None:
m = re.search(pattern, text)
if m is None:
return None
return {
"group": m.group(),
"groups": list(m.groups()),
"start": m.start(),
"end": m.end(),
}
async def regex_split(pattern: str, text: str) -> list[str]:
return re.split(pattern, text)
return { return {
"search": search, "search": search,
"list_documents": list_documents, "list_documents": list_documents,
@ -155,10 +134,6 @@ class Sandbox:
"get_chunk": get_chunk, "get_chunk": get_chunk,
"get_docling_document": get_docling_document, "get_docling_document": get_docling_document,
"llm": llm, "llm": llm,
"regex_findall": regex_findall,
"regex_sub": regex_sub,
"regex_search": regex_search,
"regex_split": regex_split,
} }
async def execute(self, code: str) -> SandboxResult: async def execute(self, code: str) -> SandboxResult:
@ -185,7 +160,6 @@ class Sandbox:
monty = pydantic_monty.Monty( monty = pydantic_monty.Monty(
code, code,
inputs=input_names, inputs=input_names,
external_functions=list(external_fns.keys()),
) )
except ( except (
pydantic_monty.MontySyntaxError, pydantic_monty.MontySyntaxError,

View file

@ -31,7 +31,7 @@ dependencies = [
"pathspec>=1.0.4", "pathspec>=1.0.4",
"pydantic>=2.12.5", "pydantic>=2.12.5",
"pydantic-ai-slim[openai,fastmcp,logfire,ag-ui]>=1.66.0", "pydantic-ai-slim[openai,fastmcp,logfire,ag-ui]>=1.66.0",
"pydantic-monty>=0.0.7", "pydantic-monty>=0.0.8",
"python-dotenv>=1.2.2", "python-dotenv>=1.2.2",
"pyyaml>=6.0.3", "pyyaml>=6.0.3",
"rich>=14.3.3", "rich>=14.3.3",

View file

@ -381,70 +381,6 @@ class TestSandboxDoclingDocument:
assert "True" in result.stdout assert "True" in result.stdout
class TestSandboxRegex:
"""Test regex external functions."""
@pytest.mark.asyncio
async def test_regex_findall(self, sandbox):
"""regex_findall extracts all matches."""
result = await sandbox.execute(
r"matches = await regex_findall(r'\d+', 'abc 123 def 456')"
"\nprint(matches)"
)
assert result.success
assert "['123', '456']" in result.stdout
@pytest.mark.asyncio
async def test_regex_sub(self, sandbox):
"""regex_sub replaces matches."""
result = await sandbox.execute(
r"out = await regex_sub(r'\d+', 'X', 'abc 123 def 456')"
"\nprint(out)"
)
assert result.success
assert "abc X def X" in result.stdout
@pytest.mark.asyncio
async def test_regex_search_match(self, sandbox):
"""regex_search returns match dict when pattern matches."""
result = await sandbox.execute(
r"m = await regex_search(r'(\d+)', 'abc 123')"
"\nprint(m['group'])"
"\nprint(m['start'])"
"\nprint(m['end'])"
)
assert result.success
assert "123" in result.stdout
assert "4" in result.stdout
assert "7" in result.stdout
@pytest.mark.asyncio
async def test_regex_search_no_match(self, sandbox):
"""regex_search returns None when pattern doesn't match."""
result = await sandbox.execute(
r"m = await regex_search(r'\d+', 'abc')"
"\nprint(m is None)"
)
assert result.success
assert "True" in result.stdout
@pytest.mark.asyncio
async def test_regex_split(self, sandbox):
"""regex_split splits on pattern."""
result = await sandbox.execute(
"out = await regex_split(',', 'a,b,,c')\nprint(out)"
)
assert result.success
assert "['a', 'b', '', 'c']" in result.stdout
@pytest.mark.asyncio
async def test_regex_invalid_pattern(self, sandbox):
"""Invalid regex pattern surfaces as an error."""
result = await sandbox.execute("await regex_findall('[invalid', 'text')")
assert not result.success
assert result.stderr != ""
class TestSandboxLLM: class TestSandboxLLM:
"""Test llm() external function.""" """Test llm() external function."""

View file

@ -128,7 +128,7 @@ interactions:
connection: connection:
- keep-alive - keep-alive
content-length: content-length:
- '7737' - '7274'
content-type: content-type:
- application/json - application/json
host: host:
@ -173,18 +173,6 @@ interactions:
- `pictures`: list of figures/images with metadata - `pictures`: list of figures/images with metadata
- `pages`: page dimensions and metadata - `pages`: page dimensions and metadata
### await regex_findall(pattern, text) -> list[str]
Find all non-overlapping matches of a regular expression pattern in text.
### await regex_sub(pattern, repl, text) -> str
Replace all occurrences of a regular expression pattern with a replacement string.
### await regex_search(pattern, text) -> dict | None
Search for the first match of a pattern. Returns a dict with keys: group, groups, start, end — or None if no match.
### await regex_split(pattern, text) -> list[str]
Split text by a regular expression pattern.
### await llm(prompt) -> str ### await llm(prompt) -> str
Call an LLM directly with the given prompt. Returns the response as a string. Call an LLM directly with the given prompt. Returns the response as a string.
Use this for classification, summarization, extraction, or any task where you Use this for classification, summarization, extraction, or any task where you
@ -202,11 +190,11 @@ interactions:
## Available Python Features ## Available Python Features
The interpreter supports: variables, arithmetic, strings, f-strings, lists, dicts, tuples, sets, loops, conditionals, comprehensions, functions, async/await, `map()`, `sorted()`/`.sort(key=...)`, try/except, and the `json` module. The interpreter supports: variables, arithmetic, strings, f-strings, lists, dicts, tuples, sets, loops, conditionals, comprehensions, functions, async/await, `map()`, `filter()`, `getattr()`, `sorted()`/`.sort(key=...)`, try/except, and the `json`, `re`, `math` modules.
Not supported: imports (other than `json`), class definitions, generators/yield, match statements, decorators, `with` statements. Not supported: most imports (only `json`, `re`, `math` are available), class definitions, generators/yield, match statements, decorators, `with` statements.
For pattern matching or text extraction, use the `regex_*` functions, string methods (`str.split`, `str.find`, `str.startswith`, `in` operator), or the `llm()` function. For pattern matching or text extraction, use `import re`, string methods (`str.split`, `str.find`, `str.startswith`, `in` operator), or the `llm()` function.
## Strategy Guide ## Strategy Guide
@ -232,10 +220,11 @@ interactions:
### Extracting data with regex ### Extracting data with regex
```python ```python
import re
numbers = [] numbers = []
results = await search("financial data", limit=20) results = await search("financial data", limit=20)
for r in results: for r in results:
amounts = await regex_findall(r'\$([\d,]+)', r['content']) amounts = re.findall(r'\$([\d,]+)', r['content'])
for a in amounts: for a in amounts:
numbers.append(int(a.replace(',', ''))) numbers.append(int(a.replace(',', '')))
if numbers: if numbers:
@ -296,6 +285,7 @@ interactions:
strict: true strict: true
type: json_schema type: json_schema
stream: false stream: false
temperature: 0.0
tool_choice: auto tool_choice: auto
tools: tools:
- function: - function:
@ -325,7 +315,7 @@ interactions:
response: response:
headers: headers:
content-length: content-length:
- '690' - '699'
content-type: content-type:
- application/json - application/json
parsed_body: parsed_body:
@ -334,25 +324,26 @@ interactions:
index: 0 index: 0
message: message:
content: '' content: ''
reasoning: Need revenue from quarterly reports. Search for "quarterly report revenue". reasoning: Need to search for quarterly reports revenue.
role: assistant role: assistant
tool_calls: tool_calls:
- function: - function:
arguments: '{"code":"results = await search(\"quarterly report revenue\", limit=20)\nprint(len(results))\nfor arguments: '{"code":"import re\n# search for revenue in quarterly reports\nresults = await search(\"quarterly
r in results[:5]:\n print(r[''document_title''], r[''score''], r[''content''][:200])"}' report revenue\", limit=20)\nprint(len(results))\nfor r in results[:5]:\n print(r[''document_title''],
r[''score''])\n"}'
name: execute_code name: execute_code
id: call_no1egdsi id: call_exbbulxp
index: 0 index: 0
type: function type: function
created: 1772626955 created: 1773329130
id: chatcmpl-2 id: chatcmpl-407
model: gpt-oss model: gpt-oss
object: chat.completion object: chat.completion
system_fingerprint: fp_ollama system_fingerprint: fp_ollama
usage: usage:
completion_tokens: 85 completion_tokens: 85
prompt_tokens: 1688 prompt_tokens: 1594
total_tokens: 1773 total_tokens: 1679
status: status:
code: 200 code: 200
message: OK message: OK
@ -405,7 +396,7 @@ interactions:
connection: connection:
- keep-alive - keep-alive
content-length: content-length:
- '8682' - '8148'
content-type: content-type:
- application/json - application/json
host: host:
@ -450,18 +441,6 @@ interactions:
- `pictures`: list of figures/images with metadata - `pictures`: list of figures/images with metadata
- `pages`: page dimensions and metadata - `pages`: page dimensions and metadata
### await regex_findall(pattern, text) -> list[str]
Find all non-overlapping matches of a regular expression pattern in text.
### await regex_sub(pattern, repl, text) -> str
Replace all occurrences of a regular expression pattern with a replacement string.
### await regex_search(pattern, text) -> dict | None
Search for the first match of a pattern. Returns a dict with keys: group, groups, start, end — or None if no match.
### await regex_split(pattern, text) -> list[str]
Split text by a regular expression pattern.
### await llm(prompt) -> str ### await llm(prompt) -> str
Call an LLM directly with the given prompt. Returns the response as a string. Call an LLM directly with the given prompt. Returns the response as a string.
Use this for classification, summarization, extraction, or any task where you Use this for classification, summarization, extraction, or any task where you
@ -479,11 +458,11 @@ interactions:
## Available Python Features ## Available Python Features
The interpreter supports: variables, arithmetic, strings, f-strings, lists, dicts, tuples, sets, loops, conditionals, comprehensions, functions, async/await, `map()`, `sorted()`/`.sort(key=...)`, try/except, and the `json` module. The interpreter supports: variables, arithmetic, strings, f-strings, lists, dicts, tuples, sets, loops, conditionals, comprehensions, functions, async/await, `map()`, `filter()`, `getattr()`, `sorted()`/`.sort(key=...)`, try/except, and the `json`, `re`, `math` modules.
Not supported: imports (other than `json`), class definitions, generators/yield, match statements, decorators, `with` statements. Not supported: most imports (only `json`, `re`, `math` are available), class definitions, generators/yield, match statements, decorators, `with` statements.
For pattern matching or text extraction, use the `regex_*` functions, string methods (`str.split`, `str.find`, `str.startswith`, `in` operator), or the `llm()` function. For pattern matching or text extraction, use `import re`, string methods (`str.split`, `str.find`, `str.startswith`, `in` operator), or the `llm()` function.
## Strategy Guide ## Strategy Guide
@ -509,10 +488,11 @@ interactions:
### Extracting data with regex ### Extracting data with regex
```python ```python
import re
numbers = [] numbers = []
results = await search("financial data", limit=20) results = await search("financial data", limit=20)
for r in results: for r in results:
amounts = await regex_findall(r'\$([\d,]+)', r['content']) amounts = re.findall(r'\$([\d,]+)', r['content'])
for a in amounts: for a in amounts:
numbers.append(int(a.replace(',', ''))) numbers.append(int(a.replace(',', '')))
if numbers: if numbers:
@ -552,21 +532,20 @@ interactions:
- content: What is the total revenue across all quarterly reports? - content: What is the total revenue across all quarterly reports?
role: user role: user
- content: null - content: null
reasoning: Need revenue from quarterly reports. Search for "quarterly report revenue". reasoning: Need to search for quarterly reports revenue.
role: assistant role: assistant
tool_calls: tool_calls:
- function: - function:
arguments: '{"code":"results = await search(\"quarterly report revenue\", limit=20)\nprint(len(results))\nfor arguments: '{"code":"import re\n# search for revenue in quarterly reports\nresults = await search(\"quarterly
r in results[:5]:\n print(r[''document_title''], r[''score''], r[''content''][:200])"}' report revenue\", limit=20)\nprint(len(results))\nfor r in results[:5]:\n print(r[''document_title''], r[''score''])\n"}'
name: execute_code name: execute_code
id: call_no1egdsi id: call_exbbulxp
type: function type: function
- content: '{"code":"results = await search(\"quarterly report revenue\", limit=20)\nprint(len(results))\nfor r in results[:5]:\n print(r[''document_title''], - content: '{"code":"import re\n# search for revenue in quarterly reports\nresults = await search(\"quarterly report
r[''score''], r[''content''][:200])","stdout":"3\nQ1 Report 0.03226645663380623 Sales report Q1: Revenue was $100,000.\nQ2 revenue\", limit=20)\nprint(len(results))\nfor r in results[:5]:\n print(r[''document_title''], r[''score''])\n","stdout":"3\nQ1
Report 0.03226645663380623 Sales report Q2: Revenue was $150,000.\nQ3 Report 0.032258063554763794 Sales report Q3: Report 0.03226645663380623\nQ2 Report 0.03226645663380623\nQ3 Report 0.032258063554763794\n","stderr":"","success":true}'
Revenue was $200,000.\n","stderr":"","success":true}'
role: tool role: tool
tool_call_id: call_no1egdsi tool_call_id: call_exbbulxp
model: gpt-oss model: gpt-oss
reasoning_effort: low reasoning_effort: low
response_format: response_format:
@ -589,6 +568,7 @@ interactions:
strict: true strict: true
type: json_schema type: json_schema
stream: false stream: false
temperature: 0.0
tool_choice: auto tool_choice: auto
tools: tools:
- function: - function:
@ -618,7 +598,7 @@ interactions:
response: response:
headers: headers:
content-length: content-length:
- '689' - '680'
content-type: content-type:
- application/json - application/json
parsed_body: parsed_body:
@ -627,25 +607,25 @@ interactions:
index: 0 index: 0
message: message:
content: '' content: ''
reasoning: Three reports with revenue numbers. Sum = 450k. Need citation chunks. Retrieve chunks. reasoning: We need revenue numbers. Let's fetch chunks.
role: assistant role: assistant
tool_calls: tool_calls:
- function: - function:
arguments: '{"code":"chunks = []\nfor r in results:\n chunk = await get_chunk(r[''chunk_id''])\n chunks.append(chunk)\n print(chunk[''document_title''], arguments: '{"code":"# get chunks for each result\nchunks = []\nfor r in results:\n chunk = await get_chunk(r[''chunk_id''])\n chunks.append(chunk)\n print(chunk[''document_title''],
chunk[''content''].strip())"}' chunk[''content''][:200])\n"}'
name: execute_code name: execute_code
id: call_sg5vtxpb id: call_2hd3mgon
index: 0 index: 0
type: function type: function
created: 1772626957 created: 1773329146
id: chatcmpl-37 id: chatcmpl-173
model: gpt-oss model: gpt-oss
object: chat.completion object: chat.completion
system_fingerprint: fp_ollama system_fingerprint: fp_ollama
usage: usage:
completion_tokens: 85 completion_tokens: 85
prompt_tokens: 1922 prompt_tokens: 1798
total_tokens: 2007 total_tokens: 1883
status: status:
code: 200 code: 200
message: OK message: OK
@ -658,7 +638,7 @@ interactions:
connection: connection:
- keep-alive - keep-alive
content-length: content-length:
- '9437' - '8925'
content-type: content-type:
- application/json - application/json
host: host:
@ -703,18 +683,6 @@ interactions:
- `pictures`: list of figures/images with metadata - `pictures`: list of figures/images with metadata
- `pages`: page dimensions and metadata - `pages`: page dimensions and metadata
### await regex_findall(pattern, text) -> list[str]
Find all non-overlapping matches of a regular expression pattern in text.
### await regex_sub(pattern, repl, text) -> str
Replace all occurrences of a regular expression pattern with a replacement string.
### await regex_search(pattern, text) -> dict | None
Search for the first match of a pattern. Returns a dict with keys: group, groups, start, end — or None if no match.
### await regex_split(pattern, text) -> list[str]
Split text by a regular expression pattern.
### await llm(prompt) -> str ### await llm(prompt) -> str
Call an LLM directly with the given prompt. Returns the response as a string. Call an LLM directly with the given prompt. Returns the response as a string.
Use this for classification, summarization, extraction, or any task where you Use this for classification, summarization, extraction, or any task where you
@ -732,11 +700,11 @@ interactions:
## Available Python Features ## Available Python Features
The interpreter supports: variables, arithmetic, strings, f-strings, lists, dicts, tuples, sets, loops, conditionals, comprehensions, functions, async/await, `map()`, `sorted()`/`.sort(key=...)`, try/except, and the `json` module. The interpreter supports: variables, arithmetic, strings, f-strings, lists, dicts, tuples, sets, loops, conditionals, comprehensions, functions, async/await, `map()`, `filter()`, `getattr()`, `sorted()`/`.sort(key=...)`, try/except, and the `json`, `re`, `math` modules.
Not supported: imports (other than `json`), class definitions, generators/yield, match statements, decorators, `with` statements. Not supported: most imports (only `json`, `re`, `math` are available), class definitions, generators/yield, match statements, decorators, `with` statements.
For pattern matching or text extraction, use the `regex_*` functions, string methods (`str.split`, `str.find`, `str.startswith`, `in` operator), or the `llm()` function. For pattern matching or text extraction, use `import re`, string methods (`str.split`, `str.find`, `str.startswith`, `in` operator), or the `llm()` function.
## Strategy Guide ## Strategy Guide
@ -762,10 +730,11 @@ interactions:
### Extracting data with regex ### Extracting data with regex
```python ```python
import re
numbers = [] numbers = []
results = await search("financial data", limit=20) results = await search("financial data", limit=20)
for r in results: for r in results:
amounts = await regex_findall(r'\$([\d,]+)', r['content']) amounts = re.findall(r'\$([\d,]+)', r['content'])
for a in amounts: for a in amounts:
numbers.append(int(a.replace(',', ''))) numbers.append(int(a.replace(',', '')))
if numbers: if numbers:
@ -805,35 +774,34 @@ interactions:
- content: What is the total revenue across all quarterly reports? - content: What is the total revenue across all quarterly reports?
role: user role: user
- content: null - content: null
reasoning: Need revenue from quarterly reports. Search for "quarterly report revenue". reasoning: Need to search for quarterly reports revenue.
role: assistant role: assistant
tool_calls: tool_calls:
- function: - function:
arguments: '{"code":"results = await search(\"quarterly report revenue\", limit=20)\nprint(len(results))\nfor arguments: '{"code":"import re\n# search for revenue in quarterly reports\nresults = await search(\"quarterly
r in results[:5]:\n print(r[''document_title''], r[''score''], r[''content''][:200])"}' report revenue\", limit=20)\nprint(len(results))\nfor r in results[:5]:\n print(r[''document_title''], r[''score''])\n"}'
name: execute_code name: execute_code
id: call_no1egdsi id: call_exbbulxp
type: function type: function
- content: '{"code":"results = await search(\"quarterly report revenue\", limit=20)\nprint(len(results))\nfor r in results[:5]:\n print(r[''document_title''], - content: '{"code":"import re\n# search for revenue in quarterly reports\nresults = await search(\"quarterly report
r[''score''], r[''content''][:200])","stdout":"3\nQ1 Report 0.03226645663380623 Sales report Q1: Revenue was $100,000.\nQ2 revenue\", limit=20)\nprint(len(results))\nfor r in results[:5]:\n print(r[''document_title''], r[''score''])\n","stdout":"3\nQ1
Report 0.03226645663380623 Sales report Q2: Revenue was $150,000.\nQ3 Report 0.032258063554763794 Sales report Q3: Report 0.03226645663380623\nQ2 Report 0.03226645663380623\nQ3 Report 0.032258063554763794\n","stderr":"","success":true}'
Revenue was $200,000.\n","stderr":"","success":true}'
role: tool role: tool
tool_call_id: call_no1egdsi tool_call_id: call_exbbulxp
- content: null - content: null
reasoning: Three reports with revenue numbers. Sum = 450k. Need citation chunks. Retrieve chunks. reasoning: We need revenue numbers. Let's fetch chunks.
role: assistant role: assistant
tool_calls: tool_calls:
- function: - function:
arguments: '{"code":"chunks = []\nfor r in results:\n chunk = await get_chunk(r[''chunk_id''])\n chunks.append(chunk)\n print(chunk[''document_title''], arguments: '{"code":"# get chunks for each result\nchunks = []\nfor r in results:\n chunk = await get_chunk(r[''chunk_id''])\n chunks.append(chunk)\n print(chunk[''document_title''],
chunk[''content''].strip())"}' chunk[''content''][:200])\n"}'
name: execute_code name: execute_code
id: call_sg5vtxpb id: call_2hd3mgon
type: function type: function
- content: '{"code":"chunks = []\nfor r in results:\n chunk = await get_chunk(r[''chunk_id''])\n chunks.append(chunk)\n print(chunk[''document_title''], - content: '{"code":"# get chunks for each result\nchunks = []\nfor r in results:\n chunk = await get_chunk(r[''chunk_id''])\n chunks.append(chunk)\n print(chunk[''document_title''],
chunk[''content''].strip())","stdout":"","stderr":"NameError: name ''results'' is not defined","success":false}' chunk[''content''][:200])\n","stdout":"","stderr":"NameError: name ''results'' is not defined","success":false}'
role: tool role: tool
tool_call_id: call_sg5vtxpb tool_call_id: call_2hd3mgon
model: gpt-oss model: gpt-oss
reasoning_effort: low reasoning_effort: low
response_format: response_format:
@ -856,6 +824,7 @@ interactions:
strict: true strict: true
type: json_schema type: json_schema
stream: false stream: false
temperature: 0.0
tool_choice: auto tool_choice: auto
tools: tools:
- function: - function:
@ -885,7 +854,7 @@ interactions:
response: response:
headers: headers:
content-length: content-length:
- '737' - '713'
content-type: content-type:
- application/json - application/json
parsed_body: parsed_body:
@ -894,25 +863,25 @@ interactions:
index: 0 index: 0
message: message:
content: '' content: ''
reasoning: Need to keep results variable. Use same scope. Let's re-run with storing results. reasoning: Need to re-run search inside same code.
role: assistant role: assistant
tool_calls: tool_calls:
- function: - function:
arguments: '{"code":"results = await search(\"quarterly report revenue\", limit=20)\nchunks = []\nfor r in results:\n c arguments: '{"code":"results = await search(\"quarterly report revenue\", limit=20)\nchunks = []\nfor r in results:\n chunk
= await get_chunk(r[''chunk_id''])\n chunks.append(c)\n print(c[''document_title''], c[''content''].strip())"}' = await get_chunk(r[''chunk_id''])\n chunks.append(chunk)\n print(chunk[''document_title''], chunk[''content''][:200])\n"}'
name: execute_code name: execute_code
id: call_h6pfbenb id: call_10n40kz9
index: 0 index: 0
type: function type: function
created: 1772626960 created: 1773329159
id: chatcmpl-20 id: chatcmpl-749
model: gpt-oss model: gpt-oss
object: chat.completion object: chat.completion
system_fingerprint: fp_ollama system_fingerprint: fp_ollama
usage: usage:
completion_tokens: 98 completion_tokens: 93
prompt_tokens: 2084 prompt_tokens: 1970
total_tokens: 2182 total_tokens: 2063
status: status:
code: 200 code: 200
message: OK message: OK
@ -965,7 +934,7 @@ interactions:
connection: connection:
- keep-alive - keep-alive
content-length: content-length:
- '10405' - '9885'
content-type: content-type:
- application/json - application/json
host: host:
@ -1010,18 +979,6 @@ interactions:
- `pictures`: list of figures/images with metadata - `pictures`: list of figures/images with metadata
- `pages`: page dimensions and metadata - `pages`: page dimensions and metadata
### await regex_findall(pattern, text) -> list[str]
Find all non-overlapping matches of a regular expression pattern in text.
### await regex_sub(pattern, repl, text) -> str
Replace all occurrences of a regular expression pattern with a replacement string.
### await regex_search(pattern, text) -> dict | None
Search for the first match of a pattern. Returns a dict with keys: group, groups, start, end — or None if no match.
### await regex_split(pattern, text) -> list[str]
Split text by a regular expression pattern.
### await llm(prompt) -> str ### await llm(prompt) -> str
Call an LLM directly with the given prompt. Returns the response as a string. Call an LLM directly with the given prompt. Returns the response as a string.
Use this for classification, summarization, extraction, or any task where you Use this for classification, summarization, extraction, or any task where you
@ -1039,11 +996,11 @@ interactions:
## Available Python Features ## Available Python Features
The interpreter supports: variables, arithmetic, strings, f-strings, lists, dicts, tuples, sets, loops, conditionals, comprehensions, functions, async/await, `map()`, `sorted()`/`.sort(key=...)`, try/except, and the `json` module. The interpreter supports: variables, arithmetic, strings, f-strings, lists, dicts, tuples, sets, loops, conditionals, comprehensions, functions, async/await, `map()`, `filter()`, `getattr()`, `sorted()`/`.sort(key=...)`, try/except, and the `json`, `re`, `math` modules.
Not supported: imports (other than `json`), class definitions, generators/yield, match statements, decorators, `with` statements. Not supported: most imports (only `json`, `re`, `math` are available), class definitions, generators/yield, match statements, decorators, `with` statements.
For pattern matching or text extraction, use the `regex_*` functions, string methods (`str.split`, `str.find`, `str.startswith`, `in` operator), or the `llm()` function. For pattern matching or text extraction, use `import re`, string methods (`str.split`, `str.find`, `str.startswith`, `in` operator), or the `llm()` function.
## Strategy Guide ## Strategy Guide
@ -1069,10 +1026,11 @@ interactions:
### Extracting data with regex ### Extracting data with regex
```python ```python
import re
numbers = [] numbers = []
results = await search("financial data", limit=20) results = await search("financial data", limit=20)
for r in results: for r in results:
amounts = await regex_findall(r'\$([\d,]+)', r['content']) amounts = re.findall(r'\$([\d,]+)', r['content'])
for a in amounts: for a in amounts:
numbers.append(int(a.replace(',', ''))) numbers.append(int(a.replace(',', '')))
if numbers: if numbers:
@ -1112,51 +1070,50 @@ interactions:
- content: What is the total revenue across all quarterly reports? - content: What is the total revenue across all quarterly reports?
role: user role: user
- content: null - content: null
reasoning: Need revenue from quarterly reports. Search for "quarterly report revenue". reasoning: Need to search for quarterly reports revenue.
role: assistant role: assistant
tool_calls: tool_calls:
- function: - function:
arguments: '{"code":"results = await search(\"quarterly report revenue\", limit=20)\nprint(len(results))\nfor arguments: '{"code":"import re\n# search for revenue in quarterly reports\nresults = await search(\"quarterly
r in results[:5]:\n print(r[''document_title''], r[''score''], r[''content''][:200])"}' report revenue\", limit=20)\nprint(len(results))\nfor r in results[:5]:\n print(r[''document_title''], r[''score''])\n"}'
name: execute_code name: execute_code
id: call_no1egdsi id: call_exbbulxp
type: function type: function
- content: '{"code":"results = await search(\"quarterly report revenue\", limit=20)\nprint(len(results))\nfor r in results[:5]:\n print(r[''document_title''], - content: '{"code":"import re\n# search for revenue in quarterly reports\nresults = await search(\"quarterly report
r[''score''], r[''content''][:200])","stdout":"3\nQ1 Report 0.03226645663380623 Sales report Q1: Revenue was $100,000.\nQ2 revenue\", limit=20)\nprint(len(results))\nfor r in results[:5]:\n print(r[''document_title''], r[''score''])\n","stdout":"3\nQ1
Report 0.03226645663380623 Sales report Q2: Revenue was $150,000.\nQ3 Report 0.032258063554763794 Sales report Q3: Report 0.03226645663380623\nQ2 Report 0.03226645663380623\nQ3 Report 0.032258063554763794\n","stderr":"","success":true}'
Revenue was $200,000.\n","stderr":"","success":true}'
role: tool role: tool
tool_call_id: call_no1egdsi tool_call_id: call_exbbulxp
- content: null - content: null
reasoning: Three reports with revenue numbers. Sum = 450k. Need citation chunks. Retrieve chunks. reasoning: We need revenue numbers. Let's fetch chunks.
role: assistant role: assistant
tool_calls: tool_calls:
- function: - function:
arguments: '{"code":"chunks = []\nfor r in results:\n chunk = await get_chunk(r[''chunk_id''])\n chunks.append(chunk)\n print(chunk[''document_title''], arguments: '{"code":"# get chunks for each result\nchunks = []\nfor r in results:\n chunk = await get_chunk(r[''chunk_id''])\n chunks.append(chunk)\n print(chunk[''document_title''],
chunk[''content''].strip())"}' chunk[''content''][:200])\n"}'
name: execute_code name: execute_code
id: call_sg5vtxpb id: call_2hd3mgon
type: function type: function
- content: '{"code":"chunks = []\nfor r in results:\n chunk = await get_chunk(r[''chunk_id''])\n chunks.append(chunk)\n print(chunk[''document_title''], - content: '{"code":"# get chunks for each result\nchunks = []\nfor r in results:\n chunk = await get_chunk(r[''chunk_id''])\n chunks.append(chunk)\n print(chunk[''document_title''],
chunk[''content''].strip())","stdout":"","stderr":"NameError: name ''results'' is not defined","success":false}' chunk[''content''][:200])\n","stdout":"","stderr":"NameError: name ''results'' is not defined","success":false}'
role: tool role: tool
tool_call_id: call_sg5vtxpb tool_call_id: call_2hd3mgon
- content: null - content: null
reasoning: Need to keep results variable. Use same scope. Let's re-run with storing results. reasoning: Need to re-run search inside same code.
role: assistant role: assistant
tool_calls: tool_calls:
- function: - function:
arguments: '{"code":"results = await search(\"quarterly report revenue\", limit=20)\nchunks = []\nfor r in results:\n c arguments: '{"code":"results = await search(\"quarterly report revenue\", limit=20)\nchunks = []\nfor r in results:\n chunk
= await get_chunk(r[''chunk_id''])\n chunks.append(c)\n print(c[''document_title''], c[''content''].strip())"}' = await get_chunk(r[''chunk_id''])\n chunks.append(chunk)\n print(chunk[''document_title''], chunk[''content''][:200])\n"}'
name: execute_code name: execute_code
id: call_h6pfbenb id: call_10n40kz9
type: function type: function
- content: '{"code":"results = await search(\"quarterly report revenue\", limit=20)\nchunks = []\nfor r in results:\n c - content: '{"code":"results = await search(\"quarterly report revenue\", limit=20)\nchunks = []\nfor r in results:\n chunk
= await get_chunk(r[''chunk_id''])\n chunks.append(c)\n print(c[''document_title''], c[''content''].strip())","stdout":"Q1 = await get_chunk(r[''chunk_id''])\n chunks.append(chunk)\n print(chunk[''document_title''], chunk[''content''][:200])\n","stdout":"Q1
Report Sales report Q1: Revenue was $100,000.\nQ2 Report Sales report Q2: Revenue was $150,000.\nQ3 Report Sales Report Sales report Q1: Revenue was $100,000.\nQ2 Report Sales report Q2: Revenue was $150,000.\nQ3 Report Sales
report Q3: Revenue was $200,000.\n","stderr":"","success":true}' report Q3: Revenue was $200,000.\n","stderr":"","success":true}'
role: tool role: tool
tool_call_id: call_h6pfbenb tool_call_id: call_10n40kz9
model: gpt-oss model: gpt-oss
reasoning_effort: low reasoning_effort: low
response_format: response_format:
@ -1179,6 +1136,7 @@ interactions:
strict: true strict: true
type: json_schema type: json_schema
stream: false stream: false
temperature: 0.0
tool_choice: auto tool_choice: auto
tools: tools:
- function: - function:
@ -1208,7 +1166,7 @@ interactions:
response: response:
headers: headers:
content-length: content-length:
- '614' - '643'
content-type: content-type:
- application/json - application/json
parsed_body: parsed_body:
@ -1216,25 +1174,26 @@ interactions:
- finish_reason: tool_calls - finish_reason: tool_calls
index: 0 index: 0
message: message:
content: Now compute sum. content: ''
reasoning: Sum revenues.
role: assistant role: assistant
tool_calls: tool_calls:
- function: - function:
arguments: '{"code":"total = 0\nfor c in chunks:\n nums = await regex_findall(r''\\$([\\d,]+)'', c[''content''])\n for arguments: '{"code":"total=0\nfor c in chunks:\n import re\n m=re.search(r''\\$([\\d,]+)'', c[''content''])\n if
n in nums:\n total += int(n.replace('','', ''''))\nprint(total)"}' m:\n val=int(m.group(1).replace('','',''''))\n total+=val\nprint(total)\n"}'
name: execute_code name: execute_code
id: call_rlqh271l id: call_51jmnwfv
index: 0 index: 0
type: function type: function
created: 1772626962 created: 1773329170
id: chatcmpl-924 id: chatcmpl-461
model: gpt-oss model: gpt-oss
object: chat.completion object: chat.completion
system_fingerprint: fp_ollama system_fingerprint: fp_ollama
usage: usage:
completion_tokens: 83 completion_tokens: 88
prompt_tokens: 2312 prompt_tokens: 2196
total_tokens: 2395 total_tokens: 2284
status: status:
code: 200 code: 200
message: OK message: OK
@ -1247,7 +1206,7 @@ interactions:
connection: connection:
- keep-alive - keep-alive
content-length: content-length:
- '11090' - '10618'
content-type: content-type:
- application/json - application/json
host: host:
@ -1292,18 +1251,6 @@ interactions:
- `pictures`: list of figures/images with metadata - `pictures`: list of figures/images with metadata
- `pages`: page dimensions and metadata - `pages`: page dimensions and metadata
### await regex_findall(pattern, text) -> list[str]
Find all non-overlapping matches of a regular expression pattern in text.
### await regex_sub(pattern, repl, text) -> str
Replace all occurrences of a regular expression pattern with a replacement string.
### await regex_search(pattern, text) -> dict | None
Search for the first match of a pattern. Returns a dict with keys: group, groups, start, end — or None if no match.
### await regex_split(pattern, text) -> list[str]
Split text by a regular expression pattern.
### await llm(prompt) -> str ### await llm(prompt) -> str
Call an LLM directly with the given prompt. Returns the response as a string. Call an LLM directly with the given prompt. Returns the response as a string.
Use this for classification, summarization, extraction, or any task where you Use this for classification, summarization, extraction, or any task where you
@ -1321,11 +1268,11 @@ interactions:
## Available Python Features ## Available Python Features
The interpreter supports: variables, arithmetic, strings, f-strings, lists, dicts, tuples, sets, loops, conditionals, comprehensions, functions, async/await, `map()`, `sorted()`/`.sort(key=...)`, try/except, and the `json` module. The interpreter supports: variables, arithmetic, strings, f-strings, lists, dicts, tuples, sets, loops, conditionals, comprehensions, functions, async/await, `map()`, `filter()`, `getattr()`, `sorted()`/`.sort(key=...)`, try/except, and the `json`, `re`, `math` modules.
Not supported: imports (other than `json`), class definitions, generators/yield, match statements, decorators, `with` statements. Not supported: most imports (only `json`, `re`, `math` are available), class definitions, generators/yield, match statements, decorators, `with` statements.
For pattern matching or text extraction, use the `regex_*` functions, string methods (`str.split`, `str.find`, `str.startswith`, `in` operator), or the `llm()` function. For pattern matching or text extraction, use `import re`, string methods (`str.split`, `str.find`, `str.startswith`, `in` operator), or the `llm()` function.
## Strategy Guide ## Strategy Guide
@ -1351,10 +1298,11 @@ interactions:
### Extracting data with regex ### Extracting data with regex
```python ```python
import re
numbers = [] numbers = []
results = await search("financial data", limit=20) results = await search("financial data", limit=20)
for r in results: for r in results:
amounts = await regex_findall(r'\$([\d,]+)', r['content']) amounts = re.findall(r'\$([\d,]+)', r['content'])
for a in amounts: for a in amounts:
numbers.append(int(a.replace(',', ''))) numbers.append(int(a.replace(',', '')))
if numbers: if numbers:
@ -1394,65 +1342,65 @@ interactions:
- content: What is the total revenue across all quarterly reports? - content: What is the total revenue across all quarterly reports?
role: user role: user
- content: null - content: null
reasoning: Need revenue from quarterly reports. Search for "quarterly report revenue". reasoning: Need to search for quarterly reports revenue.
role: assistant role: assistant
tool_calls: tool_calls:
- function: - function:
arguments: '{"code":"results = await search(\"quarterly report revenue\", limit=20)\nprint(len(results))\nfor arguments: '{"code":"import re\n# search for revenue in quarterly reports\nresults = await search(\"quarterly
r in results[:5]:\n print(r[''document_title''], r[''score''], r[''content''][:200])"}' report revenue\", limit=20)\nprint(len(results))\nfor r in results[:5]:\n print(r[''document_title''], r[''score''])\n"}'
name: execute_code name: execute_code
id: call_no1egdsi id: call_exbbulxp
type: function type: function
- content: '{"code":"results = await search(\"quarterly report revenue\", limit=20)\nprint(len(results))\nfor r in results[:5]:\n print(r[''document_title''], - content: '{"code":"import re\n# search for revenue in quarterly reports\nresults = await search(\"quarterly report
r[''score''], r[''content''][:200])","stdout":"3\nQ1 Report 0.03226645663380623 Sales report Q1: Revenue was $100,000.\nQ2 revenue\", limit=20)\nprint(len(results))\nfor r in results[:5]:\n print(r[''document_title''], r[''score''])\n","stdout":"3\nQ1
Report 0.03226645663380623 Sales report Q2: Revenue was $150,000.\nQ3 Report 0.032258063554763794 Sales report Q3: Report 0.03226645663380623\nQ2 Report 0.03226645663380623\nQ3 Report 0.032258063554763794\n","stderr":"","success":true}'
Revenue was $200,000.\n","stderr":"","success":true}'
role: tool role: tool
tool_call_id: call_no1egdsi tool_call_id: call_exbbulxp
- content: null - content: null
reasoning: Three reports with revenue numbers. Sum = 450k. Need citation chunks. Retrieve chunks. reasoning: We need revenue numbers. Let's fetch chunks.
role: assistant role: assistant
tool_calls: tool_calls:
- function: - function:
arguments: '{"code":"chunks = []\nfor r in results:\n chunk = await get_chunk(r[''chunk_id''])\n chunks.append(chunk)\n print(chunk[''document_title''], arguments: '{"code":"# get chunks for each result\nchunks = []\nfor r in results:\n chunk = await get_chunk(r[''chunk_id''])\n chunks.append(chunk)\n print(chunk[''document_title''],
chunk[''content''].strip())"}' chunk[''content''][:200])\n"}'
name: execute_code name: execute_code
id: call_sg5vtxpb id: call_2hd3mgon
type: function type: function
- content: '{"code":"chunks = []\nfor r in results:\n chunk = await get_chunk(r[''chunk_id''])\n chunks.append(chunk)\n print(chunk[''document_title''], - content: '{"code":"# get chunks for each result\nchunks = []\nfor r in results:\n chunk = await get_chunk(r[''chunk_id''])\n chunks.append(chunk)\n print(chunk[''document_title''],
chunk[''content''].strip())","stdout":"","stderr":"NameError: name ''results'' is not defined","success":false}' chunk[''content''][:200])\n","stdout":"","stderr":"NameError: name ''results'' is not defined","success":false}'
role: tool role: tool
tool_call_id: call_sg5vtxpb tool_call_id: call_2hd3mgon
- content: null - content: null
reasoning: Need to keep results variable. Use same scope. Let's re-run with storing results. reasoning: Need to re-run search inside same code.
role: assistant role: assistant
tool_calls: tool_calls:
- function: - function:
arguments: '{"code":"results = await search(\"quarterly report revenue\", limit=20)\nchunks = []\nfor r in results:\n c arguments: '{"code":"results = await search(\"quarterly report revenue\", limit=20)\nchunks = []\nfor r in results:\n chunk
= await get_chunk(r[''chunk_id''])\n chunks.append(c)\n print(c[''document_title''], c[''content''].strip())"}' = await get_chunk(r[''chunk_id''])\n chunks.append(chunk)\n print(chunk[''document_title''], chunk[''content''][:200])\n"}'
name: execute_code name: execute_code
id: call_h6pfbenb id: call_10n40kz9
type: function type: function
- content: '{"code":"results = await search(\"quarterly report revenue\", limit=20)\nchunks = []\nfor r in results:\n c - content: '{"code":"results = await search(\"quarterly report revenue\", limit=20)\nchunks = []\nfor r in results:\n chunk
= await get_chunk(r[''chunk_id''])\n chunks.append(c)\n print(c[''document_title''], c[''content''].strip())","stdout":"Q1 = await get_chunk(r[''chunk_id''])\n chunks.append(chunk)\n print(chunk[''document_title''], chunk[''content''][:200])\n","stdout":"Q1
Report Sales report Q1: Revenue was $100,000.\nQ2 Report Sales report Q2: Revenue was $150,000.\nQ3 Report Sales Report Sales report Q1: Revenue was $100,000.\nQ2 Report Sales report Q2: Revenue was $150,000.\nQ3 Report Sales
report Q3: Revenue was $200,000.\n","stderr":"","success":true}' report Q3: Revenue was $200,000.\n","stderr":"","success":true}'
role: tool role: tool
tool_call_id: call_h6pfbenb tool_call_id: call_10n40kz9
- content: Now compute sum. - content: null
reasoning: Sum revenues.
role: assistant role: assistant
tool_calls: tool_calls:
- function: - function:
arguments: '{"code":"total = 0\nfor c in chunks:\n nums = await regex_findall(r''\\$([\\d,]+)'', c[''content''])\n for arguments: '{"code":"total=0\nfor c in chunks:\n import re\n m=re.search(r''\\$([\\d,]+)'', c[''content''])\n if
n in nums:\n total += int(n.replace('','', ''''))\nprint(total)"}' m:\n val=int(m.group(1).replace('','',''''))\n total+=val\nprint(total)\n"}'
name: execute_code name: execute_code
id: call_rlqh271l id: call_51jmnwfv
type: function type: function
- content: '{"code":"total = 0\nfor c in chunks:\n nums = await regex_findall(r''\\$([\\d,]+)'', c[''content''])\n for - content: '{"code":"total=0\nfor c in chunks:\n import re\n m=re.search(r''\\$([\\d,]+)'', c[''content''])\n if
n in nums:\n total += int(n.replace('','', ''''))\nprint(total)","stdout":"","stderr":"NameError: name ''chunks'' m:\n val=int(m.group(1).replace('','',''''))\n total+=val\nprint(total)\n","stdout":"","stderr":"NameError:
is not defined","success":false}' name ''chunks'' is not defined","success":false}'
role: tool role: tool
tool_call_id: call_rlqh271l tool_call_id: call_51jmnwfv
model: gpt-oss model: gpt-oss
reasoning_effort: low reasoning_effort: low
response_format: response_format:
@ -1475,6 +1423,7 @@ interactions:
strict: true strict: true
type: json_schema type: json_schema
stream: false stream: false
temperature: 0.0
tool_choice: auto tool_choice: auto
tools: tools:
- function: - function:
@ -1504,7 +1453,7 @@ interactions:
response: response:
headers: headers:
content-length: content-length:
- '819' - '848'
content-type: content-type:
- application/json - application/json
parsed_body: parsed_body:
@ -1513,27 +1462,26 @@ interactions:
index: 0 index: 0
message: message:
content: '' content: ''
reasoning: Variable scope lost. Let's combine. reasoning: Need to keep chunks variable. Let's combine.
role: assistant role: assistant
tool_calls: tool_calls:
- function: - function:
arguments: '{"code":"results = await search(\"quarterly report revenue\", limit=20)\nchunks = []\nfor r in results:\n c arguments: '{"code":"results = await search(\"quarterly report revenue\", limit=20)\nchunks = []\nfor r in results:\n chunk
= await get_chunk(r[''chunk_id''])\n chunks.append(c)\n\ntotal = 0\nfor c in chunks:\n nums = await = await get_chunk(r[''chunk_id''])\n chunks.append(chunk)\n\ntotal=0\nimport re\nfor c in chunks:\n m=re.search(r''\\$([\\d,]+)'',
regex_findall(r''\\$([\\d,]+)'', c[''content''])\n for n in nums:\n total += int(n.replace('','', c[''content''])\n if m:\n val=int(m.group(1).replace('','',''''))\n total+=val\nprint(total)\n"}'
''''))\nprint(total)"}'
name: execute_code name: execute_code
id: call_kbsx3dxm id: call_axsiusi8
index: 0 index: 0
type: function type: function
created: 1772626965 created: 1773329179
id: chatcmpl-319 id: chatcmpl-56
model: gpt-oss model: gpt-oss
object: chat.completion object: chat.completion
system_fingerprint: fp_ollama system_fingerprint: fp_ollama
usage: usage:
completion_tokens: 132 completion_tokens: 140
prompt_tokens: 2483 prompt_tokens: 2380
total_tokens: 2615 total_tokens: 2520
status: status:
code: 200 code: 200
message: OK message: OK
@ -1586,7 +1534,7 @@ interactions:
connection: connection:
- keep-alive - keep-alive
content-length: content-length:
- '12120' - '11699'
content-type: content-type:
- application/json - application/json
host: host:
@ -1631,18 +1579,6 @@ interactions:
- `pictures`: list of figures/images with metadata - `pictures`: list of figures/images with metadata
- `pages`: page dimensions and metadata - `pages`: page dimensions and metadata
### await regex_findall(pattern, text) -> list[str]
Find all non-overlapping matches of a regular expression pattern in text.
### await regex_sub(pattern, repl, text) -> str
Replace all occurrences of a regular expression pattern with a replacement string.
### await regex_search(pattern, text) -> dict | None
Search for the first match of a pattern. Returns a dict with keys: group, groups, start, end — or None if no match.
### await regex_split(pattern, text) -> list[str]
Split text by a regular expression pattern.
### await llm(prompt) -> str ### await llm(prompt) -> str
Call an LLM directly with the given prompt. Returns the response as a string. Call an LLM directly with the given prompt. Returns the response as a string.
Use this for classification, summarization, extraction, or any task where you Use this for classification, summarization, extraction, or any task where you
@ -1660,11 +1596,11 @@ interactions:
## Available Python Features ## Available Python Features
The interpreter supports: variables, arithmetic, strings, f-strings, lists, dicts, tuples, sets, loops, conditionals, comprehensions, functions, async/await, `map()`, `sorted()`/`.sort(key=...)`, try/except, and the `json` module. The interpreter supports: variables, arithmetic, strings, f-strings, lists, dicts, tuples, sets, loops, conditionals, comprehensions, functions, async/await, `map()`, `filter()`, `getattr()`, `sorted()`/`.sort(key=...)`, try/except, and the `json`, `re`, `math` modules.
Not supported: imports (other than `json`), class definitions, generators/yield, match statements, decorators, `with` statements. Not supported: most imports (only `json`, `re`, `math` are available), class definitions, generators/yield, match statements, decorators, `with` statements.
For pattern matching or text extraction, use the `regex_*` functions, string methods (`str.split`, `str.find`, `str.startswith`, `in` operator), or the `llm()` function. For pattern matching or text extraction, use `import re`, string methods (`str.split`, `str.find`, `str.startswith`, `in` operator), or the `llm()` function.
## Strategy Guide ## Strategy Guide
@ -1690,10 +1626,11 @@ interactions:
### Extracting data with regex ### Extracting data with regex
```python ```python
import re
numbers = [] numbers = []
results = await search("financial data", limit=20) results = await search("financial data", limit=20)
for r in results: for r in results:
amounts = await regex_findall(r'\$([\d,]+)', r['content']) amounts = re.findall(r'\$([\d,]+)', r['content'])
for a in amounts: for a in amounts:
numbers.append(int(a.replace(',', ''))) numbers.append(int(a.replace(',', '')))
if numbers: if numbers:
@ -1733,81 +1670,81 @@ interactions:
- content: What is the total revenue across all quarterly reports? - content: What is the total revenue across all quarterly reports?
role: user role: user
- content: null - content: null
reasoning: Need revenue from quarterly reports. Search for "quarterly report revenue". reasoning: Need to search for quarterly reports revenue.
role: assistant role: assistant
tool_calls: tool_calls:
- function: - function:
arguments: '{"code":"results = await search(\"quarterly report revenue\", limit=20)\nprint(len(results))\nfor arguments: '{"code":"import re\n# search for revenue in quarterly reports\nresults = await search(\"quarterly
r in results[:5]:\n print(r[''document_title''], r[''score''], r[''content''][:200])"}' report revenue\", limit=20)\nprint(len(results))\nfor r in results[:5]:\n print(r[''document_title''], r[''score''])\n"}'
name: execute_code name: execute_code
id: call_no1egdsi id: call_exbbulxp
type: function type: function
- content: '{"code":"results = await search(\"quarterly report revenue\", limit=20)\nprint(len(results))\nfor r in results[:5]:\n print(r[''document_title''], - content: '{"code":"import re\n# search for revenue in quarterly reports\nresults = await search(\"quarterly report
r[''score''], r[''content''][:200])","stdout":"3\nQ1 Report 0.03226645663380623 Sales report Q1: Revenue was $100,000.\nQ2 revenue\", limit=20)\nprint(len(results))\nfor r in results[:5]:\n print(r[''document_title''], r[''score''])\n","stdout":"3\nQ1
Report 0.03226645663380623 Sales report Q2: Revenue was $150,000.\nQ3 Report 0.032258063554763794 Sales report Q3: Report 0.03226645663380623\nQ2 Report 0.03226645663380623\nQ3 Report 0.032258063554763794\n","stderr":"","success":true}'
Revenue was $200,000.\n","stderr":"","success":true}'
role: tool role: tool
tool_call_id: call_no1egdsi tool_call_id: call_exbbulxp
- content: null - content: null
reasoning: Three reports with revenue numbers. Sum = 450k. Need citation chunks. Retrieve chunks. reasoning: We need revenue numbers. Let's fetch chunks.
role: assistant role: assistant
tool_calls: tool_calls:
- function: - function:
arguments: '{"code":"chunks = []\nfor r in results:\n chunk = await get_chunk(r[''chunk_id''])\n chunks.append(chunk)\n print(chunk[''document_title''], arguments: '{"code":"# get chunks for each result\nchunks = []\nfor r in results:\n chunk = await get_chunk(r[''chunk_id''])\n chunks.append(chunk)\n print(chunk[''document_title''],
chunk[''content''].strip())"}' chunk[''content''][:200])\n"}'
name: execute_code name: execute_code
id: call_sg5vtxpb id: call_2hd3mgon
type: function type: function
- content: '{"code":"chunks = []\nfor r in results:\n chunk = await get_chunk(r[''chunk_id''])\n chunks.append(chunk)\n print(chunk[''document_title''], - content: '{"code":"# get chunks for each result\nchunks = []\nfor r in results:\n chunk = await get_chunk(r[''chunk_id''])\n chunks.append(chunk)\n print(chunk[''document_title''],
chunk[''content''].strip())","stdout":"","stderr":"NameError: name ''results'' is not defined","success":false}' chunk[''content''][:200])\n","stdout":"","stderr":"NameError: name ''results'' is not defined","success":false}'
role: tool role: tool
tool_call_id: call_sg5vtxpb tool_call_id: call_2hd3mgon
- content: null - content: null
reasoning: Need to keep results variable. Use same scope. Let's re-run with storing results. reasoning: Need to re-run search inside same code.
role: assistant role: assistant
tool_calls: tool_calls:
- function: - function:
arguments: '{"code":"results = await search(\"quarterly report revenue\", limit=20)\nchunks = []\nfor r in results:\n c arguments: '{"code":"results = await search(\"quarterly report revenue\", limit=20)\nchunks = []\nfor r in results:\n chunk
= await get_chunk(r[''chunk_id''])\n chunks.append(c)\n print(c[''document_title''], c[''content''].strip())"}' = await get_chunk(r[''chunk_id''])\n chunks.append(chunk)\n print(chunk[''document_title''], chunk[''content''][:200])\n"}'
name: execute_code name: execute_code
id: call_h6pfbenb id: call_10n40kz9
type: function type: function
- content: '{"code":"results = await search(\"quarterly report revenue\", limit=20)\nchunks = []\nfor r in results:\n c - content: '{"code":"results = await search(\"quarterly report revenue\", limit=20)\nchunks = []\nfor r in results:\n chunk
= await get_chunk(r[''chunk_id''])\n chunks.append(c)\n print(c[''document_title''], c[''content''].strip())","stdout":"Q1 = await get_chunk(r[''chunk_id''])\n chunks.append(chunk)\n print(chunk[''document_title''], chunk[''content''][:200])\n","stdout":"Q1
Report Sales report Q1: Revenue was $100,000.\nQ2 Report Sales report Q2: Revenue was $150,000.\nQ3 Report Sales Report Sales report Q1: Revenue was $100,000.\nQ2 Report Sales report Q2: Revenue was $150,000.\nQ3 Report Sales
report Q3: Revenue was $200,000.\n","stderr":"","success":true}' report Q3: Revenue was $200,000.\n","stderr":"","success":true}'
role: tool role: tool
tool_call_id: call_h6pfbenb tool_call_id: call_10n40kz9
- content: Now compute sum.
role: assistant
tool_calls:
- function:
arguments: '{"code":"total = 0\nfor c in chunks:\n nums = await regex_findall(r''\\$([\\d,]+)'', c[''content''])\n for
n in nums:\n total += int(n.replace('','', ''''))\nprint(total)"}'
name: execute_code
id: call_rlqh271l
type: function
- content: '{"code":"total = 0\nfor c in chunks:\n nums = await regex_findall(r''\\$([\\d,]+)'', c[''content''])\n for
n in nums:\n total += int(n.replace('','', ''''))\nprint(total)","stdout":"","stderr":"NameError: name ''chunks''
is not defined","success":false}'
role: tool
tool_call_id: call_rlqh271l
- content: null - content: null
reasoning: Variable scope lost. Let's combine. reasoning: Sum revenues.
role: assistant role: assistant
tool_calls: tool_calls:
- function: - function:
arguments: '{"code":"results = await search(\"quarterly report revenue\", limit=20)\nchunks = []\nfor r in results:\n c arguments: '{"code":"total=0\nfor c in chunks:\n import re\n m=re.search(r''\\$([\\d,]+)'', c[''content''])\n if
= await get_chunk(r[''chunk_id''])\n chunks.append(c)\n\ntotal = 0\nfor c in chunks:\n nums = await regex_findall(r''\\$([\\d,]+)'', m:\n val=int(m.group(1).replace('','',''''))\n total+=val\nprint(total)\n"}'
c[''content''])\n for n in nums:\n total += int(n.replace('','', ''''))\nprint(total)"}'
name: execute_code name: execute_code
id: call_kbsx3dxm id: call_51jmnwfv
type: function type: function
- content: '{"code":"results = await search(\"quarterly report revenue\", limit=20)\nchunks = []\nfor r in results:\n c - content: '{"code":"total=0\nfor c in chunks:\n import re\n m=re.search(r''\\$([\\d,]+)'', c[''content''])\n if
= await get_chunk(r[''chunk_id''])\n chunks.append(c)\n\ntotal = 0\nfor c in chunks:\n nums = await regex_findall(r''\\$([\\d,]+)'', m:\n val=int(m.group(1).replace('','',''''))\n total+=val\nprint(total)\n","stdout":"","stderr":"NameError:
c[''content''])\n for n in nums:\n total += int(n.replace('','', ''''))\nprint(total)","stdout":"450000\n","stderr":"","success":true}' name ''chunks'' is not defined","success":false}'
role: tool role: tool
tool_call_id: call_kbsx3dxm tool_call_id: call_51jmnwfv
- content: null
reasoning: Need to keep chunks variable. Let's combine.
role: assistant
tool_calls:
- function:
arguments: '{"code":"results = await search(\"quarterly report revenue\", limit=20)\nchunks = []\nfor r in results:\n chunk
= await get_chunk(r[''chunk_id''])\n chunks.append(chunk)\n\ntotal=0\nimport re\nfor c in chunks:\n m=re.search(r''\\$([\\d,]+)'',
c[''content''])\n if m:\n val=int(m.group(1).replace('','',''''))\n total+=val\nprint(total)\n"}'
name: execute_code
id: call_axsiusi8
type: function
- content: '{"code":"results = await search(\"quarterly report revenue\", limit=20)\nchunks = []\nfor r in results:\n chunk
= await get_chunk(r[''chunk_id''])\n chunks.append(chunk)\n\ntotal=0\nimport re\nfor c in chunks:\n m=re.search(r''\\$([\\d,]+)'',
c[''content''])\n if m:\n val=int(m.group(1).replace('','',''''))\n total+=val\nprint(total)\n","stdout":"450000\n","stderr":"","success":true}'
role: tool
tool_call_id: call_axsiusi8
model: gpt-oss model: gpt-oss
reasoning_effort: low reasoning_effort: low
response_format: response_format:
@ -1830,6 +1767,7 @@ interactions:
strict: true strict: true
type: json_schema type: json_schema
stream: false stream: false
temperature: 0.0
tool_choice: auto tool_choice: auto
tools: tools:
- function: - function:
@ -1859,7 +1797,7 @@ interactions:
response: response:
headers: headers:
content-length: content-length:
- '880' - '980'
content-type: content-type:
- application/json - application/json
parsed_body: parsed_body:
@ -1867,21 +1805,22 @@ interactions:
- finish_reason: stop - finish_reason: stop
index: 0 index: 0
message: message:
content: '{"answer":"The total revenue across all quarterly reports is $450,000. This figure comes from three reports:\n- content: '{"answer":"The total revenue reported across all quarterly reports is $450,000. This figure is the sum
Q1 Report: $100,000\n- Q2 Report: $150,000\n- Q3 Report: $200,000\nSumming these gives the stated total.\n", "program":"results of $100,000 from Q1, $150,000 from Q2, and $200,000 from Q3, as extracted from the respective quarterly report
= await search(\"quarterly report revenue\", limit=20)\nchunks = []\nfor r in results:\n c = await get_chunk(r[''chunk_id''])\n chunks.append(c)\n\ntotal documents.","program":"import re\n# Search for quarterly report revenue chunks\nresults = await search(\"quarterly
= 0\nfor c in chunks:\n nums = await regex_findall(r''\\$([\\d,]+)'', c[''content''])\n for n in nums:\n total report revenue\", limit=20)\nchunks = []\nfor r in results:\n chunk = await get_chunk(r[''chunk_id''])\n chunks.append(chunk)\n#
+= int(n.replace('','', ''''))\nprint(total)"}' Sum revenue amounts\ntotal = 0\nfor c in chunks:\n m = re.search(r\"\\$([\\d,]+)\", c[''content''])\n if
m:\n val = int(m.group(1).replace('','', ''''))\n total += val\nprint(total)"}'
role: assistant role: assistant
created: 1772626970 created: 1773329189
id: chatcmpl-772 id: chatcmpl-169
model: gpt-oss model: gpt-oss
object: chat.completion object: chat.completion
system_fingerprint: fp_ollama system_fingerprint: fp_ollama
usage: usage:
completion_tokens: 178 completion_tokens: 186
prompt_tokens: 2744 prompt_tokens: 2655
total_tokens: 2922 total_tokens: 2841
status: status:
code: 200 code: 200
message: OK message: OK

View file

@ -128,7 +128,7 @@ interactions:
connection: connection:
- keep-alive - keep-alive
content-length: content-length:
- '7721' - '7258'
content-type: content-type:
- application/json - application/json
host: host:
@ -173,18 +173,6 @@ interactions:
- `pictures`: list of figures/images with metadata - `pictures`: list of figures/images with metadata
- `pages`: page dimensions and metadata - `pages`: page dimensions and metadata
### await regex_findall(pattern, text) -> list[str]
Find all non-overlapping matches of a regular expression pattern in text.
### await regex_sub(pattern, repl, text) -> str
Replace all occurrences of a regular expression pattern with a replacement string.
### await regex_search(pattern, text) -> dict | None
Search for the first match of a pattern. Returns a dict with keys: group, groups, start, end — or None if no match.
### await regex_split(pattern, text) -> list[str]
Split text by a regular expression pattern.
### await llm(prompt) -> str ### await llm(prompt) -> str
Call an LLM directly with the given prompt. Returns the response as a string. Call an LLM directly with the given prompt. Returns the response as a string.
Use this for classification, summarization, extraction, or any task where you Use this for classification, summarization, extraction, or any task where you
@ -202,11 +190,11 @@ interactions:
## Available Python Features ## Available Python Features
The interpreter supports: variables, arithmetic, strings, f-strings, lists, dicts, tuples, sets, loops, conditionals, comprehensions, functions, async/await, `map()`, `sorted()`/`.sort(key=...)`, try/except, and the `json` module. The interpreter supports: variables, arithmetic, strings, f-strings, lists, dicts, tuples, sets, loops, conditionals, comprehensions, functions, async/await, `map()`, `filter()`, `getattr()`, `sorted()`/`.sort(key=...)`, try/except, and the `json`, `re`, `math` modules.
Not supported: imports (other than `json`), class definitions, generators/yield, match statements, decorators, `with` statements. Not supported: most imports (only `json`, `re`, `math` are available), class definitions, generators/yield, match statements, decorators, `with` statements.
For pattern matching or text extraction, use the `regex_*` functions, string methods (`str.split`, `str.find`, `str.startswith`, `in` operator), or the `llm()` function. For pattern matching or text extraction, use `import re`, string methods (`str.split`, `str.find`, `str.startswith`, `in` operator), or the `llm()` function.
## Strategy Guide ## Strategy Guide
@ -232,10 +220,11 @@ interactions:
### Extracting data with regex ### Extracting data with regex
```python ```python
import re
numbers = [] numbers = []
results = await search("financial data", limit=20) results = await search("financial data", limit=20)
for r in results: for r in results:
amounts = await regex_findall(r'\$([\d,]+)', r['content']) amounts = re.findall(r'\$([\d,]+)', r['content'])
for a in amounts: for a in amounts:
numbers.append(int(a.replace(',', ''))) numbers.append(int(a.replace(',', '')))
if numbers: if numbers:
@ -296,6 +285,7 @@ interactions:
strict: true strict: true
type: json_schema type: json_schema
stream: false stream: false
temperature: 0.0
tool_choice: auto tool_choice: auto
tools: tools:
- function: - function:
@ -325,7 +315,7 @@ interactions:
response: response:
headers: headers:
content-length: content-length:
- '522' - '525'
content-type: content-type:
- application/json - application/json
parsed_body: parsed_body:
@ -338,20 +328,20 @@ interactions:
role: assistant role: assistant
tool_calls: tool_calls:
- function: - function:
arguments: '{"code":"docs = await list_documents(limit=1000)\nprint(len(docs))"}' arguments: '{"code":"docs = await list_documents(limit=1000)\nprint(len(docs))\n"}'
name: execute_code name: execute_code
id: call_cthflnpr id: call_04viywlj
index: 0 index: 0
type: function type: function
created: 1772626945 created: 1773329125
id: chatcmpl-979 id: chatcmpl-653
model: gpt-oss model: gpt-oss
object: chat.completion object: chat.completion
system_fingerprint: fp_ollama system_fingerprint: fp_ollama
usage: usage:
completion_tokens: 45 completion_tokens: 47
prompt_tokens: 1686 prompt_tokens: 1592
total_tokens: 1731 total_tokens: 1639
status: status:
code: 200 code: 200
message: OK message: OK
@ -364,7 +354,7 @@ interactions:
connection: connection:
- keep-alive - keep-alive
content-length: content-length:
- '8163' - '7706'
content-type: content-type:
- application/json - application/json
host: host:
@ -409,18 +399,6 @@ interactions:
- `pictures`: list of figures/images with metadata - `pictures`: list of figures/images with metadata
- `pages`: page dimensions and metadata - `pages`: page dimensions and metadata
### await regex_findall(pattern, text) -> list[str]
Find all non-overlapping matches of a regular expression pattern in text.
### await regex_sub(pattern, repl, text) -> str
Replace all occurrences of a regular expression pattern with a replacement string.
### await regex_search(pattern, text) -> dict | None
Search for the first match of a pattern. Returns a dict with keys: group, groups, start, end — or None if no match.
### await regex_split(pattern, text) -> list[str]
Split text by a regular expression pattern.
### await llm(prompt) -> str ### await llm(prompt) -> str
Call an LLM directly with the given prompt. Returns the response as a string. Call an LLM directly with the given prompt. Returns the response as a string.
Use this for classification, summarization, extraction, or any task where you Use this for classification, summarization, extraction, or any task where you
@ -438,11 +416,11 @@ interactions:
## Available Python Features ## Available Python Features
The interpreter supports: variables, arithmetic, strings, f-strings, lists, dicts, tuples, sets, loops, conditionals, comprehensions, functions, async/await, `map()`, `sorted()`/`.sort(key=...)`, try/except, and the `json` module. The interpreter supports: variables, arithmetic, strings, f-strings, lists, dicts, tuples, sets, loops, conditionals, comprehensions, functions, async/await, `map()`, `filter()`, `getattr()`, `sorted()`/`.sort(key=...)`, try/except, and the `json`, `re`, `math` modules.
Not supported: imports (other than `json`), class definitions, generators/yield, match statements, decorators, `with` statements. Not supported: most imports (only `json`, `re`, `math` are available), class definitions, generators/yield, match statements, decorators, `with` statements.
For pattern matching or text extraction, use the `regex_*` functions, string methods (`str.split`, `str.find`, `str.startswith`, `in` operator), or the `llm()` function. For pattern matching or text extraction, use `import re`, string methods (`str.split`, `str.find`, `str.startswith`, `in` operator), or the `llm()` function.
## Strategy Guide ## Strategy Guide
@ -468,10 +446,11 @@ interactions:
### Extracting data with regex ### Extracting data with regex
```python ```python
import re
numbers = [] numbers = []
results = await search("financial data", limit=20) results = await search("financial data", limit=20)
for r in results: for r in results:
amounts = await regex_findall(r'\$([\d,]+)', r['content']) amounts = re.findall(r'\$([\d,]+)', r['content'])
for a in amounts: for a in amounts:
numbers.append(int(a.replace(',', ''))) numbers.append(int(a.replace(',', '')))
if numbers: if numbers:
@ -515,13 +494,13 @@ interactions:
role: assistant role: assistant
tool_calls: tool_calls:
- function: - function:
arguments: '{"code":"docs = await list_documents(limit=1000)\nprint(len(docs))"}' arguments: '{"code":"docs = await list_documents(limit=1000)\nprint(len(docs))\n"}'
name: execute_code name: execute_code
id: call_cthflnpr id: call_04viywlj
type: function type: function
- content: '{"code":"docs = await list_documents(limit=1000)\nprint(len(docs))","stdout":"3\n","stderr":"","success":true}' - content: '{"code":"docs = await list_documents(limit=1000)\nprint(len(docs))\n","stdout":"3\n","stderr":"","success":true}'
role: tool role: tool
tool_call_id: call_cthflnpr tool_call_id: call_04viywlj
model: gpt-oss model: gpt-oss
reasoning_effort: low reasoning_effort: low
response_format: response_format:
@ -544,6 +523,7 @@ interactions:
strict: true strict: true
type: json_schema type: json_schema
stream: false stream: false
temperature: 0.0
tool_choice: auto tool_choice: auto
tools: tools:
- function: - function:
@ -573,7 +553,7 @@ interactions:
response: response:
headers: headers:
content-length: content-length:
- '459' - '416'
content-type: content-type:
- application/json - application/json
parsed_body: parsed_body:
@ -581,18 +561,17 @@ interactions:
- finish_reason: stop - finish_reason: stop
index: 0 index: 0
message: message:
content: '{"answer":"There are 3 documents in the database.","program":"docs = await list_documents(limit=1000)\nprint(f''There content: '{"answer":"There are 3 documents in the database.","program":"docs = await list_documents(limit=1000)\nprint(len(docs))"}'
are {len(docs)} documents in the database.'')" }'
role: assistant role: assistant
created: 1772626947 created: 1773329134
id: chatcmpl-490 id: chatcmpl-151
model: gpt-oss model: gpt-oss
object: chat.completion object: chat.completion
system_fingerprint: fp_ollama system_fingerprint: fp_ollama
usage: usage:
completion_tokens: 49 completion_tokens: 38
prompt_tokens: 1773 prompt_tokens: 1683
total_tokens: 1822 total_tokens: 1721
status: status:
code: 200 code: 200
message: OK message: OK

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -128,7 +128,7 @@ interactions:
connection: connection:
- keep-alive - keep-alive
content-length: content-length:
- '7715' - '7252'
content-type: content-type:
- application/json - application/json
host: host:
@ -173,18 +173,6 @@ interactions:
- `pictures`: list of figures/images with metadata - `pictures`: list of figures/images with metadata
- `pages`: page dimensions and metadata - `pages`: page dimensions and metadata
### await regex_findall(pattern, text) -> list[str]
Find all non-overlapping matches of a regular expression pattern in text.
### await regex_sub(pattern, repl, text) -> str
Replace all occurrences of a regular expression pattern with a replacement string.
### await regex_search(pattern, text) -> dict | None
Search for the first match of a pattern. Returns a dict with keys: group, groups, start, end — or None if no match.
### await regex_split(pattern, text) -> list[str]
Split text by a regular expression pattern.
### await llm(prompt) -> str ### await llm(prompt) -> str
Call an LLM directly with the given prompt. Returns the response as a string. Call an LLM directly with the given prompt. Returns the response as a string.
Use this for classification, summarization, extraction, or any task where you Use this for classification, summarization, extraction, or any task where you
@ -202,11 +190,11 @@ interactions:
## Available Python Features ## Available Python Features
The interpreter supports: variables, arithmetic, strings, f-strings, lists, dicts, tuples, sets, loops, conditionals, comprehensions, functions, async/await, `map()`, `sorted()`/`.sort(key=...)`, try/except, and the `json` module. The interpreter supports: variables, arithmetic, strings, f-strings, lists, dicts, tuples, sets, loops, conditionals, comprehensions, functions, async/await, `map()`, `filter()`, `getattr()`, `sorted()`/`.sort(key=...)`, try/except, and the `json`, `re`, `math` modules.
Not supported: imports (other than `json`), class definitions, generators/yield, match statements, decorators, `with` statements. Not supported: most imports (only `json`, `re`, `math` are available), class definitions, generators/yield, match statements, decorators, `with` statements.
For pattern matching or text extraction, use the `regex_*` functions, string methods (`str.split`, `str.find`, `str.startswith`, `in` operator), or the `llm()` function. For pattern matching or text extraction, use `import re`, string methods (`str.split`, `str.find`, `str.startswith`, `in` operator), or the `llm()` function.
## Strategy Guide ## Strategy Guide
@ -232,10 +220,11 @@ interactions:
### Extracting data with regex ### Extracting data with regex
```python ```python
import re
numbers = [] numbers = []
results = await search("financial data", limit=20) results = await search("financial data", limit=20)
for r in results: for r in results:
amounts = await regex_findall(r'\$([\d,]+)', r['content']) amounts = re.findall(r'\$([\d,]+)', r['content'])
for a in amounts: for a in amounts:
numbers.append(int(a.replace(',', ''))) numbers.append(int(a.replace(',', '')))
if numbers: if numbers:
@ -296,6 +285,7 @@ interactions:
strict: true strict: true
type: json_schema type: json_schema
stream: false stream: false
temperature: 0.0
tool_choice: auto tool_choice: auto
tools: tools:
- function: - function:
@ -325,7 +315,7 @@ interactions:
response: response:
headers: headers:
content-length: content-length:
- '522' - '576'
content-type: content-type:
- application/json - application/json
parsed_body: parsed_body:
@ -334,24 +324,25 @@ interactions:
index: 0 index: 0
message: message:
content: '' content: ''
reasoning: Need to list documents. reasoning: We need to list documents.
role: assistant role: assistant
tool_calls: tool_calls:
- function: - function:
arguments: '{"code":"docs = await list_documents(limit=1000)\nprint(len(docs))\n"}' arguments: '{"code":"docs = await list_documents(limit=1000)\nprint(len(docs))\nfor d in docs:\n print(d[''id''],
d.get(''title''))"}'
name: execute_code name: execute_code
id: call_jsd3hga7 id: call_nap68rkx
index: 0 index: 0
type: function type: function
created: 1772626976 created: 1773329124
id: chatcmpl-987 id: chatcmpl-461
model: gpt-oss model: gpt-oss
object: chat.completion object: chat.completion
system_fingerprint: fp_ollama system_fingerprint: fp_ollama
usage: usage:
completion_tokens: 46 completion_tokens: 64
prompt_tokens: 1684 prompt_tokens: 1590
total_tokens: 1730 total_tokens: 1654
status: status:
code: 200 code: 200
message: OK message: OK
@ -364,7 +355,7 @@ interactions:
connection: connection:
- keep-alive - keep-alive
content-length: content-length:
- '8160' - '7846'
content-type: content-type:
- application/json - application/json
host: host:
@ -409,18 +400,6 @@ interactions:
- `pictures`: list of figures/images with metadata - `pictures`: list of figures/images with metadata
- `pages`: page dimensions and metadata - `pages`: page dimensions and metadata
### await regex_findall(pattern, text) -> list[str]
Find all non-overlapping matches of a regular expression pattern in text.
### await regex_sub(pattern, repl, text) -> str
Replace all occurrences of a regular expression pattern with a replacement string.
### await regex_search(pattern, text) -> dict | None
Search for the first match of a pattern. Returns a dict with keys: group, groups, start, end — or None if no match.
### await regex_split(pattern, text) -> list[str]
Split text by a regular expression pattern.
### await llm(prompt) -> str ### await llm(prompt) -> str
Call an LLM directly with the given prompt. Returns the response as a string. Call an LLM directly with the given prompt. Returns the response as a string.
Use this for classification, summarization, extraction, or any task where you Use this for classification, summarization, extraction, or any task where you
@ -438,11 +417,11 @@ interactions:
## Available Python Features ## Available Python Features
The interpreter supports: variables, arithmetic, strings, f-strings, lists, dicts, tuples, sets, loops, conditionals, comprehensions, functions, async/await, `map()`, `sorted()`/`.sort(key=...)`, try/except, and the `json` module. The interpreter supports: variables, arithmetic, strings, f-strings, lists, dicts, tuples, sets, loops, conditionals, comprehensions, functions, async/await, `map()`, `filter()`, `getattr()`, `sorted()`/`.sort(key=...)`, try/except, and the `json`, `re`, `math` modules.
Not supported: imports (other than `json`), class definitions, generators/yield, match statements, decorators, `with` statements. Not supported: most imports (only `json`, `re`, `math` are available), class definitions, generators/yield, match statements, decorators, `with` statements.
For pattern matching or text extraction, use the `regex_*` functions, string methods (`str.split`, `str.find`, `str.startswith`, `in` operator), or the `llm()` function. For pattern matching or text extraction, use `import re`, string methods (`str.split`, `str.find`, `str.startswith`, `in` operator), or the `llm()` function.
## Strategy Guide ## Strategy Guide
@ -468,10 +447,11 @@ interactions:
### Extracting data with regex ### Extracting data with regex
```python ```python
import re
numbers = [] numbers = []
results = await search("financial data", limit=20) results = await search("financial data", limit=20)
for r in results: for r in results:
amounts = await regex_findall(r'\$([\d,]+)', r['content']) amounts = re.findall(r'\$([\d,]+)', r['content'])
for a in amounts: for a in amounts:
numbers.append(int(a.replace(',', ''))) numbers.append(int(a.replace(',', '')))
if numbers: if numbers:
@ -511,17 +491,19 @@ interactions:
- content: How many documents are available? - content: How many documents are available?
role: user role: user
- content: null - content: null
reasoning: Need to list documents. reasoning: We need to list documents.
role: assistant role: assistant
tool_calls: tool_calls:
- function: - function:
arguments: '{"code":"docs = await list_documents(limit=1000)\nprint(len(docs))\n"}' arguments: '{"code":"docs = await list_documents(limit=1000)\nprint(len(docs))\nfor d in docs:\n print(d[''id''],
d.get(''title''))"}'
name: execute_code name: execute_code
id: call_jsd3hga7 id: call_nap68rkx
type: function type: function
- content: '{"code":"docs = await list_documents(limit=1000)\nprint(len(docs))\n","stdout":"1\n","stderr":"","success":true}' - content: '{"code":"docs = await list_documents(limit=1000)\nprint(len(docs))\nfor d in docs:\n print(d[''id''],
d.get(''title''))","stdout":"1\n7b1434a1-bbe5-4ae1-bb3e-5400eed94d72 Cats\n","stderr":"","success":true}'
role: tool role: tool
tool_call_id: call_jsd3hga7 tool_call_id: call_nap68rkx
model: gpt-oss model: gpt-oss
reasoning_effort: low reasoning_effort: low
response_format: response_format:
@ -544,6 +526,7 @@ interactions:
strict: true strict: true
type: json_schema type: json_schema
stream: false stream: false
temperature: 0.0
tool_choice: auto tool_choice: auto
tools: tools:
- function: - function:
@ -573,7 +556,7 @@ interactions:
response: response:
headers: headers:
content-length: content-length:
- '430' - '484'
content-type: content-type:
- application/json - application/json
parsed_body: parsed_body:
@ -581,17 +564,18 @@ interactions:
- finish_reason: stop - finish_reason: stop
index: 0 index: 0
message: message:
content: '{"answer":"There is 1 document available in the knowledge base.","program":"docs = await list_documents(limit=1000)\nprint(len(docs))"}' content: '{"answer":"There is 1 document available in the knowledge base.","program":"docs = await list_documents(limit=1000)\nprint(len(docs))\nfor
d in docs:\n print(d[''id''], d.get(''title''))"}'
role: assistant role: assistant
created: 1772626977 created: 1773329133
id: chatcmpl-959 id: chatcmpl-985
model: gpt-oss model: gpt-oss
object: chat.completion object: chat.completion
system_fingerprint: fp_ollama system_fingerprint: fp_ollama
usage: usage:
completion_tokens: 37 completion_tokens: 59
prompt_tokens: 1774 prompt_tokens: 1741
total_tokens: 1811 total_tokens: 1800
status: status:
code: 200 code: 200
message: OK message: OK

78
uv.lock
View file

@ -1529,7 +1529,7 @@ requires-dist = [
{ name = "pydantic-ai-slim", extras = ["openai", "fastmcp", "logfire", "ag-ui"], specifier = ">=1.66.0" }, { name = "pydantic-ai-slim", extras = ["openai", "fastmcp", "logfire", "ag-ui"], specifier = ">=1.66.0" },
{ name = "pydantic-ai-slim", extras = ["vertexai"], marker = "extra == 'vertexai'" }, { name = "pydantic-ai-slim", extras = ["vertexai"], marker = "extra == 'vertexai'" },
{ name = "pydantic-ai-slim", extras = ["voyageai"], marker = "extra == 'voyageai'" }, { name = "pydantic-ai-slim", extras = ["voyageai"], marker = "extra == 'voyageai'" },
{ name = "pydantic-monty", specifier = ">=0.0.7" }, { name = "pydantic-monty", specifier = ">=0.0.8" },
{ name = "python-dotenv", specifier = ">=1.2.2" }, { name = "python-dotenv", specifier = ">=1.2.2" },
{ name = "pyyaml", specifier = ">=6.0.3" }, { name = "pyyaml", specifier = ">=6.0.3" },
{ name = "rich", specifier = ">=14.3.3" }, { name = "rich", specifier = ">=14.3.3" },
@ -3790,46 +3790,46 @@ wheels = [
[[package]] [[package]]
name = "pydantic-monty" name = "pydantic-monty"
version = "0.0.7" version = "0.0.8"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/f5/e3/0d8b2b025628477c839f894e632f5197872b19df0a86b2ec30fac3b5960a/pydantic_monty-0.0.7.tar.gz", hash = "sha256:2189ea1d7aadab2f95374733d692f51d1206379a4fc7ce18ab46895512e88f92", size = 684705, upload-time = "2026-02-19T14:12:47.235Z" } sdist = { url = "https://files.pythonhosted.org/packages/47/bf/e9794b562c207406d8fda0cf4fea810943a5e8a85fe69e5505046179df16/pydantic_monty-0.0.8.tar.gz", hash = "sha256:8135e781a184f971825c1d2eb6d621598103e900f6e0d34291ff0bf35df6142f", size = 802646, upload-time = "2026-03-10T14:46:51.353Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/ce/7e/ca0884108c3237bb15bb2a1b3f24ddd957b9c750f1ed3211801497941999/pydantic_monty-0.0.7-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f35e18f284524d26d5f27084e2b93eb40139055bbf0cab6221a043eb5e9ce2dc", size = 6264252, upload-time = "2026-02-19T14:13:59.317Z" }, { url = "https://files.pythonhosted.org/packages/f4/4f/7d7c7531be850469bccfbbf3cfede9e95d92b1d8e7b245d9dc77a599d6e4/pydantic_monty-0.0.8-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:025b380c0ed728bdf88e3ed60d5977498d4bb9da61cd81d9cabdaecce16f5755", size = 6699454, upload-time = "2026-03-10T14:46:39.422Z" },
{ url = "https://files.pythonhosted.org/packages/5a/5b/31f70c7792a857bacbdce90b8aae4629c31a9fec35f0116d91a2fb53241b/pydantic_monty-0.0.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8e5d8924c65bb1ced60785a156e28c73f7f79f164b4f090dc26312c3917ffff7", size = 6133285, upload-time = "2026-02-19T14:14:46.577Z" }, { url = "https://files.pythonhosted.org/packages/c0/35/074daa5fd92e4a5c1e49c8fae06036e194139feef9a51b4db82d0fee7e54/pydantic_monty-0.0.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:76846d77ebda3414beb8c9e5da9eaef722e06606dc0307613186d888e775dc51", size = 6743273, upload-time = "2026-03-10T14:46:16.184Z" },
{ url = "https://files.pythonhosted.org/packages/42/56/c92216c0427e8a10a01fa98f29252f6fabd8ca80ca193e0fd30fe28e65c1/pydantic_monty-0.0.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6279a468469d5a3b80d94dd0ab6110cd291a1dfbb057fa7d6dbad1f499be855d", size = 6059856, upload-time = "2026-02-19T14:13:02.594Z" }, { url = "https://files.pythonhosted.org/packages/55/0d/e6cb1e9e1c2e51501d8f7848c18803780164948e338350ab94769690f207/pydantic_monty-0.0.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b58149d6a8998ffed80f626c10bf0de7e65964aae1dfad80db8ecb00968fb1a", size = 6503552, upload-time = "2026-03-10T14:45:26.083Z" },
{ url = "https://files.pythonhosted.org/packages/b5/a7/bc3e67b12d8a9da65f2677d9a48bc1e055a1d853d48572ba4845a64075cf/pydantic_monty-0.0.7-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cb5feb69a5902d059db5dab269f90423b85a22163668422be47ccac8d7f7c44a", size = 6313780, upload-time = "2026-02-19T14:13:46.45Z" }, { url = "https://files.pythonhosted.org/packages/5f/a9/286f7eb6c95d7877f6f8b9bcbe26e2d988fa142cd77509e48e67302478bf/pydantic_monty-0.0.8-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1b99bb030ff8e95b160c11702b9a6823705b7dcc1a49a2c1dccc43c2538bfe27", size = 6765377, upload-time = "2026-03-10T14:45:14.472Z" },
{ url = "https://files.pythonhosted.org/packages/c8/97/a9b856b17ee1e54892dafbb7ea29305520cae2dcd8aafe82a26a0edbc33c/pydantic_monty-0.0.7-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a2f1913e9729aa6711092ecbfce764df199a4787fe3e23a7ed74c78bf846579e", size = 6856827, upload-time = "2026-02-19T14:13:40.836Z" }, { url = "https://files.pythonhosted.org/packages/74/76/85268f6305bc5b153be7c0860e69ce3b9ba916daa4a419f53d8a777e9a39/pydantic_monty-0.0.8-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b05b17fc2b8875e0efea047416fc0cd28a8018c040b25387454996b98540ccfc", size = 7324571, upload-time = "2026-03-10T14:45:48.786Z" },
{ url = "https://files.pythonhosted.org/packages/98/57/2d8184b9f5a0b2b3bb47fdad7061c6a182699824efe6de9d8dd19ee68c0a/pydantic_monty-0.0.7-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ec528f9f4194e6298757ad99e25da47f06f49ae2bc176ee26f49da5eb1dd7849", size = 6870737, upload-time = "2026-02-19T14:13:53.602Z" }, { url = "https://files.pythonhosted.org/packages/11/6a/2855c6149f6ba3138c7bfb009c07d528e2df12802e3216928b1289bbf233/pydantic_monty-0.0.8-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97fa5deef4d8cdcf60a4d8a4e7a34099deae1ad4b33acc1c33ac2e1cc348a1c2", size = 7533828, upload-time = "2026-03-10T14:46:55.386Z" },
{ url = "https://files.pythonhosted.org/packages/6b/b3/fe3d3eff82b41e517739841a492d7a48ea2daf8e7b822299b848b5d4c0aa/pydantic_monty-0.0.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75405b9186a9acfa49cd66aa339b5a2450d733a2d59fae20cc8be45e45204d5f", size = 6611843, upload-time = "2026-02-19T14:13:49.957Z" }, { url = "https://files.pythonhosted.org/packages/31/63/44b5bb5798323f7f735f5855a0d3f478d6852d9d1774427d77e31b5dbffb/pydantic_monty-0.0.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1aabd56af5db51c4af512142fe7ffc866b6a20dcd039a4aad5245ef42768f21", size = 7271978, upload-time = "2026-03-10T14:45:33.903Z" },
{ url = "https://files.pythonhosted.org/packages/ff/d2/fdd8fe135ea14e30b40adadc896dda6c805596688998c9bcdfd8d85a16cf/pydantic_monty-0.0.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1917e42fce4733f92f5f6ad64ae4d0e87abbf9fb284ef52589ac3e292e928bfe", size = 6692856, upload-time = "2026-02-19T14:13:00.635Z" }, { url = "https://files.pythonhosted.org/packages/4b/68/ce82eb571e45afbe3c0b9544fe3ebf93f841ec895fea0d39c9604a0a421f/pydantic_monty-0.0.8-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9782e58da29176a3fb0ce8ec808571d0be99c1e2ad167637225246e594e85f13", size = 7187140, upload-time = "2026-03-10T14:46:41.784Z" },
{ url = "https://files.pythonhosted.org/packages/0d/a6/fdde6f8d76aa0cff4b53060b63d7f09dbb19da61a967cb4b3dfd972acf1c/pydantic_monty-0.0.7-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d72a5d4f3ee7f9d2630b0379e4cfb397e181eb0b16e8c49a03f80ba6471edb89", size = 6236587, upload-time = "2026-02-19T14:14:32.602Z" }, { url = "https://files.pythonhosted.org/packages/5b/45/778bc260195ddb892f284c3cb8ab8cbcb0542e6a18f11b7e50a592b507ba/pydantic_monty-0.0.8-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ff7fb7ff3f4e830ef9b28a76e634219195b552c0dfed3471fb4910708db56221", size = 6677996, upload-time = "2026-03-10T14:46:03.163Z" },
{ url = "https://files.pythonhosted.org/packages/1b/7e/0580bbc001a39252b2f7da4b7504ac10572e4ca0ec967aebc5a9d752b6f7/pydantic_monty-0.0.7-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:20028220981516912f130986354ef6c926b98778146ca349560cb852e44d9ca6", size = 6672260, upload-time = "2026-02-19T14:13:26.527Z" }, { url = "https://files.pythonhosted.org/packages/1e/02/8e8396b83d19ec70a09c24b0245177a595c2b7d6d092c6f6c7d3310b191c/pydantic_monty-0.0.8-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ce7222d923676900827e3951e65f854d65f50b65ed8c7a84011d3472773d51bf", size = 7136513, upload-time = "2026-03-10T14:45:52.179Z" },
{ url = "https://files.pythonhosted.org/packages/d8/53/578a7b781a5714db5c4b1989c6e876d30caa0adf8a5a4caad89abc306667/pydantic_monty-0.0.7-cp312-cp312-win32.whl", hash = "sha256:e28b1c3ed52892f8ac12ee0f2b535402dfe1cb1e5c18128f1cb69eb8b66c285a", size = 6131085, upload-time = "2026-02-19T14:14:13.296Z" }, { url = "https://files.pythonhosted.org/packages/fd/24/53d06af74b82043be9c4960c38bbc255eeb3de9f2a4d450f942912630bb3/pydantic_monty-0.0.8-cp312-cp312-win32.whl", hash = "sha256:4cb59e1e7b1a3d573247a871a87c88506ce9fb68bbd7648598e171cf2f04747e", size = 6582168, upload-time = "2026-03-10T14:45:58.197Z" },
{ url = "https://files.pythonhosted.org/packages/56/98/20bd45fcd472937b1b3438b7587e209e3cfd447c30d02f654b86b44adaad/pydantic_monty-0.0.7-cp312-cp312-win_amd64.whl", hash = "sha256:031dfab63ff9d7acdc641852e0d822603038cef1c27c5060900b9fd51cc853d0", size = 6664431, upload-time = "2026-02-19T14:13:29.968Z" }, { url = "https://files.pythonhosted.org/packages/25/0f/55a16faf379139263ad852421734cb096390777d299ef7f185ec10404656/pydantic_monty-0.0.8-cp312-cp312-win_amd64.whl", hash = "sha256:45bf11e3b795cc470a91cbd7cfeb9d96f7a60387e8da146a11bf952b4371aba7", size = 7335422, upload-time = "2026-03-10T14:45:28.301Z" },
{ url = "https://files.pythonhosted.org/packages/ec/fe/d8cb6c30d9d7bcc7d3c8d2c349a227e2a83cd1fbe7182f4941896eb35443/pydantic_monty-0.0.7-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:55d36818f8e35872ed35e395b41df8acc460bcdbbfd471fe0c39e293a1d50db5", size = 6262596, upload-time = "2026-02-19T14:14:15.2Z" }, { url = "https://files.pythonhosted.org/packages/27/46/3268001a639052515d5a55ea2f1e087ae1e5f7aa9d7bc62c4808d731fff1/pydantic_monty-0.0.8-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:f303f1d979213dcb365c69de3912daa70a32af019bb5ee86e086f584638974f2", size = 6698529, upload-time = "2026-03-10T14:45:39.712Z" },
{ url = "https://files.pythonhosted.org/packages/81/7a/f6b4881ca9779bd87eb8d8c0823133b56c232cf09d765c07a7f91d641490/pydantic_monty-0.0.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:acb437458d93d54a9658656545fb6c9b396dbe66f68633b3c57bfd2f4aa1d400", size = 6133793, upload-time = "2026-02-19T14:14:06.498Z" }, { url = "https://files.pythonhosted.org/packages/f4/22/28d6b7f8f7a1e0881c449310a6f2c8ee0cf85dc4434ae0f7e633dfcf5bcf/pydantic_monty-0.0.8-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b8cc698da6f7f11743df7c48b959eea000e8e30511c7e1318b67543e25985062", size = 6743849, upload-time = "2026-03-10T14:46:48.023Z" },
{ url = "https://files.pythonhosted.org/packages/39/b9/dfcffd95ff233b8c98db9254242d9c10190989762016d18509aa04d43b1b/pydantic_monty-0.0.7-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b196345ffa1997041cb870ea693148feafe270575e2c2963532eedde0e84dedf", size = 6059400, upload-time = "2026-02-19T14:13:38.953Z" }, { url = "https://files.pythonhosted.org/packages/7b/ab/e3dfe057af472e4065297d69aea0cf30616d01366a29e02d0a2739f22b93/pydantic_monty-0.0.8-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90f6da093164e99012b49b39ba1e64c166ccd126128d114f9e2c66df6fb695c4", size = 6503266, upload-time = "2026-03-10T14:46:19.594Z" },
{ url = "https://files.pythonhosted.org/packages/6b/2e/d6ecef842024267ddf4128613342b8985a7444e74f3a4a312713c913a91a/pydantic_monty-0.0.7-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d471e3cfe77d62edaf43b7f0962b95270ee4243abea12cb8e8cf1ad972dc3612", size = 6312625, upload-time = "2026-02-19T14:13:36.901Z" }, { url = "https://files.pythonhosted.org/packages/0a/82/d3e9aa9bd9ac69b3584216166a189e11370913ffcbd2a57a5cac6ce2d4ba/pydantic_monty-0.0.8-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f2432ef62140554f5970991b7df41e064824741a807515658f91283c75669086", size = 6765032, upload-time = "2026-03-10T14:45:20.571Z" },
{ url = "https://files.pythonhosted.org/packages/75/2e/e4a2a9fbc3640bcee15b80c2f8ba0f97bf989c58c01d6da187524f71d12b/pydantic_monty-0.0.7-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3a67771afd385579bf3f894ce933fb9e467fba9a632ccf27246e271d448f6f5f", size = 6859902, upload-time = "2026-02-19T14:14:26.67Z" }, { url = "https://files.pythonhosted.org/packages/f8/9d/7ab11be8eff998bf9283c7bf444254cff5212f87fe3f2a9a2f7436cce6d7/pydantic_monty-0.0.8-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99951afb4d722212c2ce85c303b5e87d50756adaff46817ad0e60e95eb1e5141", size = 7324673, upload-time = "2026-03-10T14:45:37.957Z" },
{ url = "https://files.pythonhosted.org/packages/d2/4a/7aaf5c793f52e3403892a2de1f5dd18ae38234d82111cc9b7d92443e5b0d/pydantic_monty-0.0.7-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf662e1bbee4ddd318d5b8bfa9233173045029be0f67f15f816955b246bb7ec0", size = 6870524, upload-time = "2026-02-19T14:13:28.208Z" }, { url = "https://files.pythonhosted.org/packages/39/a0/7f026ece228cc990e58aa27f2ce5af26d042baaa0186cb451f3e04ff0abe/pydantic_monty-0.0.8-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bdef70921b408378f9bc38bce4952d3c176b3f7833aa782068b310390901c516", size = 7533774, upload-time = "2026-03-10T14:46:24.265Z" },
{ url = "https://files.pythonhosted.org/packages/c3/a9/c16f078864a273460923f1371b769c2719e1ce1ad86bc9031e3ed7fb3eae/pydantic_monty-0.0.7-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0151ff59a8a0d9e29ddb448affa33943108121e6e324795646a2f5facaf1a5d8", size = 6611960, upload-time = "2026-02-19T14:14:38.812Z" }, { url = "https://files.pythonhosted.org/packages/07/e7/72f250ffd005520ad8cdffb387241a9dd92fc70bcbdd769720918bd34495/pydantic_monty-0.0.8-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00b5dee7bef619e7661f77bef765f483605bcd2a79c6b8bf5c910afa1c93fc40", size = 7272179, upload-time = "2026-03-10T14:45:08.085Z" },
{ url = "https://files.pythonhosted.org/packages/20/d3/b3ef3432558a8cc9551d8b80a028a0f51cd2a518275932e03359eac3dc39/pydantic_monty-0.0.7-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:45f17a65134d3a0031e1f54d143770699f6a0ce92a1e74f0ae4914e52370f058", size = 6691834, upload-time = "2026-02-19T14:13:34.661Z" }, { url = "https://files.pythonhosted.org/packages/b8/7c/97c87c2a315ba4376bfb83197586365003005e01d6547df7f6d77b80d13f/pydantic_monty-0.0.8-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5f4c6f6fb2ebae0bc80520af71e1057055413ca96fd33f13f3c612a085e50fb8", size = 7186684, upload-time = "2026-03-10T14:46:49.833Z" },
{ url = "https://files.pythonhosted.org/packages/ef/56/1ab5d1cbc0edfb522f0c28c9f5a7fc74eea6355234f73833087524d034bf/pydantic_monty-0.0.7-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:ede6e68cb8a1f7216e26b0b2fb6cd0eae7a92104be8a49d1042e9e428de9262b", size = 6235704, upload-time = "2026-02-19T14:13:48.276Z" }, { url = "https://files.pythonhosted.org/packages/09/42/2eea55906fee8bef7c1024bf2d35e2c301b15b562934731bdae25db448cb/pydantic_monty-0.0.8-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3ab3c558a648942d4d31e7f668d60d2a2e129751a3e8e9dc27b1e6d635e9e627", size = 6677272, upload-time = "2026-03-10T14:45:54.037Z" },
{ url = "https://files.pythonhosted.org/packages/c4/d1/cdebae67b0543f696ed7daff8587dc8a458e6552b52d5877cb8e55be74b4/pydantic_monty-0.0.7-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:4b2fd51eea05a0cc37bb91f326efdb1acbcd4b8262dac1c55aeb208e51254978", size = 6671530, upload-time = "2026-02-19T14:12:56.96Z" }, { url = "https://files.pythonhosted.org/packages/40/0a/066e53d4693b680e39080d3af4f234c1ff9976f7621b8a49dd2a41710431/pydantic_monty-0.0.8-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:782d686d217b537e6fa9047aa3444d67b3b7cc69bf6faf34078c992ceaeb1e9e", size = 7136493, upload-time = "2026-03-10T14:45:30.014Z" },
{ url = "https://files.pythonhosted.org/packages/9f/53/c0dacaec260b71050fd6b31d09570f9d74bbb2a2e9586032694e92b9fa59/pydantic_monty-0.0.7-cp313-cp313-win32.whl", hash = "sha256:40f2092970c5899ac2a2784d712a4c7e194b33cd0133315254e4baf141cd6c93", size = 6130341, upload-time = "2026-02-19T14:14:09.701Z" }, { url = "https://files.pythonhosted.org/packages/81/c1/46dc300f87314aef883a57ae5a35ba45a463c09f64d3d9c9f0b620672734/pydantic_monty-0.0.8-cp313-cp313-win32.whl", hash = "sha256:ef0db454757cb92974890b11c7b0969d8c0d95944c821f6fc6cd23846d1d2aa4", size = 6581014, upload-time = "2026-03-10T14:46:07.886Z" },
{ url = "https://files.pythonhosted.org/packages/3e/05/31490a7a899d8bbb2e513630ea6f591ceb8a111c91fe7573a96c9f6b6327/pydantic_monty-0.0.7-cp313-cp313-win_amd64.whl", hash = "sha256:42cee2646415bb9bd7da428d169783203618a418f960c6f75c7a74d6946d6b31", size = 6664341, upload-time = "2026-02-19T14:14:19.008Z" }, { url = "https://files.pythonhosted.org/packages/b0/2a/cf156df19a1612ca5ddcbd982645e54c5485e83215d9532cc9aff791f854/pydantic_monty-0.0.8-cp313-cp313-win_amd64.whl", hash = "sha256:dbf8c7cfaff2b345f8c1bfba98fdc282e790fef5c601f37c8d5355ccd45073de", size = 7335041, upload-time = "2026-03-10T14:46:21.371Z" },
{ url = "https://files.pythonhosted.org/packages/99/15/64aff358df0b822dd22f212fec501e3944edffe978a4ab05530ea641dc68/pydantic_monty-0.0.7-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:c97b2e1dcd0126417892595c1da724a8c4348f7dcec26ba774117bd51bde46f8", size = 6266090, upload-time = "2026-02-19T14:13:12.364Z" }, { url = "https://files.pythonhosted.org/packages/a5/69/5bedc7ad67fdd9e4f04007477f5c414b54c51d47c5dfdd7abad4c78663aa/pydantic_monty-0.0.8-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:47990770ed74af1e8e2160a7dd925aa1e4fd1bf4ae9658ffd1cdc32eb5c8c6e8", size = 6700454, upload-time = "2026-03-10T14:45:56.247Z" },
{ url = "https://files.pythonhosted.org/packages/64/90/7b5a4292eb9993eb8be9d958b5a57764818eeda471e3e79be7da4e9b49ba/pydantic_monty-0.0.7-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:6f40e6e133b309ba733874f5980ab6cf867ec8cea2a6a389a641819cd8dcb7cd", size = 6152219, upload-time = "2026-02-19T14:13:20.734Z" }, { url = "https://files.pythonhosted.org/packages/bf/35/06aaa9c766a83e7e95219bfb6cb88bd0a87803f85eb3f596b82da0cb3009/pydantic_monty-0.0.8-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9534f6236b3ebdd09f0f7d71e508e68736733d24cdda2a6c0a758914261c75e5", size = 6760180, upload-time = "2026-03-10T14:45:22.982Z" },
{ url = "https://files.pythonhosted.org/packages/43/e4/2740af0157eb3c6f10c16b0d8376b8c9cf0b910720fe90229885bccb4a91/pydantic_monty-0.0.7-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:57f2a327b6aa7402a2b2c3ddb3964bd45f12597f8f950dd4c5905b843b353b73", size = 6060942, upload-time = "2026-02-19T14:12:45.601Z" }, { url = "https://files.pythonhosted.org/packages/f3/b8/eaa4a4f0b3a1c343773317027bb5d1e11a1b0c1ad01d3f0921a7f547d346/pydantic_monty-0.0.8-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76c4ffd8275d520628732d82e7410e5f1f69ef5af274d676f1f2f9221fd85a34", size = 6504414, upload-time = "2026-03-10T14:45:12.984Z" },
{ url = "https://files.pythonhosted.org/packages/f6/26/1cf235c2cc8e219a94ed8b11151280ba89e8020a475b6280c89e62f7275f/pydantic_monty-0.0.7-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:771f1f158af0de2480ea2a8862e4c0c7f79e9a13cc3e17529002e1abfc077f95", size = 6315477, upload-time = "2026-02-19T14:14:11.314Z" }, { url = "https://files.pythonhosted.org/packages/9d/79/dbb0875ad2b565d7ef1981feda4438ab743130f4031107aaadc9212488dd/pydantic_monty-0.0.8-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:badaa22749fa7a22ee2cb88f6deb48fc191cb2f41237dd630593259ed9f30b67", size = 6766768, upload-time = "2026-03-10T14:46:29.12Z" },
{ url = "https://files.pythonhosted.org/packages/b8/41/0faca7b9d8868822b7177ae941f193f397479bb114d3a6396466167a3198/pydantic_monty-0.0.7-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a4182312ee8c26d8834e76375b2b5c766cb5d86d1dcf1515aa95e02704fcad83", size = 6862130, upload-time = "2026-02-19T14:13:22.375Z" }, { url = "https://files.pythonhosted.org/packages/25/cb/bd6bef8fa2cfe807dd5ef36ab8ce6d094ecdad0050cf57dec4c8a438d413/pydantic_monty-0.0.8-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e39104684eda1ae3c290e3a4369bef9d00f9b637be8515802bc1523fecb5160d", size = 7326073, upload-time = "2026-03-10T14:45:50.679Z" },
{ url = "https://files.pythonhosted.org/packages/34/7b/0f2bd4105a285f50f17af721e83a76ebc1186a9f07a2a29d6d576490a232/pydantic_monty-0.0.7-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8751696fe66fb1bdd429d98fde3a7f4b7dce9cb45f22095e28b96b690a422a2c", size = 6872292, upload-time = "2026-02-19T14:14:08.078Z" }, { url = "https://files.pythonhosted.org/packages/aa/44/b64b6e2857519d5fdc66f74998019e585e5c3bf2cf8deb7b77419d29db2a/pydantic_monty-0.0.8-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c2e5b3b11b794f82504bb6929f4101f0db84933986aee9b46ce7561add152e9", size = 7535251, upload-time = "2026-03-10T14:46:04.645Z" },
{ url = "https://files.pythonhosted.org/packages/c9/18/4380820d62d348afb1355814ea674788e28db7a73108a486e0b8898987de/pydantic_monty-0.0.7-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40b73cd1137bb4fd9bf95ed5f87e48d960f7d556c30eeafde6996f908abbf183", size = 6636567, upload-time = "2026-02-19T14:14:01.464Z" }, { url = "https://files.pythonhosted.org/packages/da/11/4e1524d94e33427990cffd74eaf94a023724c872f11d42ac90eebd74ccc0/pydantic_monty-0.0.8-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a94fc87b2a9b1b66a09f35b819b1c7e7da7702b21c923cdca21fa13129486b45", size = 7288739, upload-time = "2026-03-10T14:45:35.609Z" },
{ url = "https://files.pythonhosted.org/packages/3e/57/29e5f89a558a6409d514bb2790c72442ec65804cbf1df6a870bbc0038673/pydantic_monty-0.0.7-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c1fa45a66757de5ea45c0809e15643bc2521959dbe2bc231694b22fa189decc9", size = 6693896, upload-time = "2026-02-19T14:14:34.128Z" }, { url = "https://files.pythonhosted.org/packages/2c/7d/7e667c72c9742a6725b04d21faf50e8f552a0e23da9ca1cbeba891961c9a/pydantic_monty-0.0.8-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:70b7479e7bd47d274fbd6278a625289e71b1a4aad400f40c7a4a89fe9a50952c", size = 7189195, upload-time = "2026-03-10T14:46:09.399Z" },
{ url = "https://files.pythonhosted.org/packages/f6/26/5886d0f57ddb5ddf766ee2d0a4b3032267be9efd49a7c95c4d87a0b4b6a9/pydantic_monty-0.0.7-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:ffe8122db9f0f64619a66f4cee2f577245ba59158b7d651a2eae08df691d34f9", size = 6236867, upload-time = "2026-02-19T14:14:20.704Z" }, { url = "https://files.pythonhosted.org/packages/7b/3f/3243277e2c6bf4c3e4684fbc78c316a8965dbbb012b573b38978d8628bfc/pydantic_monty-0.0.8-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:48b8c9cb9a96a5f28b03669771368a444c8b50c758b6a5bd0d148fa02db3f65b", size = 6679333, upload-time = "2026-03-10T14:45:24.494Z" },
{ url = "https://files.pythonhosted.org/packages/b5/72/1bb8741baf84f217d92291b862f8a8cb64d735fe4be20be2827fdf787593/pydantic_monty-0.0.7-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:2122a5b6df53843329af01f6671300747449608d9cdf88ae5f9cf9977794e7a2", size = 6673504, upload-time = "2026-02-19T14:14:24.517Z" }, { url = "https://files.pythonhosted.org/packages/0c/51/88152b89f5288e9d3cd28e71f79a6567421e20d8f00b0514b7819a29a8bb/pydantic_monty-0.0.8-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:b005f10798a1b58a12b5643f69a7b54208bd4965d16ca2bd21d13fca4d1a4f67", size = 7137771, upload-time = "2026-03-10T14:46:33.043Z" },
{ url = "https://files.pythonhosted.org/packages/d1/14/a4ff2bfe46350ffde4b5edc1f293b252cff90063f1f4cece49affe5a6462/pydantic_monty-0.0.7-cp314-cp314-win32.whl", hash = "sha256:bfbea2eddb9eef186326a6dfb27d79f8de434d7a3979f36f03b04216234a0275", size = 6131872, upload-time = "2026-02-19T14:13:14.437Z" }, { url = "https://files.pythonhosted.org/packages/d8/38/baf5a66ed72b931de7ce92251822d6ffb752582389ff4f4c853742cee029/pydantic_monty-0.0.8-cp314-cp314-win32.whl", hash = "sha256:b143bba29c274e15424a097af6ae85a1e81e6c2fb7184ee7a93fbf10997dbbd3", size = 6584038, upload-time = "2026-03-10T14:46:34.53Z" },
{ url = "https://files.pythonhosted.org/packages/60/1f/d873f280aae5cbd27021189843fbd5f77be4262a7654ef30445d984518ab/pydantic_monty-0.0.7-cp314-cp314-win_amd64.whl", hash = "sha256:1b750afceef78f5c5d3e3e3c32a8060b3a7e1b97e3a00ac2bede5bc5e87cde8f", size = 6687125, upload-time = "2026-02-19T14:13:04.317Z" }, { url = "https://files.pythonhosted.org/packages/71/80/bfda690914fa15c68f8be9e824e62c4054118a9a72304735221446a89014/pydantic_monty-0.0.8-cp314-cp314-win_amd64.whl", hash = "sha256:f4bc9185bb5f37f3220a978889b4bc6f822a41ee4d5523c17eef4d869aca66e8", size = 7351170, upload-time = "2026-03-10T14:46:57.025Z" },
] ]
[[package]] [[package]]