openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
111 lines (110 loc) • 5.22 kB
JavaScript
import { i as executeSqliteQuerySync, o as getNodeSqliteKysely, p as sql } from "./kysely-sync-DUWzQvCU.mjs";
import { b as extractSqliteTableSchema } from "./sqlite-schema-facts-BVf0E_0z.mjs";
import { i as tableExists } from "./openclaw-state-db-schema-helpers-DKz5xGgh.mjs";
import { t as OPENCLAW_STATE_SCHEMA_SQL } from "./openclaw-state-schema-Cr2v_hbj.mjs";
import { l as runOpenClawStateWriteTransaction } from "./openclaw-state-db-DJZ7EKoI.mjs";
import { t as isWorkshopChangeAction } from "./skill-versions-DpMGXZ-J.mjs";
//#region src/skills/workshop/changes.kernel.ts
const WORKSHOP_ACTORS = [
"agent",
"review",
"curator",
"user"
];
function isWorkshopActor(value) {
return WORKSHOP_ACTORS.some((actor) => actor === value);
}
const MAX_CHANGES_PER_AGENT = 500;
/** Appends one change and keeps the newest rows per agent. */
function recordWorkshopChangeInDatabase(database, change) {
const { db } = database;
db.exec(extractSqliteTableSchema(OPENCLAW_STATE_SCHEMA_SQL, "skill_workshop_changes", { endMarker: "ON skill_workshop_changes(agent_id, created_at_ms);" }));
const kysely = getNodeSqliteKysely(db);
executeSqliteQuerySync(db, kysely.insertInto("skill_workshop_changes").values({
change_id: change.id,
agent_id: change.agentId,
skill_name: change.skillName,
action: change.action,
actor: change.actor,
summary: change.summary,
version_id: change.versionId ?? null,
session_key: change.sessionKey ?? null,
run_id: change.runId ?? null,
created_at_ms: change.createdAtMs
}));
executeSqliteQuerySync(db, kysely.deleteFrom("skill_workshop_changes").where("agent_id", "=", change.agentId).where("change_id", "not in", kysely.selectFrom("skill_workshop_changes").select("change_id").where("agent_id", "=", change.agentId).orderBy("created_at_ms", "desc").orderBy(sql`rowid`, "desc").limit(MAX_CHANGES_PER_AGENT)));
}
/** Newest first; a database that never recorded a change has no table yet. */
function listWorkshopChangesInDatabase(db, query) {
if (!tableExists(db, "skill_workshop_changes")) return [];
let select = getNodeSqliteKysely(db).selectFrom("skill_workshop_changes").selectAll().where("agent_id", "=", query.agentId);
if (query.beforeMs !== void 0) select = select.where("created_at_ms", "<", query.beforeMs);
if (query.runId !== void 0) select = select.where("run_id", "=", query.runId);
return executeSqliteQuerySync(db, select.orderBy("created_at_ms", "desc").orderBy(sql`rowid`, "desc").limit(query.limit)).rows.flatMap((row) => {
if (!isWorkshopChangeAction(row.action) || !isWorkshopActor(row.actor)) return [];
return [{
id: row.change_id,
agentId: row.agent_id,
skillName: row.skill_name,
action: row.action,
actor: row.actor,
summary: row.summary,
createdAtMs: row.created_at_ms,
...row.version_id ? { versionId: row.version_id } : {},
...row.session_key ? { sessionKey: row.session_key } : {},
...row.run_id ? { runId: row.run_id } : {}
}];
});
}
//#endregion
//#region src/skills/workshop/skill-usage.kernel.ts
function readSkillUsageInDatabase(database, skillFiles) {
if (skillFiles.length === 0) return [];
const kysely = getNodeSqliteKysely(database.db);
return executeSqliteQuerySync(database.db, kysely.selectFrom("skill_usage").select([
"skill_file",
"last_used_at_ms",
"use_count"
]).where("skill_file", "in", skillFiles)).rows.map((row) => ({
skillFile: row.skill_file,
useCount: row.use_count,
lastUsedAtMs: row.last_used_at_ms
}));
}
function recordSkillUsageInDatabase(database, event) {
const kysely = getNodeSqliteKysely(database.db);
executeSqliteQuerySync(database.db, kysely.insertInto("skill_usage").values({
skill_file: event.skillFile,
skill_key: event.skillKey,
skill_name: event.skillName,
skill_source: event.skillSource,
first_used_at_ms: event.ts,
last_used_at_ms: event.ts,
use_count: 1,
last_agent_id: event.agentId ?? null
}).onConflict((conflict) => conflict.column("skill_file").doUpdateSet((eb) => ({
skill_key: event.skillKey,
skill_name: event.skillName,
skill_source: event.skillSource,
first_used_at_ms: eb.fn("min", [eb.ref("first_used_at_ms"), eb.val(event.ts)]),
last_used_at_ms: eb.fn("max", [eb.ref("last_used_at_ms"), eb.val(event.ts)]),
use_count: eb("use_count", "+", 1),
last_agent_id: eb.case().when("last_used_at_ms", "<=", event.ts).then(event.agentId ?? null).else(eb.ref("last_agent_id")).end()
}))));
}
//#endregion
//#region src/skills/workshop/changes.worker.ts
const skillWorkshopOperations = {
"skills.workshop.changes.list": (input, { open }) => listWorkshopChangesInDatabase(open().db, input),
"skills.workshop.changes.record": (input, { open, stateOptions }) => runOpenClawStateWriteTransaction((current) => recordWorkshopChangeInDatabase(current, input), {
database: open(),
...stateOptions()
}, { operationLabel: "skill-workshop.changes.record" }),
"skills.usage.read": (input, { open }) => readSkillUsageInDatabase(open(), input.skillFiles),
"skills.usage.record": (input, { open, stateOptions }) => runOpenClawStateWriteTransaction((current) => recordSkillUsageInDatabase(current, input), {
database: open(),
...stateOptions()
})
};
//#endregion
export { skillWorkshopOperations };