Repository navigation
feat(plugins): plugin contract v2 and one provider registry #3755
Copy link
Copy link
Closed
Labels
Description
Part of #3747. Blocked by #3748.
Required behavior
Plugin contract v2. The type-only contract comes from agent-device/plugins; there's no runtime helper.
import type { AgentDevicePluginFactory } from 'agent-device/plugins';
const testmu: AgentDevicePluginFactory<TestmuOptions> = (options = {}) => ({
apiVersion: 2,
provider: 'testmu',
credentials: { variables: ['LT_USERNAME', 'LT_ACCESS_KEY'], byBackend?: { [backend: string]: string[] } },
connection?: { capabilities, resolve, verify },
setup: async (host) => ({ runtime, platformModule, dispose }), // or ({ webDriver, dispose })
});
export default testmu;- The default export is a factory called with options:
- the store path calls it with
config.jsonplugins[name].options; - JS hosts call it directly.
- the store path calls it with
{ webDriver }stays a data descriptor that the host interprets.
Entry discovery for v2
- Resolve the package's
./agent-deviceexport with import conditions, falling back to the package root only when that subpath is absent. If the subpath's import or setup throws, there is no fallback. - v2 packages need no
agentDevicePluginmanifest. - v1 packages, those with
agentDevicePlugin.apiVersion: 1, are dispatched by their manifest before any factory runs. They load through an adapter that reuses today's normalization (packages/plugins/src/load.ts:67) until 0.22: remove superseded plugin, client and environment APIs #3759.
One registry
- Order: built-in → store → embedder. Store entries are taken in a deterministic order (package name).
- Built-ins use the same shape: BrowserStack, AWS Device Farm, the WebDriver clouds, and Limrun until refactor(provider-limrun): ship Limrun as the
@agent-device/limrunplugin #3311. - Validation: one function validates the factory's result for every source.
- Duplicate providers: the first registration claims the ID, even if that registration fails. Later ones are recorded as failed.
cloudandproxystay reserved as routing identities. - Retire these lists:
RESERVED_PLUGIN_PROVIDERSandDEFAULT_PROVIDER_RUNTIME_REQUIRED_IDS. Move their consumers in the same change:src/cli/connection/provider-policy.ts:7;src/provider-credential-fingerprint.ts:7;- connection capability discovery (
packages/plugins/src/connection.ts:26), which reads capabilities from the registry instead of manifests.
Failure isolation and inventory
- A plugin that fails to enumerate, load, validate or set up no longer stops the daemon. The daemon starts with the remaining plugins, cleans up any partial registration, and records:
{ provider?, source: 'builtin' | 'store' | 'embedder', package?, version?, state: 'active' | 'failed', error?, credentials: { variables, byBackend } }.
Store enumeration errors (packages/plugins/src/store.ts:59) are isolated the same way. - The inventory is published in
daemon.jsonand returned by a newagent-device daemon status --json. That command needs a command-registry entry, versioned help, and a schema projection, including MCP if it's projected there. plugins list --jsonworks offline. It reports store selections and, when a daemon is running, its inventory.- The client credential fingerprint reads variable names from the daemon inventory, falling back to v1 manifests. It narrows per backend through
byBackend, preserving the refactor(provider-limrun): ship Limrun as the@agent-device/limrunplugin #3311 requirement. Credentials passed as options are excluded from the environment fingerprint. provider-not-registered(fix(daemon): refuse leases for providers without a registered runtime #3748) includes the failed inventory entry for that provider.
ADR 0034 "Provider plugin registry" (brief) covers: the three sources, one shape, the set fixed per daemon, failure isolation, and a short daemon-ownership note pointing to #3754 and #3757.
Done when
- Built-in providers, a v1 fixture plugin and a v2 fixture plugin all load through the one registry.
- Integration tests cover a broken and a working plugin side by side, and a duplicate provider ID.
connect testmuand the credential-change refusal still work.- A packaged-export smoke test for
agent-device/pluginstypes passes. - The website plugins page shows v2 authoring and the inventory.
- There's a changeset.
Reactions are currently unavailable
Activity
thymikee commentedon Oct 17, 2026
Done: #3767 (plugin contract v2, one provider registry, failure isolation, inventory), #3768 (
daemon status), #3769 (docs, ADR 0034). TestMu on v2 (#3756) landed in #3770.