mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 06:50:43 +00:00
fix(plugins): remove Pi tool result compat
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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.
|
||||
<Warning>
|
||||
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.
|
||||
</Warning>
|
||||
|
||||
## Why this changed
|
||||
@@ -91,19 +94,12 @@ releases.
|
||||
|
||||
<Steps>
|
||||
<Step title="Migrate Pi tool-result extensions to middleware">
|
||||
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.
|
||||
|
||||
</Step>
|
||||
|
||||
@@ -624,8 +618,8 @@ canonical replacement.
|
||||
|
||||
<Accordion title="Embedded extension factories → agent tool-result middleware">
|
||||
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`.
|
||||
</Accordion>
|
||||
|
||||
@@ -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 |
|
||||
|
||||
<Note>
|
||||
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.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Legacy Pi extension factories">
|
||||
`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.
|
||||
</Accordion>
|
||||
|
||||
### Gateway discovery registration
|
||||
|
||||
@@ -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<string, Function>();
|
||||
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();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -88,7 +88,6 @@ const createRegistry = (diagnostics: PluginDiagnostic[]): PluginRegistry => ({
|
||||
webFetchProviders: [],
|
||||
webSearchProviders: [],
|
||||
memoryEmbeddingProviders: [],
|
||||
embeddedExtensionFactories: [],
|
||||
codexAppServerExtensionFactories: [],
|
||||
agentToolResultMiddlewares: [],
|
||||
textTransforms: [],
|
||||
|
||||
@@ -22,7 +22,6 @@ function createStubPluginRegistry(): PluginRegistry {
|
||||
musicGenerationProviders: [],
|
||||
webFetchProviders: [],
|
||||
webSearchProviders: [],
|
||||
embeddedExtensionFactories: [],
|
||||
codexAppServerExtensionFactories: [],
|
||||
agentToolResultMiddlewares: [],
|
||||
memoryEmbeddingProviders: [],
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
},
|
||||
|
||||
@@ -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) ?? [];
|
||||
}
|
||||
@@ -42,7 +42,6 @@ export function createMockPluginRegistry(
|
||||
musicGenerationProviders: [],
|
||||
webFetchProviders: [],
|
||||
webSearchProviders: [],
|
||||
embeddedExtensionFactories: [],
|
||||
codexAppServerExtensionFactories: [],
|
||||
agentToolResultMiddlewares: [],
|
||||
memoryEmbeddingProviders: [],
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -20,7 +20,6 @@ export function createEmptyPluginRegistry(): PluginRegistry {
|
||||
musicGenerationProviders: [],
|
||||
webFetchProviders: [],
|
||||
webSearchProviders: [],
|
||||
embeddedExtensionFactories: [],
|
||||
codexAppServerExtensionFactories: [],
|
||||
agentToolResultMiddlewares: [],
|
||||
memoryEmbeddingProviders: [],
|
||||
|
||||
@@ -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<WebSearchProviderPlugin>;
|
||||
export type PluginMemoryEmbeddingProviderRegistration =
|
||||
PluginOwnedProviderRegistration<MemoryEmbeddingProviderAdapter>;
|
||||
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[];
|
||||
|
||||
@@ -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<OpenClawPluginApi["registerEmbeddedExtensionFactory"]>[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<OpenClawPluginApi["registerCodexAppServerExtensionFactory"]>[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);
|
||||
},
|
||||
|
||||
@@ -129,7 +129,6 @@ export function createPluginLoadResult(
|
||||
musicGenerationProviders: [],
|
||||
webFetchProviders: [],
|
||||
webSearchProviders: [],
|
||||
embeddedExtensionFactories: [],
|
||||
codexAppServerExtensionFactories: [],
|
||||
agentToolResultMiddlewares: [],
|
||||
memoryEmbeddingProviders: [],
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -35,7 +35,6 @@ export const createTestRegistry = (channels: TestChannelRegistration[] = []): Pl
|
||||
musicGenerationProviders: [],
|
||||
webFetchProviders: [],
|
||||
webSearchProviders: [],
|
||||
embeddedExtensionFactories: [],
|
||||
codexAppServerExtensionFactories: [],
|
||||
agentToolResultMiddlewares: [],
|
||||
memoryEmbeddingProviders: [],
|
||||
|
||||
@@ -42,7 +42,6 @@ export function createTestPluginApi(api: TestPluginApiInput = {}): OpenClawPlugi
|
||||
registerContextEngine() {},
|
||||
registerCompactionProvider() {},
|
||||
registerAgentHarness() {},
|
||||
registerEmbeddedExtensionFactory() {},
|
||||
registerCodexAppServerExtensionFactory() {},
|
||||
registerAgentToolResultMiddleware() {},
|
||||
registerDetachedTaskRuntime() {},
|
||||
|
||||
Reference in New Issue
Block a user