fs

package
v1.11.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 11, 2026 License: MIT Imports: 32 Imported by: 0

Documentation

Overview

Package fs exposes filesystem tools (Read, Write, Edit) as stateless singletons. Construction policy (eager vs lazy) is decided by the agent; this package only knows how to produce tool instances.

Index

Constants

View Source
const (
	OpCreate    = "create"
	OpEdit      = "edit"
	OpOverwrite = "overwrite"
)

Op enumerates the kinds of file mutation a FileDiff describes. Kept as strings so the wire/UI side can render without importing this package.

View Source
const (
	LineContext = "context"
	LineAdd     = "add"
	LineRemove  = "remove"
)

LineKind enumerates how a single DiffLine relates to the change. Same semantics as a unified diff's prefix character.

View Source
const ContextLines = 3

ContextLines is how many unchanged lines we include above and below an edit hunk. Matches `diff -u` default.

View Source
const DefaultReadLimit = 2000

DefaultReadLimit caps an unbounded Read at this many lines. The model can pass an explicit larger limit when it really needs more, but the default protects the context window from accidental 50k-line dumps. Matches Claude Code's MAX_LINES_TO_READ.

View Source
const MaxEditFileSize = 1 << 30 // 1 GiB

MaxEditFileSize caps the on-disk byte size edit will load into memory. edit reads the whole file via readFileWithEncoding, so a multi-GB file would OOM the process; reject it instead. Mirrors ref FileEditTool's MAX_EDIT_FILE_SIZE (1 GiB).

Variables

This section is empty.

Functions

func HashContent added in v1.4.3

func HashContent(s string) [32]byte

HashContent returns the SHA-256 of s. Callers pass the LF-normalized full file content (what readFileWithEncoding produces) so the read site and the edit/write site hash the same representation and the staleness fallback can compare them. A zero [32]byte means "no full-content view" and disables the fallback.

func Names

func Names() []tools.ToolName

Names lists every tool name this package contributes, in canonical order.

Types

type CheckpointSink added in v1.8.2

type CheckpointSink interface {
	// CaptureBefore records absPath's current on-disk bytes before the caller
	// overwrites the file. Idempotent per path within a turn (the first call
	// wins, preserving the earliest before-image). Best-effort by contract: it
	// must never block or error the edit.
	CaptureBefore(absPath string)
}

CheckpointSink receives the pre-mutation state of files the edit/write tools are about to change, so the runtime's checkpoint/rewind engine can later restore them. The interface is declared here, on the consumer side, so pkg/tools/fs stays free of an internal/checkpoint import; the runtime wires a concrete implementation in via WithCheckpoints.

A nil sink disables capture entirely — the tools nil-check before calling, and the runtime only installs a sink when checkpointing is enabled — so the feature has zero cost on the edit hot path when it is off.

type DiffHunk

type DiffHunk struct {
	OldStart, OldCount int
	NewStart, NewCount int
	Lines              []DiffLine
}

DiffHunk groups consecutive related lines, mirroring unified-diff hunks. Start counts are 1-based; Count is the number of lines in that hunk from the respective side (matches the "@@ -OldStart,OldCount +NewStart,NewCount @@" header).

type DiffLine

type DiffLine struct {
	Kind string // context / add / remove
	Old  int    // 0 if not present on the old side
	New  int    // 0 if not present on the new side
	Text string
}

DiffLine carries one rendered row. Old and New are 1-based line numbers on each side; the one that doesn't apply (e.g. New on a "remove" line) is 0 so the UI can render an empty cell.

type EditTool

type EditTool struct {
	// contains filtered or unexported fields
}

func NewEdit

func NewEdit(tracker *ReadTracker, workdir string) *EditTool

func (*EditTool) Description

func (t *EditTool) Description() string

func (*EditTool) Execute

func (t *EditTool) Execute(ctx context.Context, logger *slog.Logger, input json.RawMessage) (tools.Result, error)

func (*EditTool) Name

func (t *EditTool) Name() string

func (*EditTool) Schema

func (t *EditTool) Schema() json.RawMessage

func (*EditTool) WithCheckpoints added in v1.8.2

func (t *EditTool) WithCheckpoints(s CheckpointSink) *EditTool

WithCheckpoints installs the checkpoint/rewind capture sink (nil-safe). The runtime calls this at tool construction; tests and embedders that omit it get a no-op capture path. Returns the receiver for fluent construction.

func (*EditTool) WithLSPSync added in v1.11.0

func (t *EditTool) WithLSPSync(s LSPSyncSink) *EditTool

WithLSPSync installs the LSP-sync notification sink (nil-safe). The runtime calls this at tool construction; tests and embedders that omit it get a no-op path — edits behave exactly as before this feature existed. Returns the receiver for fluent construction.

type FileDiff

type FileDiff struct {
	Path  string
	Op    string // create / edit / overwrite
	Hunks []DiffHunk
}

FileDiff is the structured payload write_file and edit_file attach to tools.Result.Metadata so UIs can render git-style diffs (red removes, green adds, line numbers in two columns) without parsing text.

LLMs never see this — Content carries the model-facing summary.

type GlobTool

type GlobTool struct {
	// contains filtered or unexported fields
}

func NewGlob

func NewGlob(workdir string) *GlobTool

func (*GlobTool) Description

func (t *GlobTool) Description() string

func (*GlobTool) Execute

func (t *GlobTool) Execute(ctx context.Context, logger *slog.Logger, input json.RawMessage) (tools.Result, error)

func (*GlobTool) Name

func (t *GlobTool) Name() string

func (*GlobTool) Schema

func (t *GlobTool) Schema() json.RawMessage

type LSPSyncSink added in v1.11.0

type LSPSyncSink interface {
	// NotifyEdited reports that absPath now holds newContent. The didChange
	// dispatch itself is best-effort and, by default, asynchronous — it must
	// never block or fail the edit. The returned string is a rendered
	// diagnostics block to append to the tool's own Result.Content; it is
	// non-empty only when the runtime's synchronous opt-in tier is enabled
	// and diagnostics for this file arrived within its bounded wait. Empty in
	// every other case (including whenever the synchronous tier is off).
	NotifyEdited(absPath, newContent string) string
}

LSPSyncSink is notified after the edit/write tools mutate a file, so the runtime's LSP layer can re-analyze it and the model sees real, fresh diagnostics for what it just wrote — instead of editing blind until a later bash build happens to trip over the error. Declared consumer-side (mirrors CheckpointSink) so pkg/tools/fs imports neither pkg/tools/lsp nor internal/*; the runtime wires a concrete implementation in via WithLSPSync. A nil sink disables it entirely — the tools nil-check before calling, and the runtime only installs a sink when an LSP manager exists — so the feature has zero cost on the edit hot path when LSP is off.

type ReadTool

type ReadTool struct {
	// contains filtered or unexported fields
}

func NewRead

func NewRead(tracker *ReadTracker, workdir string) *ReadTool

func (*ReadTool) Description

func (t *ReadTool) Description() string

func (*ReadTool) Execute

func (t *ReadTool) Execute(ctx context.Context, logger *slog.Logger, input json.RawMessage) (tools.Result, error)

func (*ReadTool) Name

func (t *ReadTool) Name() string

func (*ReadTool) Schema

func (t *ReadTool) Schema() json.RawMessage

type ReadTracker

type ReadTracker struct {
	// contains filtered or unexported fields
}

ReadTracker records every read_file call the agent makes so that edit_file / write_file can refuse to mutate a file whose on-disk state has drifted from what the model has in context.

Two failure modes the tracker protects against, mirroring Claude Code's FileReadTool ↔ FileEditTool contract:

  1. Never read — the model is editing blind. Reject.
  2. Read but the file's bytes changed on disk afterwards — another process, or the user, edited it. Force a re-read so the model's old_string still reflects reality. Detected by an mtime advance, with a content-hash fallback so a touch / formatter / cloud-sync that bumps mtime without changing bytes does NOT force a re-read.

A truncated or offset read is NOT treated as a blocking "partial view": ref stores offset/limit but never blocks edits on them, and evva's edit path re-reads the full file and requires old_string to match uniquely, so editing after seeing only a slice is safe. IsPartialView is retained only to gate the read-dedup "file unchanged" stub.

Zero value is NOT usable; call NewReadTracker.

func NewReadTracker

func NewReadTracker() *ReadTracker

func (*ReadTracker) CanEdit

func (t *ReadTracker) CanEdit(absPath string, currentMtime time.Time, currentHash [32]byte) (bool, string)

CanEdit reports whether an edit_file call against absPath is permitted given the file's current mtime and content hash. When false, reason is the model-facing explanation (mirrors ref TS FileEditTool wording).

currentHash is the SHA-256 of the file's current full content (LF-normalized). It is only consulted when mtime indicates drift: if the recorded read carried a full-content hash and it still equals currentHash, the mtime bump is spurious (touch / formatter / cloud sync) and the edit proceeds — matching ref's full-read content comparison.

func (*ReadTracker) CanWrite

func (t *ReadTracker) CanWrite(absPath string, currentMtime time.Time, currentHash [32]byte) (bool, string)

CanWrite reports whether write_file may overwrite absPath. Same gate as edit — overwriting a stale read is the same hazard as editing one.

func (*ReadTracker) Forget

func (t *ReadTracker) Forget(absPath string)

Forget drops the entry for absPath. Used by tests; never called in production code.

func (*ReadTracker) Lookup

func (t *ReadTracker) Lookup(absPath string) (readEntry, bool)

Lookup returns the recorded entry, or zero+false if absPath has never been recorded.

func (*ReadTracker) Record

func (t *ReadTracker) Record(absPath string, mtime time.Time, partial bool, contentHash [32]byte)

Record stores that absPath was read at the given mtime, with the partial flag indicating whether the read covered only a slice of the file and contentHash the SHA-256 of the full file content (zero to disable the staleness fallback). HasReadOffset is left false — callers that represent an actual Read tool invocation should use RecordRead instead so the dedup check can tell them apart from Edit/Write post-mutation updates.

func (*ReadTracker) RecordRead

func (t *ReadTracker) RecordRead(absPath string, mtime time.Time, partial bool, contentHash [32]byte)

RecordRead is like Record but marks the entry as coming from an actual Read tool call. The Read tool's dedup check only fires for entries with HasReadOffset=true, so Edit/Write post-mutation updates (which call Record) don't cause spurious "File unchanged since last read" stubs.

type WriteTool

type WriteTool struct {
	// contains filtered or unexported fields
}

func NewWrite

func NewWrite(tracker *ReadTracker, workdir string) *WriteTool

func (*WriteTool) Description

func (t *WriteTool) Description() string

func (*WriteTool) Execute

func (t *WriteTool) Execute(ctx context.Context, logger *slog.Logger, input json.RawMessage) (tools.Result, error)

func (*WriteTool) Name

func (t *WriteTool) Name() string

func (*WriteTool) Schema

func (t *WriteTool) Schema() json.RawMessage

func (*WriteTool) WithCheckpoints added in v1.8.2

func (t *WriteTool) WithCheckpoints(s CheckpointSink) *WriteTool

WithCheckpoints installs the checkpoint/rewind capture sink (nil-safe). The runtime calls this at tool construction; tests and embedders that omit it get a no-op capture path. Returns the receiver for fluent construction.

func (*WriteTool) WithLSPSync added in v1.11.0

func (t *WriteTool) WithLSPSync(s LSPSyncSink) *WriteTool

WithLSPSync installs the LSP-sync notification sink (nil-safe). The runtime calls this at tool construction; tests and embedders that omit it get a no-op path — writes behave exactly as before this feature existed. Returns the receiver for fluent construction.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL