25f0cecf5e
read_file previously hard-rejected any read whose formatted output exceeded the ~100K char safety limit, returning an error with zero content. A file with few but very long lines (logs, wide CSV rows, minified data) sails past the line-count limit and then trips the char guard, so the model gets nothing and must guess a smaller limit — wasting a full round-trip. Now the read is trimmed to the last complete line that fits the budget and returns the partial content plus truncated_by="bytes" and a next_offset, so the model paginates forward instead of starting over. A single line larger than the whole budget is clamped on a code-point boundary (never empty) and the cursor still advances. Applies at both read paths (normal + extracted documents). Adapted from IronClaw's Rust dual line/byte cap to hermes's Python tool-layer char guard, which is the single uniform chokepoint over the gutter-rendered content for every backend.