Skip to content

Python: [Feature]: Better FileAccessProvider for python harness #6770

Description

@jhare96

Description

The existing preview feature is lacking some key tools for editing files, and the tooling name / conventions differs from existing frameworks that popular model providers train on.

Description

  • No surgical editing. To change three lines, the model must re-emit the entire file via save_file. That burns tokens, races with concurrent edits, and frequently corrupts large files when the model "rewrites from memory."
  • No read-only/read-write split. There's no first-class way to give a sub-agent read access only, so "safe to delegate investigation" agents have to be hand-rolled.
  • No per-tool approval gating. Destructive operations (delete/overwrite) can't be individually gated behind an approval step.
  • Fixed workdir. The store's root is set at construction, so one agent instance can't safely serve multiple working directories (parallel tasks/sessions) without rebuilding the agent.

Proposal: ship richer file capabilities as ContextProviders (so they inject per-run), split into a read tier and an edit tier:

  • Read tierread, list_files, grep (recursive, grep -rn-style regex with include glob filtering), glob (**-aware path matching).
  • Edit tier (extends read) — write, edit (exact-string replace, with replace_all), apply_patch (unified diff: modify/add/delete/rename), delete_file.

Cross-cutting:

  • Per-run workdir scoping: resolve the workdir from session.state["workdir"] at before_run, falling back to a construction default, so a single agent instance serves many workdirs concurrently.
  • Path safety: workdir-relative paths only, with traversal/symlink protection.
  • Approval modes per tool: gate delete_file (and optionally edit/apply_patch) behind always_require.

Code Sample

from agent_framework import (
    Agent,
    FileReadAccessProvider,
    FileEditAccessProvider # subclasses Read
)


# Editing agent: read + write/patch tools, workdir-scoped, delete gated.
editor = Agent(
    client=client,
    instructions=...,
    context_providers=[
        FileEditToolsProvider(
            default_workdir="/work/project-a",
            require_delete_approval=True,   # delete_file -> always_require
            require_edit_approval=False,    # edit/apply_patch auto-run
        ),
    ],
)

# Read-only sub-agent: gets read/list_files/grep/glob ONLY — safe to delegate.
investigator = Agent(
    client=client,
    instructions=...,
    context_providers=[FileReadToolsProvider(default_workdir="/work/project-a")],
)




session_a.state["workdir"] = "/work/task-a"
session_b.state["workdir"] = "/work/task-b"

await asyncio.gather(
    editor.run("refactor module X", session=session_a),
    editor.run("fix failing test", session=session_b),
)  # each run's file tools are scoped to its own directory


**Surgical edits instead of whole-file rewrites:**


# exact-string edit
edit(file_name="src/app.py", old_string="DEBUG = True", new_string="DEBUG = False", replace_all=True)

# unified-diff patch (add/modify/delete/rename), the format models produce best
apply_patch(file_name="src/app.py", patch="--- a/src/app.py\n+++ b/src/app.py\n@@ ...")


**Search the tree without reading every file:**


grep(pattern=r"def create_agent", include="*.py")   # recursive, like grep -rn
glob(pattern="**/*.sysml")                          # recursive path match


**Approval loop for gated destructive ops** (when `require_delete_approval=True`):


result = await editor.run("remove the obsolete config", session=session_a)
for req in result.user_input_requests:   # delete_file surfaces here for approval
    ...

Language/SDK

Both

Metadata

Metadata

Assignees

No one assigned

    Labels

    pythonUsage: [Issues, PRs], Target: PythontriageUsage: [Issues], Target: All issues that still need to be triaged
    No fields configured for Feature.

    Projects

    Status
    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions