Sagents.FileSystemCallbacks behaviour (Sagents v0.8.0-rc.4)

Copy Markdown

Behavior for file system persistence callbacks.

Implement this behavior to provide custom persistence for filesystem operations. All callbacks are optional — implement only what you need.

Scope-first contract

Every callback takes the integrator's scope struct as its first positional argument.

Example Implementation

defmodule MyApp.FilesystemPersistence do
  @behaviour Sagents.FileSystemCallbacks

  @impl true
  def on_write(%MyApp.Accounts.Scope{user: user}, file_path, content, _context) do
    case MyApp.Files.create_or_update(user.id, file_path, content) do
      {:ok, file} -> {:ok, %{id: file.id}}
      {:error, reason} -> {:error, reason}
    end
  end

  @impl true
  def on_read(%MyApp.Accounts.Scope{user: user}, file_path, _context) do
    case MyApp.Files.get(user.id, file_path) do
      nil -> {:error, :not_found}
      file -> {:ok, file.content}
    end
  end

  @impl true
  def on_delete(%MyApp.Accounts.Scope{user: user}, file_path, _context) do
    case MyApp.Files.delete(user.id, file_path) do
      {:ok, _} -> {:ok, %{}}
      {:error, reason} -> {:error, reason}
    end
  end

  @impl true
  def on_list(%MyApp.Accounts.Scope{user: user}, _context) do
    files = MyApp.Files.list_for_user(user.id)
    {:ok, Enum.map(files, & &1.path)}
  end
end

Summary

Callbacks

Called when a file is deleted.

Called to list all files in persistent storage.

Called when a file is read.

Called when a file is created or overwritten.

Types

content()

@type content() :: String.t()

context()

@type context() :: map()

file_path()

@type file_path() :: String.t()

result()

@type result() :: {:ok, term()} | {:error, term()}

Callbacks

on_delete(scope, file_path, context)

(optional)
@callback on_delete(scope :: term() | nil, file_path(), context()) :: result()

Called when a file is deleted.

Parameters

  • scope - Integrator-defined scope struct (or nil)
  • file_path - Path of the file being deleted
  • context - Filesystem-specific fields

Returns

  • {:ok, metadata} - Success
  • {:error, reason} - Failure reason

on_list(scope, context)

(optional)
@callback on_list(scope :: term() | nil, context()) ::
  {:ok, [file_path()]} | {:error, term()}

Called to list all files in persistent storage.

Optional — if not implemented, only in-memory files are listed.

Parameters

  • scope - Integrator-defined scope struct (or nil)
  • context - Filesystem-specific fields

Returns

  • {:ok, [file_path]} - List of file paths
  • {:error, reason} - Failure reason

on_read(scope, file_path, context)

(optional)
@callback on_read(scope :: term() | nil, file_path(), context()) ::
  {:ok, content()} | {:error, term()}

Called when a file is read.

If this callback is implemented, it will be called BEFORE checking the in-memory state. This enables lazy-loading from persistent storage.

Parameters

  • scope - Integrator-defined scope struct (or nil)
  • file_path - Path of the file being read
  • context - Filesystem-specific fields

Returns

  • {:ok, content} - File content from storage
  • {:error, :not_found} - File doesn't exist in storage
  • {:error, reason} - Other error

on_write(scope, file_path, content, context)

(optional)
@callback on_write(scope :: term() | nil, file_path(), content(), context()) :: result()

Called when a file is created or overwritten.

Parameters

  • scope - Integrator-defined scope struct (or nil). Use to filter DB writes.
  • file_path - Path of the file being written
  • content - Full content of the file
  • context - Filesystem-specific fields (agent_id, session_id, etc.)

Returns

  • {:ok, metadata} - Success, optionally with metadata
  • {:error, reason} - Failure reason