Skip to content

fix(tools): coerce read tool offset/limit to int — kills agent on string-typed args#110

Open
triscacezar-droid wants to merge 1 commit intohuggingface:mainfrom
triscacezar-droid:fix/coerce-read-offset-limit
Open

fix(tools): coerce read tool offset/limit to int — kills agent on string-typed args#110
triscacezar-droid wants to merge 1 commit intohuggingface:mainfrom
triscacezar-droid:fix/coerce-read-offset-limit

Conversation

@triscacezar-droid
Copy link
Copy Markdown

Symptom

The local `read` tool handler crashes the agent loop with:

```
File "agent/tools/local_tools.py", line 146, in _read_handler
offset = max((args.get("offset") or 1), 1)
TypeError: '>' not supported between instances of 'int' and 'str'
```

This happens whenever the model returns `offset` (or, by extension, `limit`) as a string like `"1"` instead of an integer. Python 3's `max()` can't compare across str and int.

Why this happens

Tool args go through JSON serialization on the way out of the model and on the way back into the handler. Even though the tool schema declares `offset: integer`, some models occasionally emit it as a string (especially smaller / faster ones, or when the model is mid-conversation and the response shape drifts), and LiteLLM passes it through verbatim. Every other tool handler that takes numeric args has the same latent risk.

Impact

The crash kills the entire agent run mid-task. In my case it ate ~30 minutes of an investigative ml-intern run that had just completed a useful baseline phase — losing the live state.

Fix

Coerce `offset` and `limit` via `int()` with a typed-fallback to the existing default. No behavior change when args arrive as ints (the common path).

```python
try:
offset = int(args.get("offset") or 1)
except (TypeError, ValueError):
offset = 1
try:
limit = int(args.get("limit") or DEFAULT_READ_LINES)
except (TypeError, ValueError):
limit = DEFAULT_READ_LINES
offset = max(offset, 1)
```

Compatibility

Pure additive defensiveness — passes all existing call shapes. No new dependencies. The same pattern could reasonably be applied to other numeric tool args (`bash.timeout`, etc.) in a follow-up; happy to do that here if you'd prefer one bigger PR.

The local read handler was doing `max(args.get("offset") or 1, 1)` which
TypeErrors on Python 3 if the model passes "1" (string) instead of 1 (int):

    File "agent/tools/local_tools.py", line 146, in _read_handler
        offset = max((args.get("offset") or 1), 1)
    TypeError: '>' not supported between instances of 'int' and 'str'

This kills the agent loop mid-task. Some models (and intermediate JSON
serialization steps) occasionally hand back numeric tool args as strings,
even though the tool schema declares them as int. The same risk applies
to `limit`.

Fix: coerce both via int() with a typed-fallback to the default, then
clamp offset to >= 1 as before. No behavior change when args arrive as
ints (the common case).

Hit while running a long agent investigation; the agent had completed
~30 minutes of useful work, then died on a mid-run file read.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant