Skip to content

Feat/meta plugin - #42

Merged
wangxingjun778 merged 21 commits into
mainfrom
feat/meta_plugin
Aug 25, 2026
Merged

Feat/meta plugin#42
wangxingjun778 merged 21 commits into
mainfrom
feat/meta_plugin

Conversation

@wangxingjun778

@wangxingjun778 wangxingjun778 commented Aug 25, 2026

Copy link
Copy Markdown
Member

Features

  • Added end-to-end adaptive plugin evolution: capability observation, proposal queues, policy decisions, live generation, installation, probation, trust promotion, quarantine, and rollback.
  • Added environment-aware capability resolution, orchestration plans, persistence, monitoring, and dashboard visualization.
  • Added governed plugin proposals, behavior tests, versioning, hot reload, disable/enable/remove, and sandbox validation.
  • Added plugin compatibility assessment and external manifest adaptation.
  • Added marketplace installation with checksum and Ed25519 signature verification.
  • Added pluggable Gateway adapter registries and Telegram active signal support.
  • Added /plugin generate, plan inspection, lifecycle controls, and approval-aware progress reporting.

Refactor

  • Promoted leapflow.plugins to a first-class subsystem with unified protocols, registries, lifecycle scopes, sandboxing, and marketplace support.
  • Reworked tool execution around registry-owned handlers, composable execution pipelines, and structured capability metadata.
  • Added dependency-driven plugin fiber activation and topological runtime dependency binding.
  • Unified Tool, Gateway, LLM, and signal-source extension contracts.

Enhancements

  • Added Progressive Trust persistence, usage statistics, environment fingerprints, and multi-workspace capability selection.
  • Improved daemon concurrency with parked turn admission and clearer queue feedback.
  • Added heartbeat support for long-running non-streaming RPC commands.
  • Improved approval UX, workspace-escape governance, and persistent grants.
  • Expanded capability transparency through LeapBoard, monitor findings, and /plugin plan.
  • Added autonomous long-run and live-generation plugin experiments with Markdown, JSON, and HTML reports.

Fixes

  • Prevented duplicate tool names from silently overriding handlers or schemas.
  • Fixed plugin command rendering, approval routing, command latency, and stale TUI spinner state.
  • Hardened unknown-tool recovery and durable capability-gap observation.
  • Fixed runtime tool dispatch, CUA mappings, Darwin adapter behavior, and workspace-bound execution.
  • Improved plugin reload cleanup, rollback safety, registry consistency, and failure isolation.

Documentation

  • Added comprehensive third-party plugin development and lifecycle management guides.
  • Updated README and engineering guidance for plugin governance, progressive trust, approvals, and autonomous evolution.
  • Added detailed adaptive-plugin experiment instructions and generated reporting guidance.

Tests

  • Added broad unit/component coverage for plugin lifecycle, compatibility, marketplace, sandboxing, capability resolution, governance, Gateway adapters, and approval safety.
  • Added the R7 real-daemon adaptive plugin journey and refreshed deterministic cassette coverage.
  • Extended journey coverage for lifecycle, recovery, concurrency, persistence, and autonomous plugin evolution.

Delivers a full self-evolving plugin framework inspired by
deepseek-harness's "everything is a plugin" design, adapted to
LeapFlow's Signal-Driven philosophy.

Core layers:

  Protocol layer
    - ToolPlugin, GatewayAdapterPlugin, LLMProviderPlugin
    - SignalSource (transform-only), ActiveSignalSource (lifecycle)
    - CVProcessor, FrameStore (upgraded from ABC to Protocol)

  Registry + lifecycle
    - Delete registry_bootstrap.py (1507 lines) -> ToolPluginRegistry
      + plugins/ modular directory
    - ToolMetadata as single source of truth
    - EffectScope + PluginFiber state machine
    - ScopedRegistry (Tool/Gateway/LLM) with adopt_existing_plugins
      for full fiber coverage at boot

  Hot-reload
    - reload_plugin() explicit API
    - version counter drives engine _registry_cache invalidation
    - per-turn handler snapshot guarantees concurrent safety
    - config-driven disabled_plugins

  Self-Modification (7 tools, approval-gated)
    - plugin_list / plugin_status / plugin_reload / plugin_disable /
      plugin_enable / plugin_generate / plugin_install
    - HIGH risk, allow_permanent=False (defense-in-depth in risk.py)
    - Cross-subsystem introspection (tools + gateway + llm)
    - Progressive Trust auto-approve for PRODUCTION-tier reload only

  Learning closed loop
    - PluginTrustLedger (DRAFT->CANDIDATE->VERIFIED->PRODUCTION)
    - PluginUsageTracker (bounded deque, cross-turn accumulator)
    - PluginAdvisor (stateless scoring)
    - PluginHealthProducer (MonitorProducer proactive alerts)
    - DuckDB persistence via PluginStatsStore
    - Data source: TurnUsageTracker.record_tool_call forward hook

  Perception signal sources
    - 7 transform-only builtin (click/scroll/keyboard/drag/clipboard/
      app_switch)
    - ActiveSignalSource lifecycle-bearing category:
      FileWatchSignalSource (watchdog), WebhookSignalSource,
      CronSignalSource, FeishuIMSignalSource (real-world signal demo)
    - Queue-serialized downstream via ActiveSourceManager
    - thread-safe emit via call_soon_threadsafe

  Self-evolution capstone
    - Plugin sandbox (subprocess isolation, JSON-RPC over stdin/stdout)
    - Marketplace prototype (LocalDirectorySource + HttpMarketplaceSource,
      checksum-verified install)
    - LLM plugin generator (multi-stage validation:
      syntax -> structure -> import -> protocol; sandbox deferred
      to install-time for safety)

  Developer experience
    - PluginFileWatcher (auto hot-reload on file changes)
    - /plugin slash command (list/status/reload/disable/enable) --
      PENDING HUMAN CONFIRMATION per AGENTS.md
    - ToolBridge cleanup assessment (Landing A/B/C plan documented
      in bridge_adapter.py)

Documentation:
  - temp/deepseek_harness/pluggable_architecture_analysis.md
  - temp/deepseek_harness/tool_plugin_refactoring_plan.md
  - temp/deepseek_harness/PLUGIN_DEVELOPER_GUIDE.md (1145 lines)
  - temp/deepseek_harness/PLUGIN_SYSTEM_TODO.md

Test coverage: 1721 -> 1954 (+233 new tests, zero regressions).

Pending items:
  - /plugin slash command needs human verification per AGENTS.md
  - Journey cassettes need re-recording (`make seed-cassettes`)
  - ToolBridge Landing A/B/C staged cleanup
Implement a 6-stage (P0: stages 1-2) assessment pipeline that evaluates
foreign plugins (primarily from deepseek-harness ecosystem) for LeapFlow
compatibility before installation is attempted.

Core components:
- learning/compatibility/protocol.py: Verdict enum (COMPATIBLE/ADAPTABLE/
  PARTIAL/INCOMPATIBLE), frozen dataclasses (PluginManifestInput,
  StageResult, CompatibilityReport, AdapterSpec)
- learning/compatibility/taxonomy.py: 30+ entry pluggability boundary map
  classifying every DSH plugin category against LeapFlow's architecture
- learning/compatibility/stages/manifest_parser.py: Stage 1 — auto-detect
  and parse LeapFlow PluginManifest or DSH package.json formats
- learning/compatibility/stages/category_resolver.py: Stage 2 — taxonomy
  lookup with INCOMPATIBLE short-circuit
- learning/compatibility/pipeline.py: assess_plugin() orchestrator with
  short-circuit on INCOMPATIBLE at any stage

Also removes 3 vestigial empty directories (tools/plugins/, tools/sandbox/,
tools/marketplace/) left over from the module extraction.

Tests: 35 new tests covering parsing, resolution, pipeline e2e, short-
circuit, and API contracts. Full suite: 2145 passed, 0 regressions.
Implement all 6 assessment stages + verdict synthesizer + tool exposure
+ marketplace install gate:

- Stage 3 (interface_analyzer): pattern-match declared_interfaces against
  required interface patterns per target Protocol
- Stage 4 (dependency_checker): classify deps as satisfiable/shimmable/
  blocking using curated pattern sets
- Stage 5 (execution_model): map async/sync/worker/streaming + source
  language (python/typescript) to LeapFlow equivalents
- Stage 6 (security_classifier): map permissions to risk levels, recommend
  isolation (in_process/sandbox/reject)
- verdict.py: aggregate all stages into final CompatibilityReport with
  AdapterSpec generation for ADAPTABLE verdicts
- Pipeline extended to run all 6 stages with lazy imports + short-circuit
- Tool #12: assess_compatibility (read-only, no approval needed)
- Marketplace install gate: INCOMPATIBLE manifests rejected before install

Tests: 76 compatibility + 56 self-management = 2186 total passed, 0 regressions.
…oading + docs update

- adapter_generator.py: template-based bridge wrapper generation for
  ADAPTABLE plugins (DshXxxBridgePlugin skeleton with SandboxHost JSON-RPC
  delegation); LLM-enhanced mode with graceful fallback to template
- manifest_converter.py: convert_dsh_to_leapflow() pure utility for DSH
  package.json → LeapFlow PluginManifest format mapping
- pipeline.py: file-path manifest loading (str/Path → JSON read with
  graceful error handling for missing/invalid/non-object files)
- Docs: README Compatibility Assessment subsection, third_party_dev §5.7,
  lifecycle governance matrix row, developer guide module paths, TODO
  marks P0+P1+P2 as complete (~99%)

Tests: 111 compatibility assessment tests. Full suite: 2221 passed.
Deep review: 3-dim (completeness/correctness/impact) all clear, no
Critical or Warning findings.
Inspired by the Cordis spatiotemporal composability formal model:

1. PluginFiber state machine extended with LOADING and FAILED states:
   - PENDING→LOADING→ACTIVE (opt-in async init tracking)
   - LOADING→FAILED (init failure with error storage)
   - FAILED→LOADING (retry semantics, clears error)
   - PENDING→DISPOSED (cleanup of never-started fibers)
   - Existing PENDING→ACTIVE path preserved (zero breaking changes)
   - New methods: begin_loading(), fail(error), retry()
   - New properties: is_loading, is_failed, error

2. EventBus scope-bound subscriptions:
   - Subscriber storage: list → dict[id, callback] for O(1) unsubscribe
   - New scope parameter: subscribe(cb, scope=fiber.scope) auto-registers
     unsubscribe cleanup on EffectScope dispose
   - Duck-typed scope check avoids import cycles
   - Net performance improvement during bulk plugin dispose

Both changes are cold-path only — zero impact on per-turn tool dispatch.
Tests: 2232 passed (+11 new), 0 regressions.
…ogical bind order

Two upgrades inspired by Cordis reactive coeffects and provider-consumer
lifecycle coupling:

1. Dependency-driven fiber activation (scoped_registry.py):
   - Plugins with declared dependencies enter LOADING state at boot
   - _check_pending_activations() fixpoint loop auto-activates fibers
     when all their deps become satisfied (provider plugin ACTIVE or
     dep in last_bound_deps)
   - Plugins with NO deps activate immediately (zero behavior change)
   - Circular/unsatisfiable deps: graceful force-activate with WARNING
   - External runtime deps (file_read_gate etc.) log DEBUG, not WARNING

2. Provider-consumer ordering protocol (registry.py):
   - bind_runtime() now iterates plugins in topological order using
     graphlib.TopologicalSorter (stdlib Python 3.11+)
   - Providers are bound before consumers, eliminating init-order bugs
   - CycleError: log warning + fallback to registration order

Tests: 11 new (test_dependency_activation.py). Full suite: 2243 passed,
0 regressions.
… + docs

1. Waterfall Tool Execution Pipeline (domain/tool_pipeline.py):
   - ToolInterceptor runtime_checkable Protocol (name, priority, before, after)
   - ToolExecutionPipeline: composable pre/post interceptor chain
   - Before hooks by ascending priority; short-circuit on non-None return
   - After hooks in reverse priority (innermost first)
   - Zero overhead when no interceptors registered
   - Built-in examples: AuditInterceptor, TimeoutInterceptor
   - Exposed via ToolPluginRegistry.tool_pipeline property

2. Async EffectScope cleanup (domain/effect_scope.py):
   - async_effect(cleanup) registers async teardown callbacks
   - async_dispose() awaits children + async effects + sync effects (LIFO)
   - Sync dispose() graceful degradation: asyncio.run() or fire-and-forget

3. Documentation updates:
   - plugin_fiber.py docstring: full 6-state machine documentation
   - README: Lifecycle & Composability section
   - All docs/plugins/ files: 6-state, pipeline, dep-driven activation
   - TODO: Cordis P0+P1+P2 marked complete

Deep review: 3-dim (completeness + correctness) all clear, 0 findings.
Tests: 2284 passed (+40 new pipeline + async tests), 0 regressions.
…rade

Three follow-up items + comprehensive experiment upgrade:

1. Engine ToolExecutionPipeline integration (engine.py):
   - _execute_general_tool routes handler calls through registry.tool_pipeline
     when interceptors are registered (fast path preserved when empty)
   - Timeout enforcement moved into pipeline.execute() via annotations
   - Approval/semantic gating unchanged (runs before pipeline)

2. Adapter generator escaping hardening (adapter_generator.py):
   - _normalize_name strips all non-identifier chars (re.sub)
   - _pascal_case strips non-alnum from parts
   - String interpolation uses _py_str_literal()/repr() for safety
   - compile() guard at generation time catches template bugs early

3. ActiveSourceManager async dispose: confirmed already correct
   (async def dispose() awaited by PerceptionSession.stop() directly;
   no EffectScope misregistration to fix)

4. Plugin experiment comprehensive upgrade (temp/plugin_exp/):
   - 8 new automated phases (F-M): fiber states, scope-bound EventBus,
     dependency activation, waterfall pipeline, async cleanup,
     compatibility assessment, proposals, lifecycle storm
   - 5 new test plugins (dep_chain × 3, fiber_test, dsh_compat manifest)
   - Existing phases B/C/D upgraded with new assertions
   - Runner: 484 → 1257 lines, 13 phases total, all passing

Tests: 2286 passed, 0 regressions. Experiment: 13/13 phases green.
Implement /plugin generate — a single-action slash command that generates,
validates, and installs a LeapFlow-conformant plugin from a natural-language
description with zero intermediate prompts.

Command: /plugin generate [--preview|--dry-run|--id <id>] <description>
- Config gate: plugin_generation_enabled must be True
- LLM gate: provider must be available
- Auto-derive plugin_id from description (slugify first 3 words)
- Generate via PluginGenerator + bounded refinement retry (1 attempt)
- Validate (syntax→structure→import→protocol)
- Install via self_management._install_from_code (sandbox + register)
- Preview/dry-run modes for inspection without install
- Auto-approve (user intent = consent; differs from agent-tool approval gate)

Review fixes:
- --id without value now returns usage error (not silent bad id)
- Retry error snippet capped at 512 chars (prevents token bloat)

Docs: README, third_party_dev, lifecycle governance matrix, TODO all updated.
PENDING: human confirmation per AGENTS.md (slash command new behavior).

Tests: 2286 passed, 0 regressions.
The /plugin generate command and plugin_generate tool should be available
out of the box without requiring users to manually flip a config switch.
Installation still goes through ApprovalGate; the generation step itself
is read-only (produces code without writing), so gating it separately
adds friction without meaningful safety benefit.
Root cause: /plugin generate (and any non-streaming RPC with a 30-60s LLM
call) timed out because the client's 30s readline deadline fired while the
daemon blocked on the handler. Streaming turns (engine.chat) survive via
periodic heartbeats, but command.execute used a plain request-response with
no heartbeat.

Fix:
- server.py: _await_with_heartbeat() wraps async non-streaming handlers,
  sending a heartbeat StreamChunk (metadata.heartbeat=True) every
  _stream_heartbeat_s (10s) while awaiting. Fast RPCs (<10s) send zero
  heartbeats (asyncio.wait returns immediately on completion). Handler
  exceptions propagate via task.result(); on client disconnect the task
  is cancelled and awaited (no orphan tasks).
- client.py: request() skips stream.chunk notifications with
  metadata.heartbeat=True, resetting its per-read deadline each time, so a
  live-but-slow server no longer trips the timeout. A truly dead server
  still times out on the next readline.

Verified safe by 2-dim review (correctness + impact): multi-client isolation
intact (heartbeats go to the per-connection writer), streaming heartbeats
unaffected (separate _dispatch_stream path), exception path unchanged.

PENDING human confirmation per AGENTS.md (daemon RPC + slash-command path).
Tests: 2299 passed (+1 regression test), 0 failed.
@wangxingjun778
wangxingjun778 merged commit 15a2694 into main Aug 25, 2026
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant