refactor(appkit): separate plugin context binding from plugin construction#293
Closed
MarioCadenas wants to merge 1 commit intoagent/4-createagent-appsfrom
Closed
refactor(appkit): separate plugin context binding from plugin construction#293MarioCadenas wants to merge 1 commit intoagent/4-createagent-appsfrom
MarioCadenas wants to merge 1 commit intoagent/4-createagent-appsfrom
Conversation
Move the telemetry/cache/context wiring out of the Plugin constructor into a new attachContext(deps) method called by AppKit after construction. Lets plugin factories eagerly construct instances at module top-level without depending on TelemetryManager/CacheManager being initialized yet. - Plugin.constructor stays pure by default but opportunistically binds telemetry+cache if the core services are already initialized (backward compat with existing tests that new PluginX(config) directly). - Plugin.attachContext(deps) is idempotent and does the full binding, including context. AppKit._createApp calls it after construction. - ServerPlugin overrides attachContext to register HTTP/Express instrumentations and become the route target (previously in its constructor). - BasePlugin.attachContext added to the shared interface as optional. Also defer ServerPlugin's start() to the 'setup:complete' lifecycle hook when running through AppKit. Previously start() ran inside setup() and extendRoutes() iterated context.getPlugins() synchronously — so any deferred-phase plugin declared after server() in the plugin array was invisible to the route-mount loop and its /api/<name>/* routes silently dropped. The fix also keeps the pre-AppKit path (direct new ServerPlugin(...) construction) working by falling back to immediate start() when this.context is undefined. No behavior change when used through createApp. Enables upcoming .toolkit() support on plugin factories where the factory eagerly constructs the plugin instance at call time. Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
This was referenced Apr 21, 2026
Collaborator
Author
|
Superseded by the v2 6-PR stack:
The v2 stack reorganizes the same work so no PR ships API that a later PR deletes. Start at #301 for the new entry point. Branches from this older stack are preserved unchanged. |
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.
Summary
Splits the
Pluginbase-class lifecycle into two phases:new Plugin(config)does nothing side-effectful. Factories liketoPlugincan return aPluginDatatuple at module scope without pulling inCacheManager,TelemetryManager, orPluginContext.attachContext({ context, telemetryConfig }): runs insidecreateAppafter all plugins have been constructed. Bindstelemetry,cache, and thePluginContextmediator onto each instance, then firessetup().This unblocks the new
agents()plugin (PR #294) which needs to construct agent definitions at module scope and resolve their plugin references lazily atsetup()time, and it's a prerequisite for any factory that wants to hand back a typed, reusable plugin handle beforecreateAppruns.Notes
ServerPlugin.setup()now defers its HTTP start to thesetup:completelifecycle hook so that routes registered bydeferred-phase plugins (likeagents()) are visible when the server binds. Without this,extendRoutes()would run beforeAgentsPlugin.injectRoutes()had a chance to add its handlers.attachContexttoBasePlugininpackages/shared/src/plugin.ts.PR Stack
agents()plugin +createAgent(def)+.toolkit()— feat(appkit): add agents() plugin, createAgent() factory, and .toolkit() #294agents()— feat(appkit): migrate agent-app and docs to the new agents() plugin #295preparePluginsforwards eager instance — refactor(appkit): forward eager plugin instance through preparePlugins #297fromPlugin()API — feat(appkit): add fromPlugin() for referencing plugin tools in code-defined agents #298agent()+createAgentApp— chore(appkit): remove deprecated agent() plugin and createAgentApp shortcut #299toPluginWithInstance+ bug fixes — refactor(appkit): retire toPluginWithInstance; consolidate on fromPlugin + fix schema/routing bugs #300Test plan