From ecc311d9101b34ddfe1aa4168a01b199c7d4ea33 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Tue, 11 Aug 2026 11:48:52 -0700 Subject: [PATCH] fix(agents): bound rehearsal inventory at 2048 --- src/commands/agents.db-rehearsal.test.ts | 48 ++++++++++++++++++++++++ src/commands/agents.db-rehearsal.ts | 2 +- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/src/commands/agents.db-rehearsal.test.ts b/src/commands/agents.db-rehearsal.test.ts index c870201ea359..e6d63ccf7ab2 100644 --- a/src/commands/agents.db-rehearsal.test.ts +++ b/src/commands/agents.db-rehearsal.test.ts @@ -161,6 +161,54 @@ describe("agents database rehearsal", () => { expect(result.complete).toBe(true); }); + it("accepts exactly 2048 logical inventory references", async () => { + const stateRoot = await makeRoot(); + const configPath = path.join(stateRoot, "openclaw.json"); + const entries = Object.fromEntries( + Array.from({ length: 1024 }, (_, index) => [ + `agent-${index}`, + index === 0 ? { default: true } : {}, + ]), + ); + await fsp.writeFile( + configPath, + JSON.stringify({ agents: { entries }, plugins: { enabled: false } }), + ); + + const result = (await runAgentDatabaseRehearsal({ + schemaVersion: 1, + mode: "inventory", + stateRoot, + configPath, + })) as Extract; + + expect(result.references).toHaveLength(2048); + }); + + it("rejects the 2049th logical inventory reference", async () => { + const stateRoot = await makeRoot(); + const configPath = path.join(stateRoot, "openclaw.json"); + const entries = Object.fromEntries( + Array.from({ length: 1025 }, (_, index) => [ + `agent-${index}`, + index === 0 ? { default: true } : {}, + ]), + ); + await fsp.writeFile( + configPath, + JSON.stringify({ agents: { entries }, plugins: { enabled: false } }), + ); + + await expect( + runAgentDatabaseRehearsal({ + schemaVersion: 1, + mode: "inventory", + stateRoot, + configPath, + }), + ).rejects.toMatchObject({ code: "inventory-limit-exceeded" }); + }); + it("rejects unsupported plugin persistence before validating or opening any database", async () => { const root = await makeRoot(); await expect( diff --git a/src/commands/agents.db-rehearsal.ts b/src/commands/agents.db-rehearsal.ts index 6e60d4890d9f..6dd840355fa2 100644 --- a/src/commands/agents.db-rehearsal.ts +++ b/src/commands/agents.db-rehearsal.ts @@ -44,7 +44,7 @@ import { VERSION } from "../version.js"; const REHEARSAL_SCHEMA_VERSION = 1; const REHEARSAL_REQUEST_MAX_BYTES = 256 * 1024; const REHEARSAL_MAX_AGENT_DATABASES = 256; -const REHEARSAL_MAX_INVENTORY_REFERENCES = 256; +const REHEARSAL_MAX_INVENTORY_REFERENCES = 2048; type RehearsalMode = "inventory" | "migrate" | "read-only";