Files
wehub-resource-sync 555e282cc4
pi-agent-plugin checks / lint (push) Has been cancelled
pi-agent-plugin checks / test (20) (push) Has been cancelled
pi-agent-plugin checks / test (22) (push) Has been cancelled
pi-agent-plugin checks / build (push) Has been cancelled
TypeScript SDK CI / check_changes (push) Has been cancelled
TypeScript SDK CI / changelog_check (push) Has been cancelled
ci / changelog_check (push) Has been cancelled
ci / check_changes (push) Has been cancelled
ci / build_mem0 (3.10) (push) Has been cancelled
ci / build_mem0 (3.11) (push) Has been cancelled
ci / build_mem0 (3.12) (push) Has been cancelled
CLI Node CI / lint (push) Has been cancelled
CLI Node CI / test (20) (push) Has been cancelled
CLI Node CI / test (22) (push) Has been cancelled
CLI Node CI / build (push) Has been cancelled
CLI Python CI / lint (push) Has been cancelled
CLI Python CI / test (3.10) (push) Has been cancelled
CLI Python CI / test (3.11) (push) Has been cancelled
CLI Python CI / test (3.12) (push) Has been cancelled
CLI Python CI / build (push) Has been cancelled
openclaw checks / lint (push) Has been cancelled
openclaw checks / test (20) (push) Has been cancelled
openclaw checks / test (22) (push) Has been cancelled
openclaw checks / build (push) Has been cancelled
opencode-plugin checks / build (push) Has been cancelled
TypeScript SDK CI / build_ts_sdk (20) (push) Has been cancelled
TypeScript SDK CI / build_ts_sdk (22) (push) Has been cancelled
TypeScript SDK CI / integration_ts_sdk (20) (push) Has been cancelled
TypeScript SDK CI / integration_ts_sdk (22) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:03:45 +08:00

160 lines
4.6 KiB
TypeScript

/**
* Public Artifacts Provider for OpenClaw memory-wiki bridge mode.
*
* Exposes Mem0 memories and dream state as artifacts that can be
* consumed by other plugins (e.g., memory-wiki in bridge mode).
*/
import type { Mem0Provider, MemoryItem, Mem0Config } from "./types.ts";
import type { MemoryArtifact } from "openclaw/plugin-sdk";
import { getDreamState } from "./dream-gate.ts";
export interface PublicArtifactsContext {
provider: Mem0Provider;
cfg: Mem0Config;
stateDir?: string;
effectiveUserId: (sessionKey?: string) => string;
}
/**
* Create a publicArtifacts provider that exposes Mem0 data to other plugins.
*/
export function createPublicArtifactsProvider(ctx: PublicArtifactsContext) {
return {
async listArtifacts(options?: {
userId?: string;
types?: string[];
limit?: number;
}): Promise<MemoryArtifact[]> {
const artifacts: MemoryArtifact[] = [];
const userId = options?.userId ?? ctx.effectiveUserId();
const types = options?.types ?? ["memory", "dream", "entity"];
const limit = options?.limit ?? 100;
try {
// Memory artifacts
if (types.includes("memory")) {
const memories = await ctx.provider.getAll({
user_id: userId,
page_size: limit,
});
for (const mem of memories) {
artifacts.push(memoryToArtifact(mem));
}
}
// Dream state artifact (if dream enabled and stateDir available)
if (types.includes("dream") && ctx.stateDir && ctx.cfg.skills?.dream?.enabled) {
const dreamArtifact = getDreamArtifact(ctx.stateDir, userId);
if (dreamArtifact) {
artifacts.push(dreamArtifact);
}
}
// Entity artifacts (grouped memories by category)
if (types.includes("entity")) {
const entityArtifacts = extractEntityArtifacts(artifacts.filter(a => a.type === "memory"));
artifacts.push(...entityArtifacts);
}
} catch (err) {
console.warn(
"[mem0] publicArtifacts.listArtifacts failed:",
err instanceof Error ? err.message : err,
);
}
return artifacts.slice(0, limit);
},
};
}
/**
* Convert a MemoryItem to a MemoryArtifact.
*/
function memoryToArtifact(mem: MemoryItem): MemoryArtifact {
return {
id: `mem0:memory:${mem.id}`,
type: "memory",
title: mem.memory.slice(0, 80) + (mem.memory.length > 80 ? "..." : ""),
content: mem.memory,
metadata: {
score: mem.score,
categories: mem.categories,
user_id: mem.user_id,
...mem.metadata,
},
createdAt: mem.created_at,
updatedAt: mem.updated_at,
};
}
/**
* Get dream consolidation state as an artifact.
*/
function getDreamArtifact(stateDir: string, userId: string): MemoryArtifact | null {
try {
const state = getDreamState(stateDir);
if (state.lastConsolidatedAt === 0) {
return null; // No consolidation has occurred yet
}
const lastDate = new Date(state.lastConsolidatedAt).toISOString();
return {
id: `mem0:dream:${userId}:state`,
type: "dream",
title: `Dream State (last: ${lastDate.split("T")[0]})`,
content: [
`Last consolidation: ${lastDate}`,
`Sessions since: ${state.sessionsSince}`,
`Last session: ${state.lastSessionId ?? "none"}`,
].join("\n"),
metadata: {
lastConsolidatedAt: state.lastConsolidatedAt,
sessionsSince: state.sessionsSince,
lastSessionId: state.lastSessionId,
user_id: userId,
},
updatedAt: lastDate,
};
} catch {
return null;
}
}
/**
* Extract entity artifacts from memories (grouped by category).
*/
function extractEntityArtifacts(memoryArtifacts: MemoryArtifact[]): MemoryArtifact[] {
const byCategory = new Map<string, MemoryArtifact[]>();
for (const artifact of memoryArtifacts) {
const categories = (artifact.metadata?.categories as string[]) ?? ["uncategorized"];
for (const cat of categories) {
const existing = byCategory.get(cat) ?? [];
existing.push(artifact);
byCategory.set(cat, existing);
}
}
const entities: MemoryArtifact[] = [];
for (const [category, mems] of byCategory) {
if (mems.length >= 2) {
entities.push({
id: `mem0:entity:${category}`,
type: "entity",
title: `${category.charAt(0).toUpperCase() + category.slice(1)} (${mems.length} memories)`,
content: mems.map(m => `- ${m.content}`).join("\n"),
metadata: {
category,
memoryCount: mems.length,
memoryIds: mems.map(m => m.id),
},
});
}
}
return entities;
}