mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 09:30:43 +00:00
Context engine/plugins: accept third-party engines whose info.id differs from registered slot id (#66601)
This commit is contained in:
@@ -15,6 +15,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Cron/delivery: treat explicit `delivery.mode: "none"` runs as not requested even if the runner reports `delivered: false`, so no-delivery cron jobs no longer persist false delivery failures or errors. (#69285) Thanks @matsuri1987.
|
||||
- Plugins/install: repair active and default-enabled bundled plugin runtime dependencies before import in packaged installs, so bundled Discord, WhatsApp, Slack, Telegram, and provider plugins work without putting their dependency trees in core.
|
||||
- BlueBubbles: raise the outbound `/api/v1/message/text` send timeout default from 10s to 30s, and add a configurable `channels.bluebubbles.sendTimeoutMs` (also per-account) so macOS 26 setups where Private API iMessage sends stall for 60+ seconds no longer silently lose messages at the 10s abort. Probes, chat lookups, and health checks keep the shorter 10s default. Fixes #67486. (#69193) Thanks @omarshahine.
|
||||
- Context engine/plugins: stop rejecting third-party context engines whose `info.id` differs from the registered plugin slot id. The strict-match contract added in 2026.4.14 broke `lossless-claw` and other plugins whose internal engine id does not equal the slot id they are registered under, producing repeated `info.id must match registered id` lane failures on every turn. Fixes #66601. (#66678) Thanks @GodsBoy.
|
||||
|
||||
## 2026.4.20
|
||||
|
||||
|
||||
@@ -796,15 +796,20 @@ describe("Invalid engine fallback", () => {
|
||||
expect(console.error).toHaveBeenCalledWith(expect.stringContaining("missing info"));
|
||||
});
|
||||
|
||||
it("falls back to default engine when info.id mismatches the registered id", async () => {
|
||||
const engineId = `mismatched-info-id-${Date.now().toString(36)}`;
|
||||
it("accepts resolved engines whose info.id differs from the registered slot id (#66601)", async () => {
|
||||
// Regression for openclaw/openclaw#66601: third-party plugins like
|
||||
// lossless-claw register under an external slot id ("lossless-claw") but
|
||||
// the ContextEngine they return uses the plugin's own internal id
|
||||
// (e.g. "lcm"). That id is metadata, not the lookup key.
|
||||
const engineId = `plugin-slot-${Date.now().toString(36)}`;
|
||||
const internalInfoId = "lcm";
|
||||
registerContextEngine(
|
||||
engineId,
|
||||
() =>
|
||||
({
|
||||
info: { id: "legacy", name: "Broken Engine" },
|
||||
info: { id: internalInfoId, name: "Lossless Context Manager", version: "0.5.2" },
|
||||
async ingest() {
|
||||
return { ingested: false };
|
||||
return { ingested: true };
|
||||
},
|
||||
async assemble({ messages }: { messages: AgentMessage[] }) {
|
||||
return { messages, estimatedTokens: 0 };
|
||||
@@ -816,10 +821,15 @@ describe("Invalid engine fallback", () => {
|
||||
);
|
||||
|
||||
const engine = await resolveContextEngine(configWithSlot(engineId));
|
||||
expect(engine.info.id).toBe("legacy");
|
||||
expect(console.error).toHaveBeenCalledWith(
|
||||
expect.stringContaining(`info.id must match registered id "${engineId}"`),
|
||||
);
|
||||
// The engine's own info.id is preserved; resolution does not overwrite it.
|
||||
expect(engine.info.id).toBe(internalInfoId);
|
||||
expect(engine.info.name).toBe("Lossless Context Manager");
|
||||
// And the engine is usable through the wrapper.
|
||||
const result = await engine.assemble({
|
||||
sessionId: "s1",
|
||||
messages: [makeMockMessage("user", "hello")],
|
||||
});
|
||||
expect(result.estimatedTokens).toBe(0);
|
||||
});
|
||||
|
||||
it("falls back to default engine when resolved engine omits lifecycle methods", async () => {
|
||||
|
||||
@@ -421,11 +421,13 @@ function describeResolvedContextEngineContractError(
|
||||
issues.push("missing info");
|
||||
} else {
|
||||
const infoRecord = info as Record<string, unknown>;
|
||||
// Engines own their internal info.id; it is metadata, not a handle into the
|
||||
// registry. The registered id (plugin slot id) and the engine's own id are
|
||||
// allowed to differ, so we only require that info.id is a non-empty string
|
||||
// for display/logging purposes and do not enforce equality with engineId.
|
||||
const infoId = typeof infoRecord.id === "string" ? infoRecord.id.trim() : "";
|
||||
if (!infoId) {
|
||||
issues.push("missing info.id");
|
||||
} else if (infoId !== engineId) {
|
||||
issues.push(`info.id must match registered id "${engineId}"`);
|
||||
}
|
||||
if (typeof infoRecord.name !== "string" || !infoRecord.name.trim()) {
|
||||
issues.push("missing info.name");
|
||||
|
||||
Reference in New Issue
Block a user