Sagents.FileSystem.FileSystemState (Sagents v0.8.0-rc.7)
Copy MarkdownState management for the FileSystem.
This module handles all state transitions for the virtual filesystem. File entries are stored in an in-memory map within the GenServer state.
Summary
Functions
Deletes a file from the filesystem.
Check if a file exists in the filesystem.
Flushes all pending debounce timers by persisting files synchronously.
Lists all file entries in the filesystem (without loading content).
Lists all file paths in the filesystem.
Loads a file's content from persistence into ETS.
Moves a file or directory (and its children) from one path to another.
Creates a new FileSystemState.
Persists a file to storage (called when debounce timer fires).
Reads a file entry from the filesystem state.
Registers file entries in the filesystem.
Registers a new persistence configuration.
Reset the filesystem to pristine persisted state.
Computes filesystem statistics.
Writes a file to the filesystem.
Types
@type t() :: %Sagents.FileSystem.FileSystemState{ debounce_timers: %{required(String.t()) => reference()}, files: %{required(String.t()) => Sagents.FileSystem.FileEntry.t()}, persistence_configs: %{ required(String.t()) => Sagents.FileSystem.FileSystemConfig.t() }, publisher: Sagents.Publisher.State.t(), scope_key: term() }
Functions
Deletes a file from the filesystem.
Returns {:ok, new_state} or {:error, reason, state}.
Check if a file exists in the filesystem.
Examples
iex> FileSystemState.file_exists?(state, "/notes.txt")
true
iex> FileSystemState.file_exists?(state, "/nonexistent.txt")
false
Flushes all pending debounce timers by persisting files synchronously.
Returns updated state with cleared timers.
@spec list_entries(t()) :: [Sagents.FileSystem.FileEntry.t()]
Lists all file entries in the filesystem (without loading content).
Returns entries with metadata but content NOT loaded — suitable for building
sidebar trees or LLM list_files tool responses.
Lists all file paths in the filesystem.
Returns paths for both memory and persisted files, regardless of load status.
Parameters
state- Current FileSystemState
Examples
iex> FileSystemState.list_files(state)
["/file1.txt", "/Memories/file2.txt"]
Loads a file's content from persistence into ETS.
Called by FileSystemServer when a file needs to be lazy-loaded. If the file is already loaded or is memory-only, returns {:ok, state} without changes.
Returns
{:ok, state}- File loaded successfully (or already loaded){:error, reason, state}- Failed to load from persistence
@spec move_file(t(), String.t(), String.t()) :: {:ok, [Sagents.FileSystem.FileEntry.t()], t()} | {:error, term(), t()}
Moves a file or directory (and its children) from one path to another.
This is an atomic re-key operation that does not trigger delete_from_storage
or create new entries. Instead, it:
- Re-keys entries in the files map from old path to new path
- Updates the
pathfield on each entry - Transfers any pending debounce timers to the new paths
- Calls the optional
move_in_storage/3persistence callback so backends can update their path references - If the backend doesn't implement
move_in_storage/3, marks entries asdirty_non_contentso the next persist cycle pushes the changes
Returns {:ok, moved_entries, new_state} or {:error, reason, state}.
Creates a new FileSystemState.
Options
:scope_key- Scope identifier (required) - Can be any term that uniquely identifies the scope- Tuple:
{:user, 123},{:agent, uuid},{:project, id} - UUID:
"550e8400-e29b-41d4-a716-446655440000" - Database ID:
12345or"12345"
- Tuple:
:configs- List of FileSystemConfig structs (optional, default: [])
Persists a file to storage (called when debounce timer fires).
Returns updated state.
@spec read_file(t(), String.t()) :: {:ok, Sagents.FileSystem.FileEntry.t()} | {:error, :enoent}
Reads a file entry from the filesystem state.
Parameters
state- Current FileSystemStatepath- The file path to read
Returns
{:ok, entry}- File entry found{:error, :enoent}- File not found
@spec register_files(t(), [Sagents.FileSystem.FileEntry.t()]) :: {:ok, t()}
Registers file entries in the filesystem.
This is useful for pre-populating the filesystem with file metadata without loading content. For example, used by tests or for in-memory only files.
Parameters
state- Current FileSystemStatefile_entries- List of FileEntry structs to register
Returns
{:ok, new_state}on success
Examples
iex> {:ok, entry} = FileEntry.new_memory_file("/scratch/temp.txt", "data")
iex> {:ok, new_state} = FileSystemState.register_files(state, [entry])
@spec register_persistence(t(), Sagents.FileSystem.FileSystemConfig.t()) :: {:ok, t()} | {:error, term()}
Registers a new persistence configuration.
When a persistence config is registered, this function calls the persistence module's
list_persisted_files/2 callback to discover existing files and adds them to the
filesystem with loaded: false (lazy loading).
Parameters
state- Current FileSystemStateconfig- FileSystemConfig to register
Returns
{:ok, new_state}on success{:error, reason}if base_directory already registered
Examples
iex> config = FileSystemConfig.new!(%{
...> base_directory: "user_files",
...> persistence_module: MyApp.Persistence.Disk
...> })
iex> {:ok, new_state} = FileSystemState.register_persistence(state, config)
Reset the filesystem to pristine persisted state.
This clears:
- All memory-only files (completely removed)
- All in-memory modifications to persisted files (discarded)
- All dirty flags (no persistence of pending changes)
- All debounce timers (pending writes cancelled)
Then re-indexes all persisted files from storage backends, ensuring:
- Fresh metadata from storage (picks up any external changes)
- Files marked as unloaded (will lazy-load on next access)
- Latest list of persisted files (includes files created during execution)
Uses the existing index_persisted_files/1 code path for consistency.
Returns
Updated state with reset filesystem.
Examples
iex> state = FileSystemState.reset(state)
Computes filesystem statistics.
@spec write_file(t(), String.t(), String.t(), keyword()) :: {:ok, Sagents.FileSystem.FileEntry.t(), t()} | {:error, term(), t()}
Writes a file to the filesystem.
For existing files, preserves existing metadata (custom, created_at, mime_type) and only updates content-related fields. For new files, creates a fresh entry.
Returns {:ok, entry, new_state} or {:error, reason, state}.