refactor: revert plugin-trait machinery, keep reversible effects + Arc-tool optimization + OSS base - #1
Merged
Merged
Conversation
Add funera_core::plugin::Plugin (name/inject/provides/apply) with
InstanceState + PluginInstance, and make Tool, ChatProvider,
InspectorMiddleware, and MutatorMiddleware subtraits of it.
Migration is backward-compatible: each capability type only adds an
impl Plugin { fn name() } block (or the impl_plugin! macro);
ame()
moves up to Plugin. Re-export Plugin from funera-orchestrate.
Not compile-verified: sandbox blocks crates.io HTTPS (SEC_E_NO_CREDENTIALS).
Add a shared service table (coeffect context, TypeId-keyed) and an effect accumulator (disposers, LIFO) to FuneraEnv, with: - effect(): register a reversible effect (body runs now, returns its inverse) - provide()/get()/contains(): typed service provision and resolution - dispose(): run all disposers in reverse registration order 5 unit tests cover provide/get roundtrip, dispose-driven removal, LIFO effect ordering, and dispose idempotence.
Make each FuneraEnv own its effect accumulator (disposers) while sharing the service table, add derive() for child envs, and add a ServiceObserver notification primitive (on_service_change). Add PluginRegistry: mounts plugins as PluginInstances on derived envs and drives their lifecycle reactively via a fixpoint refresh — activating Pending instances whose inject requirements are met, deactivating Active instances whose requirements are lost, rolling back partial effects on apply failure, and reverting effects on unmount. 6 tests cover pending-until-satisfied, provider-satisfies-dependent, removal-deactivates-dependent, unmount-reverts-effects, failed-apply rollback, and the service-change observer.
Add funera_core::loader::{PluginEntry, Loader}. PluginEntry describes one
desired plugin (id, plugin, disabled, revision); Loader::reconcile diffs
the desired set against the current one and applies minimal mount/unmount
operations — unmounting vanished/disabled/changed-revision entries and
mounting new ones. A changed revision is a hot replacement: the old
instance's effects are reverted and a fresh instance is mounted.
6 tests cover mount, idempotence, removal, disabled entries, revision
reload, and effect reversal on reload.
Cover FuneraEnv/FuneraEnvWatcher methods that had no funera-core-level tests: set_model/model/watch_model, set_client/has_client_changed, model_changed/client_changed (async), add/remove/set_tool_availability tools, add/activate/deactivate/remove skills, skill prompt plumbing, and with_sandbox_policy (add a sandbox_policy() getter to observe the previously set-only field). +17 tests; all pass under --all-features.
- assert the actual tool/skill registry field (not just the watcher snapshot) in with_tool_registry/with_skill_registry, catching the 'delete field' mutations - rewrite the async *_changed tests to verify they BLOCK when no change is pending (50ms timeout), catching 'return Ok(())' mutations env.rs mutation score: 64 mutants -> 51 caught, 13 unviable, 0 missed.
- README: add 'Plugin architecture' section (Plugin trait, capability layer, PluginRegistry, Loader/HMR); fix the Custom tool example for the Plugin supertrait; update project structure - funera_core lib docs: add loader/plugin module rows - re-export PluginRegistry/Loader/PluginEntry from funera-orchestrate - add Loader::entry_state (by entry id) with a unit test - new example funera-orchestrate/examples/plugin_architecture.rs: reactive activation, deactivation on provider removal, and hot reload, all assertion-checked without an LLM
Gate nono (Landlock, MSRV 1.95) behind the sandbox feature; declare rust-version 1.88 (let-chains require 1.88); add a CI job checking the default build on 1.88.
CONTRIBUTING, CoC 3.0, SECURITY, CHANGELOG, issue/PR templates, CODEOWNERS, .editorconfig, README badges + Contributing.
…ools/skills as plugins
…oader; add replace_core_tool example
…c-tool optimization
The unified Plugin abstraction overreached and broke the clean trait-based
architecture of main. Revert the core to plain extensible traits and keep
only the two things worth keeping from the experiment:
- Reversible effects (FuneraEnv::effect / dispose): register a side effect
with its inverse; dispose() runs all inverses in reverse (LIFO) order,
idempotently and panic-isolated. EnvActor now calls dispose() automatically
when the runtime is dropped, so registrations never leak memory or services.
- Arc-based tool registry with lock-free execution (get_tool_arc, cloned
guarded registry) and remove_tool_if_same as the leak-safe inverse of
add_tool for a disposer.
Removed: plugin.rs + plugin/{adapters,broker,instance,registry}, loader.rs +
loader/config, env/key.rs typed-service layer, MiddlewareProcessor type
erasure, AgentLoop-as-plugin (loop.rs), ServiceBroker, plugin reconciliation
in runtime/env_actor, and the six plugin examples.
Also fixes pre-existing main defects: integration.rs did not compile (send
handle semantics, AgentEvent::Text, missing provider generic), clippy lints
under -D warnings, and an unused import.
Replace the plugin narrative with the real architecture (actor-based runtime, trait-based extensibility) plus a new 'Reversible effects' section; swap concepts/plugin.md for concepts/effects.md; rewrite env.md and architecture.md; drop agent-loop/service-broker pages; update SUMMARY/getting-started/examples index; document the reversible-effects keep and plugin removal in CHANGELOG; drop stale plugin references from CONTRIBUTING/ROADMAP.
coverage: --all-features enables real-llm, which runs the live-LLM integration tests without an API key and panics; use the same feature set as the test jobs. mutants: the PR checkout does not carry origin/main, so --in-diff origin/main...HEAD failed to produce a diff; fetch main and pass an explicit diff file.
cargo-mutants without --workspace only considers the current package (the root funera re-export crate), which contains no mutation opportunities, so the job silently reported 'No mutants to filter' and passed without testing anything. Add --workspace so the diff is mutated across all workspace members.
Add tests for code paths that cargo-mutants flagged as uncovered when mutation testing runs with --all-features: RawToolRegistry/GuardedToolRegistry get_tool_arc and remove_tool_if_same, ToolExecutor::run (direct command/response round-trip with a bounded wait), a non-default SandboxPolicy round-trip through the env getter, register_all_tools_with_sandbox, and AgentRuntimeBuilder::with_builtin_tools.
Without --all-features the mutants test build only compiles default-feature code, so mutants in security/sandbox/builtin-tools-gated code are trivially reported missed.
cargo-hack --feature-powerset surfaced cfg-gated unused imports/variables and one real feature-dependency bug that broke '--no-default-features --features funera-builtin-tools': the feature only enabled funera-core/tool, not the local tool feature, so AgentRuntimeBuilder::with_builtin_tools referenced a field that did not exist. Fix feature deps and cfg-gate imports/bindings (tool/skill/security/sandbox combinations).
Checks every distinct resolved feature combination compiles with -D warnings for funera-core, funera-orchestrate, the root funera facade, and funera-builtin-tools.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The unified Plugin abstraction overreached and broke the clean trait-based architecture of main. This PR reverts the core to plain extensible traits and keeps only what is worth keeping.
Kept
FuneraEnv::effect/dispose— register a side effect with its inverse;dispose()runs all inverses in reverse (LIFO) order, idempotently and panic-isolated.EnvActorcallsdispose()automatically when the runtime is dropped, so registrations never leak memory or services.get_tool_arc, cloned guarded registry) andremove_tool_if_sameas the leak-safe inverse ofadd_tool.Removed
plugin.rs+plugin/{adapters,broker,instance,registry},loader.rs+loader/config.rs,env/key.rstyped-service layer,MiddlewareProcessortype erasure,AgentLoopas a plugin subtrait,ServiceBroker, plugin reconciliation, and the six plugin examples.Also fixes pre-existing defects in main
funera-orchestrate/tests/integration.rsdid not compile on main (send-handle semantics,AgentEvent::Text, missing provider generic).-D warningsviolations.coverageran the live-LLMreal-llmtests without an API key;mutantswas a silent no-op (missingorigin/mainand missing--workspace, so it never mutated anything) — it now genuinely runs 36 mutants against the diff (19 caught, 17 unviable, 0 missed).Feature-combination validation (new)
feature-matrixCI job runscargo hack --feature-powerset(with-D warnings) for funera-core, funera-orchestrate, the root facade, and funera-builtin-tools, covering every distinct resolved feature combination (features are not independent: security⇒tool, sandbox⇒security, regex⇒security).--no-default-features --features funera-builtin-toolsdid not compile (the feature enabledfunera-core/toolbut not the localtoolfeature).Tests added to cover the changed code
get_tool_arc/remove_tool_if_same(raw and guarded registries),ToolExecutor::runcommand round-trip, non-defaultSandboxPolicyround-trip,register_all_tools_with_sandbox,AgentRuntimeBuilder::with_builtin_tools, plus the existing reversible-effects LIFO/panic/isolation tests.New example:
cargo run -p funera-orchestrate --example reversible_effects.