Changelog
Copy Markdownv0.4.0
Major FileSystem API expansion with directory entries, richer FileEntry struct, file move/rename, metadata-only persistence optimization, and a clearer API surface. Also adds tool_context for caller-supplied data in tools, MessagePreprocessor for display/LLM message splitting, and improved middleware messaging.
Breaking changes — see Upgrading section below.
Upgrading from v0.3.1
FileEntry field renames:
FileEntry.dirty→FileEntry.dirty_contentFileEntry.dirty_metadata→FileEntry.dirty_non_content
API renames:
FileSystemState.update_metadata/4→update_custom_metadata/4(no longer accepts:titleopt — useupdate_entry/4for title changes)FileSystemServer.update_metadata/4→update_custom_metadata/4Persistence.list_persisted_files/2→list_persisted_entries/2(now returns[%FileEntry{}]instead of[path_string])
Return type changes:
FileSystemServer.write_file/4returns{:ok, %FileEntry{}}instead of:okFileSystemServer.read_file/2returns{:ok, %FileEntry{}}instead of{:ok, content_string}FileSystemState.write_file/4returns{:ok, entry, state}instead of{:ok, state}
Added
- Directory entries as first-class
FileEntrywithentry_type: :directory, automaticmkdir -pancestor creation, andnew_directory/2constructor #34 title,id, andfile_typefields onFileEntryfor richer file metadata #34FileEntry.update_entry_changeset/2— changeset for safe entry-level field updates (title, id, file_type) #39update_entry/4onFileSystemStateandFileSystemServer— updates entry-level fields via changeset #39update_custom_metadata/4onFileSystemStateandFileSystemServer— replacesupdate_metadata/4with a clearer name scoped tometadata.custom#39list_entries/1onFileSystemStateandFileSystemServer— returns all entries with synthesized directories for tree UIs #34create_directory/3onFileSystemStateandFileSystemServer#34move_file/3onFileSystemStateandFileSystemServer— atomically moves a file or directory (and its children) to a new path, re-keying entries and transferring debounce timers #39move_in_storage/3optional callback onPersistencebehaviour — persistence backends can implement this to handle path changes efficiently #39update_metadata_in_storage/2optional callback onPersistencebehaviour — efficient metadata-only updates without rewriting file content #38dirty_non_contentflag onFileEntry— tracks non-content changes separately from content changes, enabling metadata-only persistence optimization #38, #39persist_file/2routes toupdate_metadata_in_storagewhen only non-content fields changed and the backend supports it, falling back towrite_to_storageotherwise #38default: trueoption onFileSystemConfig— catch-all config for path-agnostic persistence backends (e.g. database), specific configs take priority #33- Configurable
entry_to_mapoption on FileSystem middleware — controls how entries are serialized to JSON for LLM tool results, withdefault_entry_to_map/1fallback #34 tool_contextfield onAgent— caller-supplied map (user IDs, tenant info, scopes) merged intoLLMChain.custom_contextfor tool functions #35Sagents.MessagePreprocessorbehaviour — intercepts messages in AgentServer to produce separate display and LLM versions, enabling rich reference expansion (e.g.@ProjectBrief→ full content for LLM, styled chip for UI) #37notify_middleware/3onAgentServer— renamed fromsend_middleware_message/3to better reflect its general-purpose notification role (deprecated wrapper retained for backwards compatibility) #36- FileSystem setup guide documentation #32
- Middleware messaging documentation rewrite covering external notification and async task patterns #36
Changed
- BREAKING:
FileEntry.dirtyfield renamed todirty_content#39 - BREAKING:
update_metadata/4renamed toupdate_custom_metadata/4on bothFileSystemStateandFileSystemServer#39 - BREAKING:
FileSystemServer.write_file/4returns{:ok, %FileEntry{}}instead of:ok#34 - BREAKING:
FileSystemServer.read_file/2returns{:ok, %FileEntry{}}instead of{:ok, content_string}#34 - BREAKING:
FileSystemState.write_file/4returns{:ok, entry, state}instead of{:ok, state}#34 - BREAKING:
Persistence.list_persisted_files/2renamed tolist_persisted_entries/2, returns[%FileEntry{}]instead of[path_string]#34 - Non-content updates (
update_custom_metadata,update_entry) persist immediately by default; passpersist: :debounceto opt into debounced persistence #39 - New persisted files persist immediately on creation; only subsequent content updates are debounced #34
- FileSystem middleware
lstool now returns JSON array of entry maps instead of path strings #34 - Updated code generator templates to thread
tool_contextandmessage_preprocessorthrough Coordinator and Factory #35, #37 - Documentation examples updated to use latest Anthropic model names #32
Fixed
FileEntry.update_content/3now resetsdirty_non_contenttofalse, preventing a data loss scenario where a metadata update followed by a content write would incorrectly route toupdate_metadata_in_storageand lose the content change #38
v0.3.1
Fixed
- Horde dependency is now truly optional. Projects using the default
:localdistribution mode no longer require:hordeto be installed for compilation to succeed. Previously,use Horde.Registryanduse Horde.DynamicSupervisorin the Horde implementation modules caused compile-time failures even when Horde was declared as optional #27
v0.3.0
Adds structured agent completion (until_tool), interruptible tools for improved HITL workflows, middleware-based observability callbacks, and custom execution modes. Requires LangChain ~> 0.6.1.
Added
until_tooloption for structured agent completion — agents loop until a specific target tool is called, returning the tool result as a 3-tuple{:ok, state, %ToolResult{}}. Works with bothAgent.execute/3and SubAgent, including HITL interrupt/resume cycles #3callbacks/1optional behaviour callback onMiddleware— middleware can now declare LangChain-compatible callback handler maps for observability (OpenTelemetry, metrics, etc.), composable and self-contained within middleware #6Middleware.get_callbacks/1andMiddleware.collect_callbacks/1for extracting and aggregating middleware callback maps #6modefield onAgent— allows specifying a customLLMChain.Modeimplementation instead of the defaultSagents.Modes.AgentExecution#17- Tool interruption and resumption at the base Agent level, fixing SubAgent interrupt/resume flows #24
Mode.Steps.continue_or_done_safe/4— enforces theuntil_toolcontract by returning an error if the LLM stops without calling the target tool #3- Observability guide documentation #19
- Middleware documentation #24
- Detection and warning when agents use built-in lower-level LangChain run modes that bypass Sagents HITL/state propagation #3
Changed
- SubAgent execution refactored from custom
execute_chain_with_hitl/2to unifiedLLMChain.run/2viaAgentExecutionmode — same pipeline as Agent #3 AgentServer.execute_agent/2andresume_agent/2now combine PubSub callbacks with middleware callbacks and handle 3-tuple returns fromAgent.execute/3#6, #3build_llm_callbacksrenamed tobuild_pubsub_callbacksto clarify its purpose #6- Requires
langchain ~> 0.6.1(up from~> 0.5.3) for interruptible tool support #24 - Updated
mix sagents.setuptemplate generators for new patterns #24
Fixed
AgentServer.agent_info/1crashing withKeyError: key :messages not found— now usesget_state/1instead ofexport_state/1#25
v0.2.1
Agent execution now uses LangChain's new customizable run mode system. The duplicated execution loops in Agent (execute_chain_with_state_updates and execute_chain_with_hitl) have been replaced by a single composable mode — Sagents.Modes.AgentExecution — built from pipe-friendly step functions.
Added
Sagents.Modes.AgentExecution— custom LLMChain execution mode that composes HITL interrupt checking, tool execution, and state propagation into a single pipelineSagents.Mode.Steps— reusable pipe-friendly step functions for building custom execution modes:check_pre_tool_hitl/2— checks tool calls against HITL policy before executionpropagate_state/2— merges tool result state deltas into the chain's custom context
- GitHub Actions CI workflow for automated testing on push and PRs #14
Changed
Agent.execute_chain/3now delegates toSagents.Modes.AgentExecutionviaLLMChain.run/2instead of maintaining separate execution loops for HITL and non-HITL agents — removed ~160 lines of duplicated loop logic fromAgent- Requires
langchain ~> 0.5.3forLLMChain.execute_step/1and theModebehaviour
Fixed
- HITL
process_decisions/3now validates that each decision is a map, returning a clear error instead of crashing the AgentServer GenServer #4
v0.2.0
Cluster-aware release with optional Horde-based distribution. Agents can now run across a cluster of nodes with automatic state migration, or continue running locally on a single node (the default).
Breaking changes: The Sagents OTP application (Sagents.Application) has been removed. Applications must now add Sagents.Supervisor to their own supervision tree. PubSub events are now wrapped in {:agent, event} tuples. Agent state persistence has moved from the Coordinator to the AgentServer via new behaviour modules.
Upgrading from v0.1.0 to v0.2.0
Supervision tree change: Replace any reliance on the automatic Sagents.Application startup with an explicit child in your application's supervision tree:
children = [
# ... your other children (Repo, PubSub, etc.)
Sagents.Supervisor
]PubSub event format change: All PubSub events broadcast by AgentServer are now wrapped in {:agent, event} tuples. Update your handle_info clauses:
# Before (v0.1.0)
def handle_info({:status_changed, status, data}, socket), do: ...
# After (v0.2.0)
def handle_info({:agent, {:status_changed, status, data}}, socket), do: ...Persistence ownership change: Agent state and display message persistence is now owned by the AgentServer itself via optional behaviour modules (Sagents.AgentPersistence and Sagents.DisplayMessagePersistence). The Coordinator no longer handles persistence directly.
Re-run the setup generator: Commit your current code to version control first, then re-run mix sagents.setup to regenerate updated templates for the new supervision tree and persistence modules. Review the diffs to keep any customizations you've made.
Added
- Cluster-aware distribution with optional Horde support — configure
config :sagents, :distribution, :hordeto enable, defaults to:local Sagents.Supervisor— single-line supervisor for adding Sagents to your application's supervision treeSagents.ProcessRegistry— abstraction overRegistryandHorde.Registry, switches backend based on distribution configSagents.ProcessSupervisor— abstraction overDynamicSupervisorandHorde.DynamicSupervisorSagents.Horde.ClusterConfig— cluster member discovery, regional clustering for Fly.io, and configuration validationSagents.AgentPersistencebehaviour — optional callback module for persisting agent state snapshots at key lifecycle points (completion, error, interrupt, shutdown, title generation)Sagents.DisplayMessagePersistencebehaviour — optional callback module for persisting display messages and tool execution status updatesAgentServer.agent_info/1— get detailed info about a running agent (pid, status, state, message count)AgentServer.list_running_agents/0,list_agents_matching/1,agent_count/0— agent discovery and enumerationAgentServer.get_metadata/1— metadata about an agent including node info- Node transfer events:
{:agent, {:node_transferring, data}}and{:agent, {:node_transferred, data}}broadcast during Horde redistribution AgentSupervisor.start_link_sync/1— synchronous startup that waits for AgentServer to be registered before returning- Horde dependency (
~> 0.10) added for cluster support - Cluster integration tests for node transfer and redistribution scenarios
Changed
- Breaking: Removed
Sagents.Application— Sagents no longer starts its own OTP application; applications must addSagents.Supervisorto their supervision tree - Breaking: All PubSub events now wrapped in
{:agent, event}tuples for easier pattern matching and routing - Breaking: Agent state and display message persistence moved from Coordinator to AgentServer via behaviour modules
- AgentServer tracks
restoredflag to detect Horde migrations and broadcasts transfer events - AgentServer includes presence tracking with real-time status and node metadata updates
- Updated
mix sagents.setupgenerator templates for new supervision tree setup and persistence behaviours mix precommitnow includes cluster integration tests
v0.1.0
Initial release published to hex.pm.