Changelog
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[0.3.0] - 2026-05-18
Removed
Phronomy::Memorymodule fully removed:ConversationManager, allStoragebackends (InMemory, ActiveRecord), allRetrievalstrategies (Recent, Semantic, Composite), and allCompressionhelpers (ToolOutputPruner, Summary) have been deleted. Conversation history is now the responsibility of the calling application — pass prior messages viaconfig[:messages](Array<RubyLLM::Message>) and receive the updated array inresult[:messages].Phronomy::StateStoremodule fully removed:InMemory,ActiveRecord,Redis, andFileSystemstate-store backends have been deleted. The Workflow halted-state object is now returned directly frominvokeandsend_eventand must be stored by the caller if resumption is needed.Phronomy::Configuration#default_state_storeremoved: No longer meaningful without a built-in state store.Phronomy::Configuration#default_memory/#memory_async/#memory_job_queueremoved: No longer meaningful without the Memory module.- Rails integration removed:
Railtieinitializers forAgentJobandacts_as_phronomy_messageno longer load. Therails/andactive_record/directories have been deleted. Phronomy::ActorandPhronomy::ThreadActorRegistrydeleted: The Active Object pattern implementation (actor.rb,thread_actor_registry.rb) has been removed. It provided synchronous blocking only (no true async) and was architecturally inconsistent with theWorkflowRunnerhalt/resume model. All thread coordination now uses plainMutexwhere needed.Phronomy.configuration.max_actorsremoved: The configuration option is no longer meaningful withoutThreadActorRegistry.
Changed
Agent::Base#invokeand#streamno longer route execution through a per-thread Actor. Both methods now call_invoke_impl/_stream_impldirectly on the calling thread.Memory::Storage::InMemorynow stores all thread data in an instance-levelHashinstead ofThread.currentthread-local storage. The class-levelTHREAD_DATA_KEYconstant has been removed.with_thread_lockuses a per-thread-idMutexto preserve concurrent-compaction safety (issue #44).StateStore::InMemorynow stores state in an instance-levelHash. TheTHREAD_DATA_KEYconstant has been removed.VectorStore::RedisSearchuses aMutexforensure_index!andclearinstead of an Actor, preserving the thread-safety invariant on@index_created.Tool::McpTool::StdioTransport,Tracing::LangfuseTracer,TrustPipeline, andMemory::Retrieval::Semanticno longer hold a dedicated Actor instance. All operations execute directly on the calling thread.PIIPatternDetector—:my_numberreplaced by:ssn([#77]): The built-in PII detector now checks for US Social Security Numbers (\b\d{3}-\d{2}-\d{4}\b) instead of Japanese My Numbers. The JIS X 0076 check-digit validation andmy_number_valid?helper have been removed. Category key renamed from:my_numberto:ssn.PIIPatternDetector— phone pattern updated to international format ([#77]): The:phonepattern now matches 3-digit area code + 3–4-digit exchange + 4-digit subscriber number with optional E.164 country-code prefix ((?:\+\d{1,3}[.\- ]?)?\(?\d{3}\)?[.\- ]?\d{3,4}[.\- ]?\d{4}\b), replacing the previous Japan-specific pattern.
Fixed
RubyLLM::Providers::OpenAI#handle_error_chunk—NoMethodErroron single-line SSE error chunks: Some models (e.g. Qwen running via LM Studio) return SSE error events as a single line (data: {...}) without a precedingevent:line. The upstream implementation calledchunk.split("\n")[1].delete_prefix(...), which raisedNoMethodError: undefined method 'delete_prefix' for nilwhen the second element was absent. A monkey-patch inlib/phronomy/ruby_llm_patches.rbguards against this by returning an empty string when the split result has fewer than two elements.README— stale Memory API examples ([#76]): All references to the non-existentWindowMemory,ActiveRecordMemory,SemanticMemoryclasses andload_messages/memory_compressionAPI have been replaced with the correctConversationManager-based API.README—PIIPatternDetectorcomment ([#77]): Inline comment updated to# Detect SSNs, credit cards, emails, and phone numbers.README— Configuration block markdown ([#80]): Themax_actorsNote block was incorrectly placed inside the Ruby code fence; moved outside so it renders as a blockquote.README—Guardrailsstability label ([#76]): Changed fromStabletoBetato reflect that the built-in detector patterns may evolve.CHANGELOG— stale entries ([#78]): Removed the orphaned[Unreleased]section describing a never-released API, and replaced a forward"As of 0.3.0"reference with future-tense wording.McpTool— YARD class comment ([#79]): Updated to document both thestdio://andhttp:///https://transport schemes.README—max_actorsconfiguration reference ([#80]): Addedc.max_actorsexample and LRU eviction note to the Configuration section.
[0.2.2] - 2026-05-17
Fixed
Tool::Basetype validation — strict mode (#73): Removed string-coercion pass-through for:integer,:number/:float, and:booleanparameters. AStringvalue such as"42"now correctly raises a type error regardless of theon_schema_errormode. Fixes silent data corruption where the raw string was forwarded toexecuteinstead of the expected numeric/boolean type.README— correctsend_eventAPI example (#69): Fixed code sample that calledapp.send_event(:approve, config: { thread_id: ... })(positional args) which raisesArgumentErrorat runtime. Corrected toapp.send_event(state: state, event: :approve).phronomy.gemspec— excludevendor/from gem package (#70):vendor/bundle(~3 500 files, ~14 MB) was included in released gems. Added"vendor/"to the file reject list.
Added
Phronomy::Configuration#max_actors(#72): New optional attribute (defaultnil= unlimited, backward-compatible). When set,ThreadActorRegistryenforces an LRU eviction policy: the least-recently-used actor is stopped and removed before a new one is created, preventing unbounded thread growth in long-running processes.README— feature stability table (#71): Features section now uses a table with Stable / Beta / Experimental labels so users can assess maturity at a glance.TrustPipeline::Result#citations— unverified-source warning (#74): YARD documentation now explicitly states that citations are extracted from the LLM's own output and have not been verified against any external source.
CI
- Ruby 3.4 added to CI matrix (#75): Aligns test coverage with the gemspec
requirement (
>= 3.2.0) and verifies compatibility with the current stable Ruby release.
[0.2.1] — Unreleased
Changed
WorkflowRunner— state_machines fully drives execution (architecture overhaul). Previouslystate_machineswas used only for post-hoc transition validation; the next-node was calculated by Phronomy internally (resolve_next_node). After this change, all state transition decisions — including guard evaluation for routing events — will be delegated entirely tostate_machines.PhaseTrackernow exposesattr_accessor :contextso guard lambdas can access theWorkflowContextviam.context.- Guard bridge pattern:
if: ->(m) { guard_proc.call(m.context) }. - Three event types registered per workflow:
advance_<from>— unconditional after-transitions<routing_event>— guarded branching from action states (name is the event name used in the DSL, e.g.:route,:route_review)<external_event>— human-in-the-loop triggers from wait states- Invalid transitions now raise
ArgumentErrorinstead of logging warnings.
WorkflowRunnerinitializer signature changed —edges:,conditional_edges:, andwait_states:replaced byafter_transitions:,route_transitions:,external_events:, andwait_state_names:. This is an internal-only change; the publicPhronomy::Workflow.defineDSL is unchanged.
Removed (internal)
WorkflowRunner#resolve_next_node— logic moved to state_machinesWorkflowRunner#advance_phase— replaced byfire_event!Workflow::Builder#build_edges,#build_conditional_edges,#build_wait_states— replaced by unified event classification inbuild
[0.2.0] - 2026-05-13
Added
Phronomy::Graph::WorkflowRunner— state_machines-based execution engine (introduced as the internal successor toCompiledGraph).state.phase— single source of truth for graph execution state (replacescurrent_nodes+halted_beforedual attributes).state.halted?— returnstruewhen the graph is paused.CompiledGraph#add_wait_state— declared a named wait state that halts automatically when reached (later superseded bywait_stateDSL inWorkflow.define).CompiledGraph#send_event(state:, event:, input: nil)— event-driven resume API (later superseded byapp.send_event).
Removed
ParallelNodeandadd_parallel_nodeDSL. UseThread.neworConcurrent::Futureat the application level instead.Phronomy::Graph::TimeoutError(was only used byParallelNode).