Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 36 additions & 7 deletions examples/openclaw-plugin/context-engine.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { createHash } from "node:crypto";

import type { OpenVikingClient } from "./client.js";
import type { MemoryOpenVikingConfig } from "./config.js";
import {
Expand Down Expand Up @@ -73,7 +75,7 @@ type ContextEngine = {
};

export type ContextEngineWithSessionMapping = ContextEngine & {
/** Return the OV session ID for an OpenClaw sessionKey (identity: sessionKey IS the OV session ID). */
/** Return the OV session ID for an OpenClaw sessionKey using a stable cross-platform-safe mapping. */
getOVSessionForKey: (sessionKey: string) => string;
/** Ensure an OV session exists on the server for the given OpenClaw sessionKey (auto-created by getSession if absent). */
resolveOVSession: (sessionKey: string) => Promise<string>;
Expand Down Expand Up @@ -134,6 +136,30 @@ function warnOrInfo(logger: Logger, message: string): void {
logger.info(message);
}

function md5Short(input: string): string {
return createHash("md5").update(input).digest("hex").slice(0, 12);
}

const SAFE_SESSION_KEY_RE = /^[A-Za-z0-9_-]+$/;

export function mapSessionKeyToOVSessionId(sessionKey: string): string {
const normalized = sessionKey.trim();
if (!normalized) {
return "openclaw_session";
}
if (SAFE_SESSION_KEY_RE.test(normalized)) {
return normalized;
}

const readable = normalized
.replace(/[^A-Za-z0-9_-]+/g, "-")
.replace(/-+/g, "-")
.replace(/^-|-$/g, "")
.slice(0, 48);
const digest = md5Short(normalized);
return readable ? `openclaw_${readable}_${digest}` : `openclaw_session_${digest}`;
}

export function createMemoryOpenVikingContextEngine(params: {
id: string;
name: string;
Expand All @@ -157,11 +183,12 @@ export function createMemoryOpenVikingContextEngine(params: {
try {
const client = await getClient();
const agentId = resolveAgentId(sessionKey);
const commitResult = await client.commitSession(sessionKey, { wait: true, agentId });
const ovSessionId = mapSessionKeyToOVSessionId(sessionKey);
const commitResult = await client.commitSession(ovSessionId, { wait: true, agentId });
logger.info(
`openviking: committed OV session for sessionKey=${sessionKey}, archived=${commitResult.archived ?? false}, memories=${commitResult.memories_extracted ?? 0}, task_id=${commitResult.task_id ?? "none"}`,
`openviking: committed OV session for sessionKey=${sessionKey}, ovSessionId=${ovSessionId}, archived=${commitResult.archived ?? false}, memories=${commitResult.memories_extracted ?? 0}, task_id=${commitResult.task_id ?? "none"}`,
);
await client.deleteSession(sessionKey, agentId).catch(() => {});
await client.deleteSession(ovSessionId, agentId).catch(() => {});
} catch (err) {
warnOrInfo(logger, `openviking: commit failed for sessionKey=${sessionKey}: ${String(err)}`);
}
Expand All @@ -184,10 +211,10 @@ export function createMemoryOpenVikingContextEngine(params: {

// --- session-mapping extensions ---

getOVSessionForKey: (sessionKey: string) => sessionKey,
getOVSessionForKey: (sessionKey: string) => mapSessionKeyToOVSessionId(sessionKey),

async resolveOVSession(sessionKey: string): Promise<string> {
return sessionKey;
return mapSessionKeyToOVSessionId(sessionKey);
},

commitOVSession: doCommitOVSession,
Expand Down Expand Up @@ -252,7 +279,9 @@ export function createMemoryOpenVikingContextEngine(params: {
}

const client = await getClient();
const OVSessionId = sessionKey ?? afterTurnParams.sessionId;
const OVSessionId = sessionKey
? mapSessionKeyToOVSessionId(sessionKey)
: afterTurnParams.sessionId;
await client.addSessionMessage(OVSessionId, "user", decision.normalizedText, agentId);
const commitResult = await client.commitSession(OVSessionId, { wait: true, agentId });
logger.info(
Expand Down
4 changes: 2 additions & 2 deletions examples/openclaw-plugin/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ const contextEnginePlugin = {
text: Type.String({ description: "Information to store as memory source text" }),
role: Type.Optional(Type.String({ description: "Session role, default user" })),
sessionId: Type.Optional(Type.String({ description: "Existing OpenViking session ID" })),
sessionKey: Type.Optional(Type.String({ description: "OpenClaw sessionKey — uses the persistent 1:1 mapped OV session" })),
sessionKey: Type.Optional(Type.String({ description: "OpenClaw sessionKey — uses the persistent mapped OV session" })),
}),
async execute(_toolCallId: string, params: Record<string, unknown>) {
const { text } = params as { text: string };
Expand Down Expand Up @@ -641,7 +641,7 @@ const contextEnginePlugin = {
return contextEngineRef;
});
api.logger.info(
"openviking: registered context-engine (before_prompt_build=auto-recall, afterTurn=auto-capture, sessionKey=1:1 mapping)",
"openviking: registered context-engine (before_prompt_build=auto-recall, afterTurn=auto-capture, sessionKey=stable mapped session)",
);
} else {
api.logger.warn(
Expand Down
Loading