refactor(state): remove the dead agent lease scope (#121615)

* refactor(state): remove dead agent lease scope

* docs(refactor): remove stale QMD lease claim
This commit is contained in:
Peter Steinberger
2026-08-10 17:01:53 -07:00
committed by GitHub
parent 94490bd69b
commit e581acbf81
4 changed files with 17 additions and 49 deletions
+5 -6
View File
@@ -1469,10 +1469,10 @@ create` validates the written archive by default; `--no-verify` is the
bridge; they are not a second canonical transcript store.
- QMD's own `index.sqlite`, YAML collection config, and model downloads remain
external-tool artifacts under `~/.openclaw/agents/<agentId>/qmd`; they are not
mirrored into `plugin_blob_entries`. OpenClaw-owned QMD coordination is
database-first: shared `state_leases` serialize embeds globally and per-agent
`state_leases` serialize collection/update/embed writers. Runtime creates no
QMD lock sidecars.
mirrored into `plugin_blob_entries`. Current host-owned lease consumers use
shared `state_leases`; the per-agent `state_leases` table remains in the
canonical schema but has no runtime tenants. Runtime creates no QMD lock
sidecars.
- The optional `memory-lancedb` plugin no longer creates
`~/.openclaw/memory/lancedb` as an implicit OpenClaw-managed store. It is an
external LanceDB backend and stays disabled until the operator configures an
@@ -2044,8 +2044,7 @@ payload.
`gateway_locks` and no longer exposes a file-lock directory seam.
- Generic plugin SDK dedupe persistence no longer uses file locks or JSON
files; it writes shared SQLite plugin-state rows. Done.
- QMD coordination uses a shared SQLite lease for embeds and a per-agent
SQLite lease for every collection/update/embed writer. Runtime no longer
- QMD writers no longer take OpenClaw state leases. Runtime no longer
creates `qmd/embed.lock.lock` or `agents/<agentId>/qmd-write.lock.lock`;
Doctor removes only definitely stale retired sidecars. Done.
@@ -730,7 +730,6 @@ describe("CLI attempt execution", () => {
DELETE FROM auth_profile_store;
DELETE FROM auth_profile_state;
DELETE FROM cache_entries;
DELETE FROM state_leases;
`);
},
database,
-2
View File
@@ -4,7 +4,6 @@ import { pathToFileURL } from "node:url";
import { afterEach, describe, expect, it } from "vitest";
import { executeSqliteQuerySync, getNodeSqliteKysely } from "../infra/kysely-sync.js";
import { withOpenClawTestState } from "../test-utils/openclaw-test-state.js";
import { closeOpenClawAgentDatabasesForTest } from "./openclaw-agent-db.js";
import type { DB as OpenClawStateKyselyDatabase } from "./openclaw-state-db.generated.js";
import {
closeOpenClawStateDatabaseForTest,
@@ -15,7 +14,6 @@ import { withOpenClawStateLease } from "./openclaw-state-lease.js";
type LeaseDatabase = Pick<OpenClawStateKyselyDatabase, "state_leases">;
afterEach(() => {
closeOpenClawAgentDatabasesForTest();
closeOpenClawStateDatabaseForTest();
});
+12 -40
View File
@@ -10,11 +10,6 @@ import {
import { isSqliteLockError } from "../infra/sqlite-transaction.js";
import { loggingState } from "../logging/state.js";
import { MAX_TIMER_TIMEOUT_MS } from "../shared/number-coercion.js";
import type { DB as OpenClawAgentKyselyDatabase } from "./openclaw-agent-db.generated.js";
import {
openOpenClawAgentDatabase,
runOpenClawAgentWriteTransaction,
} from "./openclaw-agent-db.js";
import type { DB as OpenClawStateKyselyDatabase } from "./openclaw-state-db.generated.js";
import {
openOpenClawStateDatabase,
@@ -23,12 +18,12 @@ import {
} from "./openclaw-state-db.js";
type LeaseDatabase = Pick<OpenClawStateKyselyDatabase, "state_leases">;
type AgentLeaseDatabase = Pick<OpenClawAgentKyselyDatabase, "state_leases">;
type LeaseKysely = ReturnType<typeof getNodeSqliteKysely<LeaseDatabase>>;
type OpenClawStateLeaseDatabase =
| { scope: "shared"; options?: OpenClawStateDatabaseOptions }
| { scope: "agent"; agentId: string; path?: string };
type OpenClawStateLeaseDatabase = {
scope: "shared";
options?: OpenClawStateDatabaseOptions;
};
type OpenClawStateLeaseOptions = {
scope: string;
@@ -157,11 +152,8 @@ function validateOptions(options: OpenClawStateLeaseOptions) {
if (typeof database !== "object" || database === null || Array.isArray(database)) {
throw invalidInput("state lease database must be an object");
}
if (database.scope !== "shared" && database.scope !== "agent") {
throw invalidInput("state lease database scope must be shared or agent");
}
if (database.scope === "agent") {
validateNonEmptyString(database.agentId, "state lease agent database agentId");
if (database.scope !== "shared") {
throw invalidInput("state lease database scope must be shared");
}
const leaseLabel =
options.leaseLabel === undefined
@@ -217,41 +209,21 @@ function withLeaseWriteTransaction<T>(
operation: (db: DatabaseSync, kysely: LeaseKysely) => T,
busyTimeoutMs = LEASE_DB_BUSY_TIMEOUT_MS,
): T {
if (database.scope === "shared") {
const stateDatabase = openOpenClawStateDatabase(database.options);
const run = () =>
runOpenClawStateWriteTransaction(
({ db }) => operation(db, getNodeSqliteKysely<LeaseDatabase>(db)),
database.options,
{ operationLabel, busyTimeoutMs },
);
return withBusyTimeout(stateDatabase.db, busyTimeoutMs, run);
}
const agentOptions = {
agentId: database.agentId,
...(database.path ? { path: database.path } : {}),
};
const agentDatabase = openOpenClawAgentDatabase(agentOptions);
const stateDatabase = openOpenClawStateDatabase(database.options);
const run = () =>
runOpenClawAgentWriteTransaction(
({ db }) => operation(db, getNodeSqliteKysely<AgentLeaseDatabase>(db)),
agentOptions,
runOpenClawStateWriteTransaction(
({ db }) => operation(db, getNodeSqliteKysely<LeaseDatabase>(db)),
database.options,
{ operationLabel, busyTimeoutMs },
);
return withBusyTimeout(agentDatabase.db, busyTimeoutMs, run);
return withBusyTimeout(stateDatabase.db, busyTimeoutMs, run);
}
function withLeaseRead<T>(
database: OpenClawStateLeaseDatabase,
operation: (db: DatabaseSync, kysely: LeaseKysely) => T,
): T {
const sqlite =
database.scope === "shared"
? openOpenClawStateDatabase(database.options).db
: openOpenClawAgentDatabase({
agentId: database.agentId,
...(database.path ? { path: database.path } : {}),
}).db;
const sqlite = openOpenClawStateDatabase(database.options).db;
return operation(sqlite, getNodeSqliteKysely<LeaseDatabase>(sqlite));
}