Skip to content

feat(files): scoped search, in-place edits, and ranged reads for agent memory filesystems - #7393

Open
mzxchandra wants to merge 21 commits into
feat/file-folder-operationsfrom
feat/file-memory-ops
Open

feat(files): scoped search, in-place edits, and ranged reads for agent memory filesystems#7393
mzxchandra wants to merge 21 commits into
feat/file-folder-operationsfrom
feat/file-memory-ops

Conversation

@mzxchandra

@mzxchandra mzxchandra commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Stacked on #7388 (feat/file-folder-operations) — review the last 3 commits, or wait for #7388 to merge and this rebases to a clean diff.

Why

An Agent block maintaining a per-user memory filesystem:

/memory/{userId}/projects/…
/memory/{userId}/people/…
/memory/{userId}/commitments/…
/memory/{userId}/self.md

Three gaps make that unworkable today.

Search is workspace-wide. An agent maintaining /memory/{userId} needs its grep confined to that subtree, or every lookup returns other users' notes.

To be precise about what this is not: there is no per-folder authorization in Sim. Any principal with workspace read access can read every file in the workspace, with or without this change. folderPaths is a query filter, not an access boundary — it narrows what a caller asked for, not what they are permitted to see. It makes the agent's behaviour correct; it is not a security control.

There is no way to change one line. Writes are append-only or whole-file overwrite, so every correction regenerates the whole note — the LongWriter output ceiling and cumulative drift, on every note, every night. Scoped grep without an in-place edit is a fast finder bolted to a blunt writer.

Reads are all-or-nothing. Fine at four notes, wasteful at two hundred.

What

1. folderPaths + includeSubfolders on file_search

The segment table carries no folder id, so the predicate travels through the workspaceFiles join both queries already make.

It is applied to the coverage query too, not just the match query, so complete/indexStatus describe the scope searched. That is the half that matters for the driving use case: an agent choosing between add a note and update the existing one cannot distinguish an unindexed file from a missing fact, and adds a duplicate. A scoped complete: true is a far stronger signal than a workspace-wide one. The tool description now says so explicitly — a non-ready index means unknown, not absent.

Search takes its own branch through execute-tool.ts and never touches fileManageContract, which is why it was skipped in #7388. Resolution happens in the use case, so the v2 route inherits it.

2. file_edit and file_insert — in-place editing

file_edit(folderPath, fileName, oldString, newString) and file_insert(folderPath, fileName, afterLine, content).

oldString must match exactly once, or the edit is refused naming the line numbers each match sits on. Taking the first match rewrites an arbitrary line; replacing all of them rewrites lines the caller never saw. This is the same refusal we landed on append after .find() picking arbitrarily was a P1 twice running, and matches Letta's memory_replace and Anthropic's str_replace.

afterLine past the end is refused, not clamped — clamping turns an agent's off-by-one into a silent write to the wrong end of the file.

Architecture: the read-modify-write is a compound mutation, so it lives in one application use case (editWorkspaceFileContent) with the tool case and the v2 route as thin adapters, rather than being sequenced in a surface. It reuses files.update_content; an edit is a content update, and a new catalog entry would fragment the policy. Append inlines the same shape in operations.ts today; moving it onto this use case is a clean follow-up, deliberately not done here.

Concurrency: the Redis advisory lock plus expectedUpdatedAt CAS, exactly as append does. Deliberately contentUpdatedAt, not updatedAt — a rename or move bumps the latter and would fail an edit that raced nothing.

Binary guard (new): edits operate on stored bytes, never on parser-extracted text — extraction is one-way, so writing it back would replace a DOCX with a transcript of itself. Non-UTF-8 input is refused. Append has the same gap today (toString('utf-8') with no check); pre-existing and shipped, so it is flagged rather than changed inside a PR about new operations.

3. offset / limit on file_get_content

Applied per file, since a selection can be several files and one running offset across them would depend on an ordering the caller cannot see. Returns lineRanges with totalLines — without it a caller cannot tell a file that ended from a window that stopped early, the same absent-vs-unknown confusion as the search index.

Also: the workspace root was not addressable

parseFolderPath('/') returns [], and no folder row has an empty segment list, so folderPaths: ['/'] resolved as Folder not found: / on read, get_content, compress, and append — everything shipped in #7388. The UI hides it; the contract accepts it and an LLM will try it.

Fixed in resolveFolderIdsForPaths, reported as includeRootFiles rather than a sentinel in the id set, because the root is the absence of a folder id and a magic string would survive every type check then match nothing on reaching a SQL in (...).

This changes behaviour on four shipped operations (they error today, they return files after). Not needed by the driving use case — it is here only because Op 1 refactors the function carrying it. Happy to lift it into a follow-up if you'd rather.

V2

Route Notes
GET /api/v2/files/search new; no v2 content search existed
PATCH /api/v2/files/[fileId]/content new; PUT on the same path is whole-file replace, so PATCH is the partial counterpart
GET /api/v2/files/[fileId]/text gains offset/limit, joining the existing maxBytes

Where to spend review attention

  • file_edit is a new mutation primitive. Everything before it appended or replaced wholesale. The uniqueness refusal is the only thing between a sloppy oldString and silent corruption on an unattended nightly path.
  • Folder scoping is now a security boundary. lib/workspace-files/folder-path-selection.test.ts pins that /memory/user-a does not reach /memory/user-a-2 (shared prefix) or /memory/user-b, and never climbs to a parent.
  • Line counting is one shared rule (countLines). insert accepts exactly the range that search, a ranged read, and the post-edit count all report. An earlier draft counted the trailing newline as a line, which told an agent the file was one line longer than insert would take.

Fixed along the way

operations.test.ts mocked resolveWorkspaceFileReference with an object signature; the manager takes (workspaceId, reference) positionally, so the mock returned undefined for anything reaching that path. Nothing exercised it before. Corrected rather than worked around — same partial-mock trap that hid three P1s in #7388.

Verification

tsc clean · 45 audits · api-validation · client-boundary · biome · 12,596 tests.

Generated surfaces regenerated: integration docs, tool metadata, OpenAPI (29 file-audit operations, 215 total), CLI API + CLI docs.

Not yet done: browser E2E. Every P1 in #7388 was a disconnected wire that mocked tests cannot see. Running it against the real /memory/{userId} shape next.

@vercel

vercel Bot commented Sep 2, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
docs Ready Ready Preview Sep 2, 2026 5:58pm UTC

Request Review

@greptile-apps

greptile-apps Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR adds folder-scoped file-content search, exact in-place edit and line insertion operations, and per-file ranged text reads across workflow tools, v2 APIs, generated clients, and documentation.

  • Resolves folder paths at execution time and reports search-index coverage for the selected scope.
  • Adds CAS-protected, advisory-locked text edits with uniqueness, range, and UTF-8 validation.
  • Exposes line windows and total line counts through file tools and the v2 text endpoint.
  • Makes workspace-root selection addressable by representing root files separately from folder IDs.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
apps/sim/lib/workspace-files/application/edit-workspace-file-content.ts Introduces the authorized, locked read-modify-write use case for exact replacement and line insertion with optimistic concurrency checks.
apps/sim/lib/workspace-files/application/search-workspace-file-content.ts Adds runtime folder-scope resolution and passes the authorized workspace scope to both search matches and coverage reporting.
apps/sim/lib/workspace-files/search/repository.ts Applies workspace, folder, root-file, and recursive-scope predicates consistently to indexed matches and coverage queries.
apps/sim/lib/workspace-files/application/read-workspace-file-text.ts Adds per-file line slicing and range metadata while retaining the existing parsed-text read boundary.
apps/sim/app/api/v2/files/search/route.ts Exposes scoped content search through the v2 route and delegates workspace authorization to the authorized application use case.
apps/sim/lib/workspace-files/application/edit-workspace-file-content.test.ts Covers edit behavior with a valid typed session principal and an edit helper bound to the exported use-case union.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  Caller[Workflow tool or v2 client] --> Contract[Validated file operation contract]
  Contract --> Auth[Workspace authorization]
  Auth --> Scope[Resolve folder and root scope]
  Scope --> Search[Scoped indexed search]
  Auth --> Read[Read stored file content]
  Read --> Range[Return per-file line window]
  Read --> Edit[Validate UTF-8 and edit request]
  Edit --> Lock[Acquire advisory lock]
  Lock --> CAS[Persist with content timestamp CAS]
  CAS --> Result[Return updated line count]
Loading

Reviews (7): Last reviewed commit: "fix(files): keep multi-folder search ser..." | Re-trigger Greptile

Comment thread apps/sim/lib/workspace-files/application/edit-workspace-file-content.test.ts Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 38 files

Re-trigger cubic

Comment thread apps/sim/lib/workspace-files/edit-content.ts Outdated
Comment thread apps/sim/lib/api/contracts/v2/files.ts Outdated
Comment thread apps/sim/lib/api/contracts/tools/file.ts
Comment thread apps/sim/app/api/v2/files/search/route.ts Outdated
Comment thread apps/sim/blocks/blocks/file.ts Outdated
Comment thread apps/docs/openapi-v2-files-audit.json
Comment thread apps/sim/lib/workspace-files/application/edit-workspace-file-content.ts Outdated
Comment thread apps/sim/lib/workspace-files/application/edit-workspace-file-content.test.ts Outdated
Comment thread apps/docs/content/docs/integrations/file.mdx Outdated
Comment thread apps/docs/content/docs/cli/files.mdx Outdated
mzxchandra and others added 3 commits September 2, 2026 00:59
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
…ontent.test.ts

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
@mzxchandra

Copy link
Copy Markdown
Contributor Author

@greptile

@mzxchandra

Copy link
Copy Markdown
Contributor Author

@cubic review

@cubic-dev-ai

cubic-dev-ai Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

@cubic review

@mzxchandra I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review completed against the latest diff

Re-trigger cubic

Comment thread apps/sim/tools/file/search.ts Outdated
Comment thread apps/sim/lib/api/contracts/v2/files.ts
Comment thread apps/sim/blocks/blocks/file.ts Outdated
Comment thread apps/sim/lib/internal/file/operations.ts Outdated
Comment thread apps/sim/lib/internal/file/operations.ts
Comment thread apps/docs/content/docs/cli/reference.mdx
Comment thread apps/sim/lib/folders/scope.ts
Comment thread apps/sim/lib/api/contracts/v2/files.ts Outdated
…o feat/file-memory-ops

# Conflicts:
#	apps/sim/lib/workspace-files/application/workspace-file-folders.test.ts

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed

Fix all with cubic | Re-trigger cubic

Comment thread apps/sim/lib/api/contracts/tools/file.ts Outdated
@mzxchandra

Copy link
Copy Markdown
Contributor Author

@greptile

@mzxchandra

Copy link
Copy Markdown
Contributor Author

@cubic review

@cubic-dev-ai

cubic-dev-ai Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

@cubic review

@mzxchandra I have started the AI code review. It will take a few minutes to complete.

@mzxchandra

Copy link
Copy Markdown
Contributor Author

@greptile

@mzxchandra

Copy link
Copy Markdown
Contributor Author

@cubic review

@cubic-dev-ai

cubic-dev-ai Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

@cubic review

@mzxchandra I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 41 files

Fix all with cubic | Re-trigger cubic

Comment thread apps/sim/lib/api/contracts/v2/openapi/files-audit.ts
Comment thread apps/sim/lib/workspace-files/application/edit-workspace-file-content.ts Outdated
Comment thread apps/sim/blocks/blocks/file.ts
Comment thread apps/sim/lib/api/contracts/v2/files.ts Outdated
@mzxchandra

Copy link
Copy Markdown
Contributor Author

@greptile

@mzxchandra

Copy link
Copy Markdown
Contributor Author

@cubic review

@cubic-dev-ai

cubic-dev-ai Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

@cubic review

@mzxchandra I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 41 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

You've manually re-run cubic several times on this PR. Each manual re-review checks the full PR again and counts toward your usage quota. To preserve your usage limits, we recommend letting cubic automatically review new commits.

Re-trigger cubic

@mzxchandra

Copy link
Copy Markdown
Contributor Author

@greptile

@mzxchandra

Copy link
Copy Markdown
Contributor Author

@cubic review

@cubic-dev-ai

cubic-dev-ai Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

@cubic review

@mzxchandra I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 41 files

You've manually re-run cubic several times on this PR. Each manual re-review checks the full PR again and counts toward your usage quota. To preserve your usage limits, we recommend letting cubic automatically review new commits.

Fix all with cubic | Re-trigger cubic

Comment thread apps/sim/lib/api/contracts/v2/files.ts
Comment thread apps/sim/lib/api/contracts/v2/openapi/files-audit.ts Outdated
Comment thread apps/docs/openapi-v2-files-audit.json Outdated
@mzxchandra

Copy link
Copy Markdown
Contributor Author

@greptile

@mzxchandra

Copy link
Copy Markdown
Contributor Author

@cubic review

@cubic-dev-ai

cubic-dev-ai Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

@cubic review

@mzxchandra I have started the AI code review. It will take a few minutes to complete.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant