Skip to content

[BUG]: Scratchpad not firing on Read Artifact #596

Description

@Shearerbeard

Summary

Scratchpad is not intercepting large artifact reads on subsequent orchestration turns in a predictable manner. Example from today:

● ReadArtifact(filename: "task-0-files-iter...", run_id: "01a03950-4b4e-758...")
⎿ completed in 296ms
● My tools returned more data than I can work with at once.

  To help me out, try:
  - Narrowing your search with filters
  - Asking for a summary instead of full results
  - Splitting into smaller requests

Coordinator has no context budget wired at the moment and we may be seeing some redundant outputs on disc conflating things.

Related to #125

Reproduction

Get a worker to hit a large tool output and summarize the results - ask the coordinator to verify the results its self next turn.

Relevant log output

Claude Fable benchmark observation traces from that run (claude driving benchmarks)


What you hit is a real gap, and it's exactly the caveat from my last answer — but on the coordinator, not a worker. Here's the reconstruction from /tmp/aura-k8s-orchestration-fs/88ee9b71…:

  Run 1 (01a03950, 10:26) — goal: "Read the local JSON file …task_0--deduplicate_logs_time_range-0-522842ae.json". The files worker called read_text_file and got back 76 MB (67 MB file, JSON-escaped). The worker's scratchpad worked as designed: it intercepted the output, wrote
  iteration-1/scratchpad/task_0-files-read_text_file-1-c7d2a033.json plus an extracted .content.json, and the worker answered with a structural summary. But the PersistenceWrapper observes raw output, so it also wrote the full 76 MB as an artifact:
  artifacts/task-0-files-iter-1-read-text-file-0-output.txt. That filename went into the run manifest's tool_trace[].artifact_filename.

  Run 2 (01a03953, 10:28) — your follow-up query. The coordinator saw the prior run's session context, decided it needed the data, and called read_artifact(filename="task-0-files-iter-1-read-text-file-0-output.txt", run_id="01a03950…"). That's the ● ReadArtifact(…) line. It returned 76 MB
  inline in 296 ms, the next LLM call failed with a context-length error, and the web server swapped the error for the canned banner (handlers.rs:613, CONTEXT_OVERFLOW_MESSAGE). Run 2's directory is empty because the coordinator never got as far as writing a plan.

  Why the scratchpad didn't help: the coordinator's read_artifact is built bare — ReadArtifactTool::new(self.persistence.clone()) at crates/aura/src/orchestration/orchestrator.rs:2295, with no .with_scratchpad(...). The only site that wires the scratchpad in is the worker path
  (builder.rs:1091), and coordinators have no ContextBudget at all (builder.rs:141: "None for coordinator agents"). So surface_content takes its first branch — scratchpad inactive → return content inline, unbounded — regardless of size.

  So to answer the question precisely: read_artifact is scratchpad-aware for workers, and not for the coordinator. Whoever told you it's enabled was right about workers; the cross-run/follow-up case you exercised goes through the coordinator.

  There's a second, contributing problem: persisting a 76 MB artifact at all. The worker already had the content in its scratchpad; writing the raw output again as an artifact just creates a landmine for anything that reads artifacts later (the coordinator's re-planning, list_prior_runs
  follow-ups, a future worker via read_artifact without a budget).

  Options, roughly in order of how much I'd recommend them:

  1. Give the coordinator's read_artifact a budget — build a ContextBudget from the coordinator's LLM context_window and hand it .with_scratchpad(...) with a read root covering the session dir, so oversized artifacts come back as in-place pointers. Needs the coordinator to also get the
     scratchpad read tools (schema/head/grep…) or the pointer is useless to it. Moderate change, ~1–2 days.
  2. Hard cap in read_artifact when no budget is present — e.g. refuse (or head-truncate with a notice) above N tokens. Small, defensive, catches every unbudgeted caller. Half a day.
  3. Don't persist raw output that the scratchpad already intercepted — have persistence record the scratchpad file reference instead of duplicating 76 MB. Also fixes the disk bloat (that run wrote ~320 MB across the artifact, two scratchpad files, and tool-calls.json).

  I'd do 2 immediately as a backstop and 1 as the proper fix; 3 is worth a separate issue. Want me to file the GitHub issue(s), or start on any of these?

Additional Context

No response

Upload screenshots

No response

Searched Issues

  • No similar issues found

Code of Conduct

  • I agree to follow this project's Code of Conduct

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions