Skip to content

agent: read_file — Grok Build-style line offset + limit #688

Description

@btipling

Summary

Extend the existing read_file tool so it windows like Grok Build’s read_file. Do not add a second tool.

Grok Build today:

Arg Meaning
path / target_file required
offset 1-based start line (default 1)
limit number of lines to return (default 1000)

Result is a line-numbered window (N→content), not a byte range and not a prefix-from-start dump.

Invincible today (lib/agent/tools.tsclient.readFile(path, maxBytes) → BYO sandbox/tools.mjs / Vercel lib/sandbox/vercelClient.ts): path + optional maxBytes prefix, 16 MiB hard cap, no line addressing. A truncated read does not authorize str_replace / overwrite (fileFreshness truncated: true).

This issue locks the window shape that #563 left as “pick in plan”: line offset + limit, same names and defaults as Grok Build. #563’s “don’t dump a huge file when no window” is the default-limit=1000 case.

Desired behavior (lock)

Same args and defaults as Grok Build:

read_file { path, offset?, limit? }
  • offset — first line to return, 1-based. Omit / 1 = start of file.
  • limit — max lines to return. Omit = 1000.
  • Response body is the window only, each line prefixed with its file line number so the next call can pass offset without guessing (Grok Build uses N→line; pick that or N|line in implement — one format, documented).
  • Status line stays the first line / L1 brief source and must name the window, e.g. read_file lib/foo.ts offset=40 limit=20 lines=412 (truncated): (exact string locked in implement). salientToolBits must keep L1 as path + size, not the body.
  • maxBytes stays as a safety cap on the returned window (still server-capped at 16 MiB). It is not the window API.

Unchanged jail / cwd / in-jail absolute rules. finalize / TOOL_RESULT_MAX_CHARS still apply to the window.

Edit gate (do not weaken #277)

Read freshness.recordRead str_replace / overwrite
Window covers the entire file (returned line count < limit, and not byte-truncated) truncated: false authorized (same as today’s full read)
Hit limit or maxBytes truncated: true denied — existing “truncated read_file is not enough”

No silent “windowed is full enough.” To edit a 1400-line file the model raises limit (or pages, then requests a limit that covers the file). Do not add a full: true flag unless a later plan proves default-1000 makes grants impossible in practice.

Caps (NEW — generous defaults; any change to 16 MiB is a human decision)

Cap Value Notes
Default limit 1000 lines Grok Build default. NEW.
offset ≥ 1 1-based. Out of range → empty window + truncated/lines= so the model can recover, not a crash.
maxBytes / 16 MiB unchanged Still the hard read/write byte ceiling.

Layers

Concern Layer Path
Tool schema + status line + freshness Vercel backend lib/agent/tools.ts, lib/agent/fileFreshness.ts
BYO read sandbox daemon sandbox/tools.mjs readFileTool — today fh.read(..., 0) prefix only
Vercel sandbox read backend lib/sandbox/vercelClient.ts
L1 brief backend lib/agent/agentStream.ts salientToolBits
Living doc docs docs/sandbox.md (read_file row), docs/harness-limits.md if a cap is listed

Do not load 16 MiB into the model to return 40 lines. Daemon/client may scan to line offset; the tool result must be the window only. Protocol bump only if the BYO /v1/read_file body must grow (offset/limit) — lock in implement; additive fields preferred.

Acceptance

  • read_file accepts offset + limit with Grok Build defaults (1 / 1000)
  • Returned body is a line-numbered window; L1 does not dump the body
  • Default read of a 1400-line file is 1000 lines + truncated; does not grant edit
  • Read of a 50-line file with defaults is a full grant (same as today)
  • offset=40, limit=20 returns file lines 40–59 only
  • Existing jail / cwd / maxBytes / redact / finalize unchanged
  • docs/sandbox.md (and limits table if needed) describe the window — timeless, no issue theater
  • Both backends (BYO daemon + Vercel client)

Non-goals

  • A second tool (read_range, read_window, …)
  • Byte-offset windows (Grok Build is lines)
  • Hashline anchors (agent tool: stale/failed str_replace returns a small file window #564)
  • Combining list_dir into read
  • Language-specific outlines
  • Changing str_replace / write_file match semantics
  • Lowering the 16 MiB byte cap
  • Forbidden: dual DOM chat · secrets in Wasm · windowed read silently authorizing overwrite · exec sed as the product path

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions