diff --git a/CHANGELOG.md b/CHANGELOG.md
index ae547a06fda..8164fcb3e38 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,7 +6,7 @@ Docs: https://docs.openclaw.ai
### Breaking
-- Plugin SDK/tool-result transforms: deprecate the Pi-only `api.registerEmbeddedExtensionFactory(...)` path for tool-result rewriting in favor of bundled `api.registerAgentToolResultMiddleware(...)`, with `contracts.agentToolResultMiddleware` declaring the targeted harnesses. The legacy Pi hook remains wired as a bundled compatibility seam, but new bundled transforms should use the harness-neutral middleware contract so transforms run consistently across Pi and Codex app-server dynamic tools. Thanks @vincentkoc.
+- Plugin SDK/tool-result transforms: remove the Pi-only `api.registerEmbeddedExtensionFactory(...)` compatibility path. Bundled tool-result rewrites must use `api.registerAgentToolResultMiddleware(...)` with `contracts.agentToolResultMiddleware` declaring the targeted harnesses, so transforms run consistently across Pi and Codex app-server dynamic tools. Thanks @vincentkoc.
### Changes
diff --git a/docs/.generated/plugin-sdk-api-baseline.sha256 b/docs/.generated/plugin-sdk-api-baseline.sha256
index c258f2848f7..d9316d62c2d 100644
--- a/docs/.generated/plugin-sdk-api-baseline.sha256
+++ b/docs/.generated/plugin-sdk-api-baseline.sha256
@@ -1,2 +1,2 @@
-f74435d49aa0af2509264d8581e12ffc624b1d6542d250d608ee5c3b41a234f3 plugin-sdk-api-baseline.json
-df33bbe47bb092ed11814576b5386253140f7aa6f8479a5334aff9b988125afc plugin-sdk-api-baseline.jsonl
+1b8ce6687d91267f78f589ee29d4cca0809fde73ea47c82ddbd14ecf54f1803a plugin-sdk-api-baseline.json
+55c48203fe5d6409f690f4d27abde41502feec1bfb63d9096cd9958fcf45c2c2 plugin-sdk-api-baseline.jsonl
diff --git a/docs/plugins/manifest.md b/docs/plugins/manifest.md
index 036d37f24ad..4759be5cc77 100644
--- a/docs/plugins/manifest.md
+++ b/docs/plugins/manifest.md
@@ -431,7 +431,7 @@ Each list is optional:
| Field | Type | What it means |
| -------------------------------- | ---------- | --------------------------------------------------------------------- |
-| `embeddedExtensionFactories` | `string[]` | Deprecated embedded extension factory ids. |
+| `embeddedExtensionFactories` | `string[]` | Codex app-server extension factory ids, currently `codex-app-server`. |
| `agentToolResultMiddleware` | `string[]` | Runtime ids a bundled plugin may register tool-result middleware for. |
| `externalAuthProviders` | `string[]` | Provider ids whose external auth profile hook this plugin owns. |
| `speechProviders` | `string[]` | Speech provider ids this plugin owns. |
@@ -445,12 +445,12 @@ Each list is optional:
| `webSearchProviders` | `string[]` | Web-search provider ids this plugin owns. |
| `tools` | `string[]` | Agent tool names this plugin owns for bundled contract checks. |
-`contracts.embeddedExtensionFactories` is retained for bundled compatibility
-code that still needs direct Pi embedded-runner events. New bundled
-tool-result transforms should declare `contracts.agentToolResultMiddleware`
-and register with `api.registerAgentToolResultMiddleware(...)` instead.
-External plugins cannot register tool-result middleware because the seam can
-rewrite high-trust tool output before the model sees it.
+`contracts.embeddedExtensionFactories` is retained for bundled Codex
+app-server-only extension factories. Bundled tool-result transforms should
+declare `contracts.agentToolResultMiddleware` and register with
+`api.registerAgentToolResultMiddleware(...)` instead. External plugins cannot
+register tool-result middleware because the seam can rewrite high-trust tool
+output before the model sees it.
Provider plugins that implement `resolveExternalAuthProfiles` should declare
`contracts.externalAuthProviders`. Plugins without the declaration still run
diff --git a/docs/plugins/sdk-agent-harness.md b/docs/plugins/sdk-agent-harness.md
index b1b5f9cdbff..9f3d8f106d9 100644
--- a/docs/plugins/sdk-agent-harness.md
+++ b/docs/plugins/sdk-agent-harness.md
@@ -155,9 +155,8 @@ tool output back into the model.
Legacy bundled plugins can still use
`api.registerCodexAppServerExtensionFactory(...)` for Codex app-server-only
middleware, but new result transforms should use the runtime-neutral API.
-The Pi-only `api.registerEmbeddedExtensionFactory(...)` hook is deprecated for
-tool-result transforms; keep it only for bundled compatibility code that still
-needs direct Pi embedded-runner events.
+The Pi-only `api.registerEmbeddedExtensionFactory(...)` hook has been removed;
+Pi tool-result transforms must use runtime-neutral middleware.
### Native Codex harness mode
diff --git a/docs/plugins/sdk-migration.md b/docs/plugins/sdk-migration.md
index 262c1ad1d4f..2e824ddbf32 100644
--- a/docs/plugins/sdk-migration.md
+++ b/docs/plugins/sdk-migration.md
@@ -5,7 +5,7 @@ sidebarTitle: "Migrate to SDK"
read_when:
- You see the OPENCLAW_PLUGIN_SDK_COMPAT_DEPRECATED warning
- You see the OPENCLAW_EXTENSION_API_DEPRECATED warning
- - You use api.registerEmbeddedExtensionFactory
+ - You used api.registerEmbeddedExtensionFactory before OpenClaw 2026.4.24
- You are updating a plugin to the modern plugin architecture
- You maintain an external OpenClaw plugin
---
@@ -24,12 +24,14 @@ anything they needed from a single entry point:
new plugin architecture was being built.
- **`openclaw/extension-api`** — a bridge that gave plugins direct access to
host-side helpers like the embedded agent runner.
-- **`api.registerEmbeddedExtensionFactory(...)`** — a Pi-only bundled extension
- hook that could observe embedded-runner events such as `tool_result`.
+- **`api.registerEmbeddedExtensionFactory(...)`** — a removed Pi-only bundled
+ extension hook that could observe embedded-runner events such as
+ `tool_result`.
-These surfaces are now **deprecated**. They still work at runtime, but new
-plugins must not use them, and existing plugins should migrate before the next
-major release removes them.
+The broad import surfaces are now **deprecated**. They still work at runtime,
+but new plugins must not use them, and existing plugins should migrate before
+the next major release removes them. The Pi-only embedded extension factory
+registration API has been removed; use tool-result middleware instead.
OpenClaw does not remove or reinterpret documented plugin behavior in the same
change that introduces a replacement. Breaking contract changes must first go
@@ -40,6 +42,7 @@ registration behavior.
The backwards-compatibility layer will be removed in a future major release.
Plugins that still import from these surfaces will break when that happens.
+ Pi-only embedded extension factory registrations already no longer load.
## Why this changed
@@ -91,19 +94,12 @@ releases.
- Bundled plugins should replace Pi-only
+ Bundled plugins must replace Pi-only
`api.registerEmbeddedExtensionFactory(...)` tool-result handlers with
runtime-neutral middleware.
```typescript
- // Before: Pi-only compatibility hook
- api.registerEmbeddedExtensionFactory((pi) => {
- pi.on("tool_result", async (event) => {
- return compactToolResult(event);
- });
- });
-
- // After: Pi and Codex runtime dynamic tools
+ // Pi and Codex runtime dynamic tools
api.registerAgentToolResultMiddleware(async (event) => {
return compactToolResult(event);
}, {
@@ -121,10 +117,8 @@ releases.
}
```
- Keep `contracts.embeddedExtensionFactories` only for bundled compatibility
- code that still needs direct Pi embedded-runner events. External plugins
- cannot register tool-result middleware because it can rewrite high-trust
- tool output before the model sees it.
+ External plugins cannot register tool-result middleware because it can
+ rewrite high-trust tool output before the model sees it.
@@ -624,8 +618,8 @@ canonical replacement.
Covered in "How to migrate → Migrate Pi tool-result extensions to
- middleware" above. Included here for completeness: the Pi-only
- `api.registerEmbeddedExtensionFactory(...)` path is deprecated in favor of
+ middleware" above. Included here for completeness: the removed Pi-only
+ `api.registerEmbeddedExtensionFactory(...)` path is replaced by
`api.registerAgentToolResultMiddleware(...)` with an explicit runtime
list in `contracts.agentToolResultMiddleware`.
diff --git a/docs/plugins/sdk-overview.md b/docs/plugins/sdk-overview.md
index f1671fe0911..b96e58c2ca2 100644
--- a/docs/plugins/sdk-overview.md
+++ b/docs/plugins/sdk-overview.md
@@ -96,19 +96,18 @@ methods:
### Infrastructure
-| Method | What it registers |
-| ----------------------------------------------- | --------------------------------------- |
-| `api.registerHook(events, handler, opts?)` | Event hook |
-| `api.registerHttpRoute(params)` | Gateway HTTP endpoint |
-| `api.registerGatewayMethod(name, handler)` | Gateway RPC method |
-| `api.registerGatewayDiscoveryService(service)` | Local Gateway discovery advertiser |
-| `api.registerCli(registrar, opts?)` | CLI subcommand |
-| `api.registerService(service)` | Background service |
-| `api.registerInteractiveHandler(registration)` | Interactive handler |
-| `api.registerAgentToolResultMiddleware(...)` | Runtime tool-result middleware |
-| `api.registerEmbeddedExtensionFactory(factory)` | Deprecated PI extension factory |
-| `api.registerMemoryPromptSupplement(builder)` | Additive memory-adjacent prompt section |
-| `api.registerMemoryCorpusSupplement(adapter)` | Additive memory search/read corpus |
+| Method | What it registers |
+| ---------------------------------------------- | --------------------------------------- |
+| `api.registerHook(events, handler, opts?)` | Event hook |
+| `api.registerHttpRoute(params)` | Gateway HTTP endpoint |
+| `api.registerGatewayMethod(name, handler)` | Gateway RPC method |
+| `api.registerGatewayDiscoveryService(service)` | Local Gateway discovery advertiser |
+| `api.registerCli(registrar, opts?)` | CLI subcommand |
+| `api.registerService(service)` | Background service |
+| `api.registerInteractiveHandler(registration)` | Interactive handler |
+| `api.registerAgentToolResultMiddleware(...)` | Runtime tool-result middleware |
+| `api.registerMemoryPromptSupplement(builder)` | Additive memory-adjacent prompt section |
+| `api.registerMemoryCorpusSupplement(adapter)` | Additive memory search/read corpus |
Reserved core admin namespaces (`config.*`, `exec.approvals.*`, `wizard.*`,
@@ -126,14 +125,8 @@ methods:
Bundled plugins must declare `contracts.agentToolResultMiddleware` for each
targeted runtime, for example `["pi", "codex"]`. External plugins
cannot register this middleware; keep normal OpenClaw plugin hooks for work
-that does not need pre-model tool-result timing.
-
-
-
- `api.registerEmbeddedExtensionFactory(...)` is deprecated. It remains a
- compatibility seam for bundled plugins that still need direct Pi
- embedded-runner events. New tool-result transforms should use
- `api.registerAgentToolResultMiddleware(...)` instead.
+that does not need pre-model tool-result timing. The old Pi-only embedded
+extension factory registration path has been removed.
### Gateway discovery registration
diff --git a/src/agents/pi-embedded-runner.extensions.test.ts b/src/agents/pi-embedded-runner.extensions.test.ts
index c0fcd9df93b..dc949aed8cc 100644
--- a/src/agents/pi-embedded-runner.extensions.test.ts
+++ b/src/agents/pi-embedded-runner.extensions.test.ts
@@ -1,24 +1,13 @@
import { SessionManager } from "@mariozechner/pi-coding-agent";
import { afterEach, describe, expect, it } from "vitest";
-import { listEmbeddedExtensionFactories } from "../plugins/embedded-extension-factory.js";
-import { loadOpenClawPlugins } from "../plugins/loader.js";
import { createEmptyPluginRegistry } from "../plugins/registry.js";
import { setActivePluginRegistry } from "../plugins/runtime.js";
import { buildEmbeddedExtensionFactories } from "./pi-embedded-runner/extensions.js";
-import {
- cleanupTempPluginTestEnvironment,
- createTempPluginDir,
- resetActivePluginRegistryForTest,
- writeTempPlugin,
-} from "./test-helpers/temp-plugin-extension-fixtures.js";
+import { cleanupTempPluginTestEnvironment } from "./test-helpers/temp-plugin-extension-fixtures.js";
const originalBundledPluginsDir = process.env.OPENCLAW_BUNDLED_PLUGINS_DIR;
const tempDirs: string[] = [];
-function createTempDir(): string {
- return createTempPluginDir(tempDirs, "openclaw-embedded-ext-");
-}
-
afterEach(() => {
cleanupTempPluginTestEnvironment(tempDirs, originalBundledPluginsDir);
});
@@ -80,245 +69,4 @@ describe("buildEmbeddedExtensionFactories", () => {
expect(seenToolCallIds[1]).toMatch(/^pi-/);
expect(seenToolCallIds[0]).not.toBe(seenToolCallIds[1]);
});
-
- it("includes plugin-registered embedded extension factories and restores them from cache", async () => {
- const tmp = createTempDir();
- process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = tmp;
-
- writeTempPlugin({
- dir: tmp,
- id: "embedded-ext",
- filename: "index.mjs",
- manifest: {
- contracts: {
- embeddedExtensionFactories: ["pi"],
- },
- },
- body: `export default { id: "embedded-ext", register(api) {
- api.registerEmbeddedExtensionFactory((pi) => {
- pi.on("session_start", () => undefined);
- });
-} };`,
- });
-
- const options = {
- config: {
- plugins: {
- entries: {
- "embedded-ext": {
- enabled: true,
- },
- },
- },
- },
- };
-
- loadOpenClawPlugins(options);
-
- const firstFactories = buildEmbeddedExtensionFactories({
- cfg: undefined,
- sessionManager: SessionManager.inMemory(),
- provider: "openai",
- modelId: "gpt-5.4",
- model: undefined,
- });
- expect(firstFactories).toHaveLength(2);
- expect(listEmbeddedExtensionFactories()).toHaveLength(1);
-
- resetActivePluginRegistryForTest();
- expect(listEmbeddedExtensionFactories()).toHaveLength(0);
-
- loadOpenClawPlugins(options);
-
- const cachedFactories = buildEmbeddedExtensionFactories({
- cfg: undefined,
- sessionManager: SessionManager.inMemory(),
- provider: "openai",
- modelId: "gpt-5.4",
- model: undefined,
- });
- expect(cachedFactories).toHaveLength(2);
-
- const handlers = new Map();
- await cachedFactories[1]?.({
- on(event: string, handler: Function) {
- handlers.set(event, handler);
- },
- } as never);
- expect(handlers.has("session_start")).toBe(true);
- });
-
- it("rejects embedded extension factories from non-bundled plugins even when they declare the Pi manifest contract", () => {
- const tmp = createTempDir();
- process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = "/nonexistent/bundled/plugins";
-
- const pluginFile = writeTempPlugin({
- dir: tmp,
- id: "embedded-ext",
- manifest: {
- contracts: {
- embeddedExtensionFactories: ["pi"],
- },
- },
- body: `export default { id: "embedded-ext", register(api) {
- api.registerEmbeddedExtensionFactory((pi) => {
- pi.on("session_start", () => undefined);
- });
-} };`,
- });
-
- const registry = loadOpenClawPlugins({
- workspaceDir: tmp,
- config: {
- plugins: {
- load: { paths: [pluginFile] },
- allow: ["embedded-ext"],
- },
- },
- });
-
- expect(registry.diagnostics).toContainEqual(
- expect.objectContaining({
- level: "error",
- pluginId: "embedded-ext",
- message: "only bundled plugins can register Pi embedded extension factories",
- }),
- );
- expect(listEmbeddedExtensionFactories()).toHaveLength(0);
- expect(
- buildEmbeddedExtensionFactories({
- cfg: undefined,
- sessionManager: SessionManager.inMemory(),
- provider: "openai",
- modelId: "gpt-5.4",
- model: undefined,
- }),
- ).toHaveLength(1);
- });
-
- it("rejects bundled plugins that omit the Pi embedded extension manifest contract", () => {
- const tmp = createTempDir();
- process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = tmp;
-
- writeTempPlugin({
- dir: tmp,
- id: "embedded-ext",
- filename: "index.mjs",
- body: `export default { id: "embedded-ext", register(api) {
- api.registerEmbeddedExtensionFactory((pi) => {
- pi.on("session_start", () => undefined);
- });
-} };`,
- });
-
- const registry = loadOpenClawPlugins({
- config: {
- plugins: {
- entries: {
- "embedded-ext": {
- enabled: true,
- },
- },
- },
- },
- });
-
- expect(registry.diagnostics).toContainEqual(
- expect.objectContaining({
- level: "error",
- pluginId: "embedded-ext",
- message:
- 'plugin must declare contracts.embeddedExtensionFactories: ["pi"] to register Pi embedded extension factories',
- }),
- );
- expect(listEmbeddedExtensionFactories()).toHaveLength(0);
- });
-
- it("rejects non-function embedded extension factories from bundled plugins", () => {
- const tmp = createTempDir();
- process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = tmp;
-
- writeTempPlugin({
- dir: tmp,
- id: "embedded-ext",
- filename: "index.mjs",
- manifest: {
- contracts: {
- embeddedExtensionFactories: ["pi"],
- },
- },
- body: `export default { id: "embedded-ext", register(api) {
- api.registerEmbeddedExtensionFactory("not-a-function");
-} };`,
- });
-
- const registry = loadOpenClawPlugins({
- config: {
- plugins: {
- entries: {
- "embedded-ext": {
- enabled: true,
- },
- },
- },
- },
- });
-
- expect(registry.diagnostics).toContainEqual(
- expect.objectContaining({
- level: "error",
- pluginId: "embedded-ext",
- message: "embedded extension factory must be a function",
- }),
- );
- expect(listEmbeddedExtensionFactories()).toHaveLength(0);
- });
-
- it("contains embedded extension factory failures so one bad plugin cannot crash setup", async () => {
- const tmp = createTempDir();
- process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = tmp;
-
- writeTempPlugin({
- dir: tmp,
- id: "embedded-ext",
- filename: "index.mjs",
- manifest: {
- contracts: {
- embeddedExtensionFactories: ["pi"],
- },
- },
- body: `export default { id: "embedded-ext", register(api) {
- api.registerEmbeddedExtensionFactory(() => {
- throw new Error("boom");
- });
-} };`,
- });
-
- loadOpenClawPlugins({
- config: {
- plugins: {
- entries: {
- "embedded-ext": {
- enabled: true,
- },
- },
- },
- },
- });
-
- const factories = buildEmbeddedExtensionFactories({
- cfg: undefined,
- sessionManager: SessionManager.inMemory(),
- provider: "openai",
- modelId: "gpt-5.4",
- model: undefined,
- });
- expect(factories).toHaveLength(2);
-
- await expect(
- factories[1]?.({
- on() {},
- } as never),
- ).resolves.toBeUndefined();
- });
});
diff --git a/src/agents/pi-embedded-runner/extensions.ts b/src/agents/pi-embedded-runner/extensions.ts
index 067f101cf5f..483786d4414 100644
--- a/src/agents/pi-embedded-runner/extensions.ts
+++ b/src/agents/pi-embedded-runner/extensions.ts
@@ -3,7 +3,6 @@ import type { AgentToolResult } from "@mariozechner/pi-agent-core";
import type { ExtensionFactory, SessionManager } from "@mariozechner/pi-coding-agent";
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import { listAgentToolResultMiddlewares } from "../../plugins/agent-tool-result-middleware.js";
-import { listEmbeddedExtensionFactories } from "../../plugins/embedded-extension-factory.js";
import type { ProviderRuntimeModel } from "../../plugins/provider-runtime-model.types.js";
import { resolveContextWindowInfo } from "../context-window-guard.js";
import { DEFAULT_CONTEXT_TOKENS } from "../defaults.js";
@@ -176,7 +175,6 @@ export function buildEmbeddedExtensionFactories(params: {
factories.push(pruningFactory);
}
factories.push(buildAgentToolResultMiddlewareFactory());
- factories.push(...listEmbeddedExtensionFactories());
return factories;
}
diff --git a/src/gateway/server-plugins.test.ts b/src/gateway/server-plugins.test.ts
index 7a32eabccc1..5fdcb06d898 100644
--- a/src/gateway/server-plugins.test.ts
+++ b/src/gateway/server-plugins.test.ts
@@ -88,7 +88,6 @@ const createRegistry = (diagnostics: PluginDiagnostic[]): PluginRegistry => ({
webFetchProviders: [],
webSearchProviders: [],
memoryEmbeddingProviders: [],
- embeddedExtensionFactories: [],
codexAppServerExtensionFactories: [],
agentToolResultMiddlewares: [],
textTransforms: [],
diff --git a/src/gateway/test-helpers.plugin-registry.ts b/src/gateway/test-helpers.plugin-registry.ts
index 70462336d16..8aa03fd6f2d 100644
--- a/src/gateway/test-helpers.plugin-registry.ts
+++ b/src/gateway/test-helpers.plugin-registry.ts
@@ -22,7 +22,6 @@ function createStubPluginRegistry(): PluginRegistry {
musicGenerationProviders: [],
webFetchProviders: [],
webSearchProviders: [],
- embeddedExtensionFactories: [],
codexAppServerExtensionFactories: [],
agentToolResultMiddlewares: [],
memoryEmbeddingProviders: [],
diff --git a/src/plugins/api-builder.ts b/src/plugins/api-builder.ts
index 1bba2e148c8..84d6d827ad5 100644
--- a/src/plugins/api-builder.ts
+++ b/src/plugins/api-builder.ts
@@ -49,7 +49,6 @@ export type BuildPluginApiParams = {
| "registerContextEngine"
| "registerCompactionProvider"
| "registerAgentHarness"
- | "registerEmbeddedExtensionFactory"
| "registerCodexAppServerExtensionFactory"
| "registerAgentToolResultMiddleware"
| "registerDetachedTaskRuntime"
@@ -105,8 +104,6 @@ const noopRegisterCommand: OpenClawPluginApi["registerCommand"] = () => {};
const noopRegisterContextEngine: OpenClawPluginApi["registerContextEngine"] = () => {};
const noopRegisterCompactionProvider: OpenClawPluginApi["registerCompactionProvider"] = () => {};
const noopRegisterAgentHarness: OpenClawPluginApi["registerAgentHarness"] = () => {};
-const noopRegisterEmbeddedExtensionFactory: OpenClawPluginApi["registerEmbeddedExtensionFactory"] =
- () => {};
const noopRegisterCodexAppServerExtensionFactory: OpenClawPluginApi["registerCodexAppServerExtensionFactory"] =
() => {};
const noopRegisterAgentToolResultMiddleware: OpenClawPluginApi["registerAgentToolResultMiddleware"] =
@@ -180,8 +177,6 @@ export function buildPluginApi(params: BuildPluginApiParams): OpenClawPluginApi
registerCompactionProvider:
handlers.registerCompactionProvider ?? noopRegisterCompactionProvider,
registerAgentHarness: handlers.registerAgentHarness ?? noopRegisterAgentHarness,
- registerEmbeddedExtensionFactory:
- handlers.registerEmbeddedExtensionFactory ?? noopRegisterEmbeddedExtensionFactory,
registerCodexAppServerExtensionFactory:
handlers.registerCodexAppServerExtensionFactory ?? noopRegisterCodexAppServerExtensionFactory,
registerAgentToolResultMiddleware:
diff --git a/src/plugins/captured-registration.ts b/src/plugins/captured-registration.ts
index 02605d426cc..7bbba7dbbca 100644
--- a/src/plugins/captured-registration.ts
+++ b/src/plugins/captured-registration.ts
@@ -1,4 +1,3 @@
-import type { ExtensionFactory } from "@mariozechner/pi-coding-agent";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import type {
AgentToolResultMiddleware,
@@ -43,7 +42,6 @@ export type CapturedPluginRegistration = {
cliRegistrars: CapturedPluginCliRegistration[];
cliBackends: CliBackendPlugin[];
textTransforms: PluginTextTransformRegistration[];
- embeddedExtensionFactories: ExtensionFactory[];
codexAppServerExtensionFactories: CodexAppServerExtensionFactory[];
agentToolResultMiddlewares: PluginAgentToolResultMiddlewareRegistration[];
speechProviders: SpeechProviderPlugin[];
@@ -68,7 +66,6 @@ export function createCapturedPluginRegistration(params?: {
const cliRegistrars: CapturedPluginCliRegistration[] = [];
const cliBackends: CliBackendPlugin[] = [];
const textTransforms: PluginTextTransformRegistration[] = [];
- const embeddedExtensionFactories: ExtensionFactory[] = [];
const codexAppServerExtensionFactories: CodexAppServerExtensionFactory[] = [];
const agentToolResultMiddlewares: PluginAgentToolResultMiddlewareRegistration[] = [];
const speechProviders: SpeechProviderPlugin[] = [];
@@ -95,7 +92,6 @@ export function createCapturedPluginRegistration(params?: {
cliRegistrars,
cliBackends,
textTransforms,
- embeddedExtensionFactories,
codexAppServerExtensionFactories,
agentToolResultMiddlewares,
speechProviders,
@@ -148,9 +144,6 @@ export function createCapturedPluginRegistration(params?: {
registerAgentHarness(harness: AgentHarness) {
agentHarnesses.push(harness);
},
- registerEmbeddedExtensionFactory(factory: ExtensionFactory) {
- embeddedExtensionFactories.push(factory);
- },
registerCodexAppServerExtensionFactory(factory: CodexAppServerExtensionFactory) {
codexAppServerExtensionFactories.push(factory);
},
diff --git a/src/plugins/embedded-extension-factory.ts b/src/plugins/embedded-extension-factory.ts
deleted file mode 100644
index 6348b70e52a..00000000000
--- a/src/plugins/embedded-extension-factory.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import type { ExtensionFactory } from "@mariozechner/pi-coding-agent";
-import { getActivePluginRegistry } from "./runtime.js";
-
-export const PI_EMBEDDED_EXTENSION_RUNTIME_ID = "pi";
-
-export function listEmbeddedExtensionFactories(): ExtensionFactory[] {
- return getActivePluginRegistry()?.embeddedExtensionFactories?.map((entry) => entry.factory) ?? [];
-}
diff --git a/src/plugins/hooks.test-helpers.ts b/src/plugins/hooks.test-helpers.ts
index 91e817f88d8..12ea7b8bcb3 100644
--- a/src/plugins/hooks.test-helpers.ts
+++ b/src/plugins/hooks.test-helpers.ts
@@ -42,7 +42,6 @@ export function createMockPluginRegistry(
musicGenerationProviders: [],
webFetchProviders: [],
webSearchProviders: [],
- embeddedExtensionFactories: [],
codexAppServerExtensionFactories: [],
agentToolResultMiddlewares: [],
memoryEmbeddingProviders: [],
diff --git a/src/plugins/loader.ts b/src/plugins/loader.ts
index 7196b44d860..0d34e3e92c4 100644
--- a/src/plugins/loader.ts
+++ b/src/plugins/loader.ts
@@ -292,7 +292,6 @@ type PluginRegistrySnapshot = {
musicGenerationProviders: PluginRegistry["musicGenerationProviders"];
webFetchProviders: PluginRegistry["webFetchProviders"];
webSearchProviders: PluginRegistry["webSearchProviders"];
- embeddedExtensionFactories: PluginRegistry["embeddedExtensionFactories"];
codexAppServerExtensionFactories: PluginRegistry["codexAppServerExtensionFactories"];
agentToolResultMiddlewares: PluginRegistry["agentToolResultMiddlewares"];
memoryEmbeddingProviders: PluginRegistry["memoryEmbeddingProviders"];
@@ -331,7 +330,6 @@ function snapshotPluginRegistry(registry: PluginRegistry): PluginRegistrySnapsho
musicGenerationProviders: [...registry.musicGenerationProviders],
webFetchProviders: [...registry.webFetchProviders],
webSearchProviders: [...registry.webSearchProviders],
- embeddedExtensionFactories: [...registry.embeddedExtensionFactories],
codexAppServerExtensionFactories: [...registry.codexAppServerExtensionFactories],
agentToolResultMiddlewares: [...registry.agentToolResultMiddlewares],
memoryEmbeddingProviders: [...registry.memoryEmbeddingProviders],
@@ -369,7 +367,6 @@ function restorePluginRegistry(registry: PluginRegistry, snapshot: PluginRegistr
registry.musicGenerationProviders = snapshot.arrays.musicGenerationProviders;
registry.webFetchProviders = snapshot.arrays.webFetchProviders;
registry.webSearchProviders = snapshot.arrays.webSearchProviders;
- registry.embeddedExtensionFactories = snapshot.arrays.embeddedExtensionFactories;
registry.codexAppServerExtensionFactories = snapshot.arrays.codexAppServerExtensionFactories;
registry.agentToolResultMiddlewares = snapshot.arrays.agentToolResultMiddlewares;
registry.memoryEmbeddingProviders = snapshot.arrays.memoryEmbeddingProviders;
diff --git a/src/plugins/registry-empty.ts b/src/plugins/registry-empty.ts
index 96145873390..96d77148d28 100644
--- a/src/plugins/registry-empty.ts
+++ b/src/plugins/registry-empty.ts
@@ -20,7 +20,6 @@ export function createEmptyPluginRegistry(): PluginRegistry {
musicGenerationProviders: [],
webFetchProviders: [],
webSearchProviders: [],
- embeddedExtensionFactories: [],
codexAppServerExtensionFactories: [],
agentToolResultMiddlewares: [],
memoryEmbeddingProviders: [],
diff --git a/src/plugins/registry-types.ts b/src/plugins/registry-types.ts
index 1c313a048a8..223ed429070 100644
--- a/src/plugins/registry-types.ts
+++ b/src/plugins/registry-types.ts
@@ -1,4 +1,3 @@
-import type { ExtensionFactory } from "@mariozechner/pi-coding-agent";
import type { AgentHarness } from "../agents/harness/types.js";
import type { ChannelPlugin } from "../channels/plugins/types.plugin.js";
import type { OperatorScope } from "../gateway/operator-scopes.js";
@@ -152,14 +151,6 @@ export type PluginWebSearchProviderRegistration =
PluginOwnedProviderRegistration;
export type PluginMemoryEmbeddingProviderRegistration =
PluginOwnedProviderRegistration;
-export type PluginEmbeddedExtensionFactoryRegistration = {
- pluginId: string;
- pluginName?: string;
- rawFactory: ExtensionFactory;
- factory: ExtensionFactory;
- source: string;
- rootDir?: string;
-};
export type PluginCodexAppServerExtensionFactoryRegistration = {
pluginId: string;
pluginName?: string;
@@ -323,7 +314,6 @@ export type PluginRegistry = {
musicGenerationProviders: PluginMusicGenerationProviderRegistration[];
webFetchProviders: PluginWebFetchProviderRegistration[];
webSearchProviders: PluginWebSearchProviderRegistration[];
- embeddedExtensionFactories: PluginEmbeddedExtensionFactoryRegistration[];
codexAppServerExtensionFactories: PluginCodexAppServerExtensionFactoryRegistration[];
agentToolResultMiddlewares: PluginAgentToolResultMiddlewareRegistration[];
memoryEmbeddingProviders: PluginMemoryEmbeddingProviderRegistration[];
diff --git a/src/plugins/registry.ts b/src/plugins/registry.ts
index 75bfad6a3f6..54e0ad6519d 100644
--- a/src/plugins/registry.ts
+++ b/src/plugins/registry.ts
@@ -1,5 +1,4 @@
import path from "node:path";
-import type { ExtensionFactory } from "@mariozechner/pi-coding-agent";
import {
getRegisteredAgentHarness,
registerAgentHarness as registerGlobalAgentHarness,
@@ -43,7 +42,6 @@ import {
getRegisteredCompactionProvider,
registerCompactionProvider,
} from "./compaction-provider.js";
-import { PI_EMBEDDED_EXTENSION_RUNTIME_ID } from "./embedded-extension-factory.js";
import { normalizePluginHttpPath } from "./http-path.js";
import { findOverlappingPluginHttpRoute } from "./http-route-overlap.js";
import {
@@ -229,69 +227,6 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) {
registry.diagnostics.push(diag);
};
- const registerPiEmbeddedExtensionFactory = (
- record: PluginRecord,
- factory: Parameters[0],
- ) => {
- if (record.origin !== "bundled") {
- pushDiagnostic({
- level: "error",
- pluginId: record.id,
- source: record.source,
- message: "only bundled plugins can register Pi embedded extension factories",
- });
- return;
- }
- if (
- !(record.contracts?.embeddedExtensionFactories ?? []).includes(
- PI_EMBEDDED_EXTENSION_RUNTIME_ID,
- )
- ) {
- pushDiagnostic({
- level: "error",
- pluginId: record.id,
- source: record.source,
- message:
- 'plugin must declare contracts.embeddedExtensionFactories: ["pi"] to register Pi embedded extension factories',
- });
- return;
- }
- if (typeof (factory as unknown) !== "function") {
- pushDiagnostic({
- level: "error",
- pluginId: record.id,
- source: record.source,
- message: "embedded extension factory must be a function",
- });
- return;
- }
- if (
- registry.embeddedExtensionFactories.some(
- (entry) => entry.pluginId === record.id && entry.rawFactory === factory,
- )
- ) {
- return;
- }
- const safeFactory: ExtensionFactory = async (pi) => {
- try {
- await factory(pi);
- } catch (error) {
- const detail = error instanceof Error ? error.message : String(error);
- registryParams.logger.warn(
- `[plugins] embedded extension factory failed for ${record.id}: ${detail}`,
- );
- }
- };
- registry.embeddedExtensionFactories.push({
- pluginId: record.id,
- pluginName: record.name,
- rawFactory: factory,
- factory: safeFactory,
- source: record.source,
- rootDir: record.rootDir,
- });
- };
-
const registerCodexAppServerExtensionFactory = (
record: PluginRecord,
factory: Parameters[0],
@@ -1585,9 +1520,6 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) {
}
registerCompactionProvider(provider, { ownerPluginId: record.id });
},
- registerEmbeddedExtensionFactory: (factory) => {
- registerPiEmbeddedExtensionFactory(record, factory);
- },
registerCodexAppServerExtensionFactory: (factory) => {
registerCodexAppServerExtensionFactory(record, factory);
},
diff --git a/src/plugins/status.test-helpers.ts b/src/plugins/status.test-helpers.ts
index a00068d5cbd..d51746e7d77 100644
--- a/src/plugins/status.test-helpers.ts
+++ b/src/plugins/status.test-helpers.ts
@@ -129,7 +129,6 @@ export function createPluginLoadResult(
musicGenerationProviders: [],
webFetchProviders: [],
webSearchProviders: [],
- embeddedExtensionFactories: [],
codexAppServerExtensionFactories: [],
agentToolResultMiddlewares: [],
memoryEmbeddingProviders: [],
diff --git a/src/plugins/types.ts b/src/plugins/types.ts
index 67c6de1ec1e..d802bdc4204 100644
--- a/src/plugins/types.ts
+++ b/src/plugins/types.ts
@@ -1,7 +1,7 @@
import type { IncomingMessage, ServerResponse } from "node:http";
import type { AgentMessage } from "@mariozechner/pi-agent-core";
import type { StreamFn } from "@mariozechner/pi-agent-core";
-import type { ExtensionFactory, ModelRegistry } from "@mariozechner/pi-coding-agent";
+import type { ModelRegistry } from "@mariozechner/pi-coding-agent";
import type { Command } from "commander";
import type {
ApiKeyCredential,
@@ -2152,16 +2152,15 @@ export type OpenClawPluginApi = {
/** Register an agent harness implementation. */
registerAgentHarness: (harness: AgentHarness) => void;
/**
- * Register a Pi embedded extension factory for OpenClaw embedded runs.
- *
- * @deprecated This is a bundled compatibility seam. New tool-result transforms
- * should use `registerAgentToolResultMiddleware(...)` and declare
- * `contracts.agentToolResultMiddleware` for the targeted runtimes.
+ * Register a Codex app-server extension factory for Codex harness tool-result
+ * middleware. Only bundled plugins may use this seam, and
+ * `contracts.embeddedExtensionFactories` must include `"codex-app-server"`.
*/
- registerEmbeddedExtensionFactory: (factory: ExtensionFactory) => void;
- /** Register a Codex app-server extension factory for Codex harness tool-result middleware. Only bundled plugins may use this seam, and `contracts.embeddedExtensionFactories` must include `"codex-app-server"`. */
registerCodexAppServerExtensionFactory: (factory: CodexAppServerExtensionFactory) => void;
- /** Register runtime-neutral tool-result middleware. Declare `contracts.agentToolResultMiddleware` for every targeted runtime. */
+ /**
+ * Register runtime-neutral tool-result middleware. Declare
+ * `contracts.agentToolResultMiddleware` for every targeted runtime.
+ */
registerAgentToolResultMiddleware: (
handler: AgentToolResultMiddleware,
options?: AgentToolResultMiddlewareOptions,
diff --git a/src/test-utils/channel-plugins.ts b/src/test-utils/channel-plugins.ts
index ea73178109a..53062f220f9 100644
--- a/src/test-utils/channel-plugins.ts
+++ b/src/test-utils/channel-plugins.ts
@@ -35,7 +35,6 @@ export const createTestRegistry = (channels: TestChannelRegistration[] = []): Pl
musicGenerationProviders: [],
webFetchProviders: [],
webSearchProviders: [],
- embeddedExtensionFactories: [],
codexAppServerExtensionFactories: [],
agentToolResultMiddlewares: [],
memoryEmbeddingProviders: [],
diff --git a/test/helpers/plugins/plugin-api.ts b/test/helpers/plugins/plugin-api.ts
index 7c2ec4890cc..e8fed03cf37 100644
--- a/test/helpers/plugins/plugin-api.ts
+++ b/test/helpers/plugins/plugin-api.ts
@@ -42,7 +42,6 @@ export function createTestPluginApi(api: TestPluginApiInput = {}): OpenClawPlugi
registerContextEngine() {},
registerCompactionProvider() {},
registerAgentHarness() {},
- registerEmbeddedExtensionFactory() {},
registerCodexAppServerExtensionFactory() {},
registerAgentToolResultMiddleware() {},
registerDetachedTaskRuntime() {},