Make CodeMode return guidance unambiguous

This commit is contained in:
Aditya Vardhan
2026-07-14 22:53:58 +05:30
parent e755dcd187
commit d5191951df
4 changed files with 34 additions and 8 deletions
+2 -2
View File
@@ -153,7 +153,7 @@ That fold-in grows `run_code`'s description, which invalidates the prompt-cache
## Return values
The last expression in the snippet is automatically captured as the return value -- the model does not need to `print()`. An assignment stores a value in the REPL but does not return it, so put the assigned name on the final line:
The last expression in the snippet is automatically captured as the return value -- the model does not need to `print()`. An assignment stores a value in the REPL but does not return it. Without a trailing expression or print output, `run_code` returns `{}`. Put the assigned name on the final line:
```python
result = await get_weather(city='Paris')
@@ -165,7 +165,7 @@ Reserve `print()` for supplementary logging: printed text is surfaced separately
| Scenario | Return |
|---|---|
| No print output | Last expression value |
| Final assignment with no trailing expression | No expression result |
| Final assignment with no trailing expression | `{}` |
| With print output | `{'output': '<printed text>', 'result': <last expression>}` |
| Multimodal content (e.g. images) | Returned natively for model processing |
+4 -2
View File
@@ -44,6 +44,8 @@ print(result.output)
The model writes code like:
```python
import asyncio
paris, tokyo = await asyncio.gather(
get_weather(city='Paris'),
get_weather(city='Tokyo'),
@@ -144,7 +146,7 @@ become callable functions inside `run_code`. Tools without
## Return values
The last expression in the code snippet is automatically captured as the return value -- the model does not need to `print()`. An assignment stores a value in the REPL but does not return it, so put the assigned name on the final line:
The last expression in the code snippet is automatically captured as the return value -- the model does not need to `print()`. An assignment stores a value in the REPL but does not return it. Without a trailing expression or print output, `run_code` returns `{}`. Put the assigned name on the final line:
```python
result = await get_weather(city='Paris')
@@ -154,7 +156,7 @@ result
| Scenario | Return |
|---|---|
| No print output | Last expression value |
| Final assignment with no trailing expression | No expression result |
| Final assignment with no trailing expression | `{}` |
| With print output | `{"output": "<printed text>", "result": <last expression>}` |
| Multimodal content (e.g. images) | Returned natively for model processing |
+2 -2
View File
@@ -85,7 +85,7 @@ Write and run Python code in a sandboxed environment.
The sandbox uses Monty, a subset of Python. Key restrictions:
- **No classes**: class definitions are not supported
- **No third-party libraries**: only the standard library modules listed below can be used
- **Importable standard library modules**: `sys`, `typing`, `asyncio`, `math`, `json`, `re`, `datetime`, `os`, `pathlib`. These must be imported before use, just like in regular Python. For example: `import asyncio` then `results = await asyncio.gather(tool_one(...), tool_two(...))`."""
- **Importable standard library modules**: `sys`, `typing`, `asyncio`, `math`, `json`, `re`, `datetime`, `os`, `pathlib`. These must be imported before use, just like in regular Python. For example: `import asyncio` then `await asyncio.gather(tool_one(...), tool_two(...))`."""
# Timing/OS restriction line, swapped depending on what host access the agent
# configured. Three states, because `mount` and `os` enable different things:
@@ -117,7 +117,7 @@ State is preserved between calls (REPL-style). Set `restart: true` to reset stat
The last expression's value is automatically captured as the return value -- you do **not** need to \
`print()` it. End the snippet with the value to return as a bare expression. A final assignment stores \
the value but does not return it. For example:
the value but does not return it. When nothing is printed, `run_code` returns `{}`. For example:
```python
result = some_expression
+26 -2
View File
@@ -247,8 +247,32 @@ class TestCodeMode:
assert description is not None
assert 'End the snippet with the value to return as a bare expression.' in description
assert 'result = some_expression\nresult' in description
assert 'e.g. `await tool_name(arg=value)`.' in description
assert 'e.g. `result = await tool_name(arg=value)`.' not in description
assert '`run_code` returns `{}`' in description
assert 'results = await asyncio.gather' not in description
async def test_run_code_function_examples_are_expressions(self) -> None:
"""Async, sync, and mixed function examples do not end on assignments."""
cases: list[tuple[FunctionToolset[object], tuple[str, ...]]] = [
(_build_function_toolset(add), ('e.g. `await tool_name(arg=value)`.',)),
(
FunctionToolset[object](tools=[Tool(add, sequential=True)]),
('e.g. `tool_name(arg=value)`.',),
),
(
FunctionToolset[object](tools=[Tool(add, sequential=True), Tool(greet)]),
('e.g. `await tool_name(arg=value)`.', 'e.g. `tool_name(arg=value)`.'),
),
]
for toolset, expected_examples in cases:
wrapper = CodeMode[object]().get_wrapper_toolset(toolset)
assert isinstance(wrapper, CodeModeToolset)
description = (await wrapper.get_tools(build_run_context(None)))['run_code'].tool_def.description
assert description is not None
assert all(example in description for example in expected_examples)
assert 'e.g. `result =' not in description
async def test_run_code_executes_call_through_monty(self) -> None:
"""End-to-end: `run_code` runs Python in Monty and dispatches to a sync wrapped tool."""