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
- func Names() []tools.ToolName
- type DiffHunk
- type DiffLine
- type EditTool
- type FileDiff
- type GlobTool
- type ReadTool
- type ReadTracker
- func (t *ReadTracker) CanEdit(absPath string, currentMtime time.Time) (bool, string)
- func (t *ReadTracker) CanWrite(absPath string, currentMtime time.Time) (bool, string)
- func (t *ReadTracker) Forget(absPath string)
- func (t *ReadTracker) Lookup(absPath string) (readEntry, bool)
- func (t *ReadTracker) Record(absPath string, mtime time.Time, partial bool)
- func (t *ReadTracker) RecordRead(absPath string, mtime time.Time, partial bool)
- type WriteTool
Constants ¶
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.
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.
const ContextLines = 3
ContextLines is how many unchanged lines we include above and below an edit hunk. Matches `diff -u` default.
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.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type DiffHunk ¶
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 (*EditTool) Schema ¶
func (t *EditTool) Schema() json.RawMessage
type FileDiff ¶
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 (*GlobTool) Description ¶
func (*GlobTool) Schema ¶
func (t *GlobTool) Schema() json.RawMessage
type ReadTool ¶
type ReadTool struct {
// contains filtered or unexported fields
}
func NewRead ¶
func NewRead(tracker *ReadTracker, workdir string) *ReadTool
func (*ReadTool) Description ¶
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.
Three failure modes the tracker protects against, mirroring Claude Code's FileReadTool ↔ FileEditTool contract:
- Never read — the model is editing blind. Reject.
- Read but mtime advanced on disk afterwards — another process, or the user, changed the file. Force a re-read so the model's old_string still matches.
- Partial-view read (offset / explicit limit) — the model only saw a slice and has no idea what surrounds the edit. Force a full re-read before mutating.
Zero value is NOT usable; call NewReadTracker.
func NewReadTracker ¶
func NewReadTracker() *ReadTracker
func (*ReadTracker) CanEdit ¶
CanEdit reports whether an edit_file call against absPath is permitted given the file's current mtime. When false, reason is the model-facing explanation (mirrors ref TS FileEditTool wording).
func (*ReadTracker) CanWrite ¶
CanWrite reports whether write_file may overwrite absPath. Same gate as edit — overwriting a stale or partial-view 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)
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. 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)
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.