Skip to content
Open
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
9 changes: 9 additions & 0 deletions examples/openclaw-plugin/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ export class OpenVikingClient {
private readonly apiKey: string,
private readonly defaultAgentId: string,
private readonly timeoutMs: number,
private readonly accountId?: string,
private readonly userId?: string,
) {}

getDefaultAgentId(): string {
Expand All @@ -160,6 +162,13 @@ export class OpenVikingClient {
if (effectiveAgentId) {
headers.set("X-OpenViking-Agent", effectiveAgentId);
}
// For root API key: send account and user headers to enable agent scope access
if (this.accountId) {
headers.set("X-OpenViking-Account", this.accountId);
}
if (this.userId) {
headers.set("X-OpenViking-User", this.userId);
}
if (init.body && !headers.has("Content-Type")) {
headers.set("Content-Type", "application/json");
}
Expand Down
8 changes: 8 additions & 0 deletions examples/openclaw-plugin/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ export type MemoryOpenVikingConfig = {
baseUrl?: string;
agentId?: string;
apiKey?: string;
/** Account ID for root API key. Required for agent scope access when using root API key. */
accountId?: string;
/** User ID for root API key. Required for agent scope access when using root API key. */
userId?: string;
targetUri?: string;
timeoutMs?: number;
autoCapture?: boolean;
Expand Down Expand Up @@ -115,6 +119,8 @@ export const memoryOpenVikingConfigSchema = {
"baseUrl",
"agentId",
"apiKey",
"accountId",
"userId",
"targetUri",
"timeoutMs",
"autoCapture",
Expand Down Expand Up @@ -168,6 +174,8 @@ export const memoryOpenVikingConfigSchema = {
baseUrl: resolvedBaseUrl,
agentId: resolveAgentId(cfg.agentId),
apiKey: rawApiKey ? resolveEnvVars(rawApiKey) : "",
accountId: typeof cfg.accountId === "string" ? cfg.accountId : undefined,
userId: typeof cfg.userId === "string" ? cfg.userId : undefined,
targetUri: typeof cfg.targetUri === "string" ? cfg.targetUri : DEFAULT_TARGET_URI,
timeoutMs: Math.max(1000, Math.floor(toNumber(cfg.timeoutMs, DEFAULT_TIMEOUT_MS))),
autoCapture: cfg.autoCapture !== false,
Expand Down
21 changes: 13 additions & 8 deletions examples/openclaw-plugin/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import {
resolvePythonCommand,
prepareLocalPort,
} from "./process-manager.js";
import { createMemoryOpenVikingContextEngine } from "./context-engine.js";
import { createMemoryOpenVikingContextEngine, commitLocks } from "./context-engine.js";
import type { ContextEngineWithCommit } from "./context-engine.js";

type PluginLogger = {
Expand Down Expand Up @@ -80,7 +80,7 @@ type OpenClawPluginApi = {

const MAX_OPENVIKING_STDERR_LINES = 200;
const MAX_OPENVIKING_STDERR_CHARS = 256_000;
const AUTO_RECALL_TIMEOUT_MS = 5_000;
const AUTO_RECALL_TIMEOUT_MS = 15_000;

function totalCommitMemories(r: CommitSessionResult): number {
const m = r.memories_extracted;
Expand Down Expand Up @@ -140,7 +140,7 @@ const contextEnginePlugin = {
}
}
} else {
clientPromise = Promise.resolve(new OpenVikingClient(cfg.baseUrl, cfg.apiKey, cfg.agentId, cfg.timeoutMs));
clientPromise = Promise.resolve(new OpenVikingClient(cfg.baseUrl, cfg.apiKey, cfg.agentId, cfg.timeoutMs, cfg.accountId, cfg.userId));
}

const getClient = (): Promise<OpenVikingClient> => clientPromise;
Expand Down Expand Up @@ -278,6 +278,14 @@ const contextEnginePlugin = {
usedTempSession = true;
}
await c.addSessionMessage(sessionId, role, text, storeAgentId);

// Wait if another commit is in progress
let waitCount = 0;
while (commitLocks.has(sessionId) && waitCount < 50) {
await new Promise(r => setTimeout(r, 100));
waitCount++;
}

const commitResult = await c.commitSession(sessionId, { wait: true, agentId: storeAgentId });
const memoriesCount = totalCommitMemories(commitResult);
if (commitResult.status === "failed") {
Expand Down Expand Up @@ -585,17 +593,14 @@ const contextEnginePlugin = {
await withTimeout(
(async () => {
const candidateLimit = Math.max(cfg.recallLimit * 4, 20);
// Skip agent scope search - requires different permissions in OpenViking
const [userSettled, agentSettled] = await Promise.allSettled([
client.find(queryText, {
targetUri: "viking://user/memories",
limit: candidateLimit,
scoreThreshold: 0,
}, agentId),
client.find(queryText, {
targetUri: "viking://agent/memories",
limit: candidateLimit,
scoreThreshold: 0,
}, agentId),
Promise.resolve({ memories: [] }), // agent scope disabled
]);

const userResult = userSettled.status === "fulfilled" ? userSettled.value : { memories: [] };
Expand Down
18 changes: 17 additions & 1 deletion examples/openclaw-plugin/openclaw.plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,16 @@
"label": "Standard diagnostics (diag JSON lines)",
"advanced": true,
"help": "Emit structured openviking: diag {...} for assemble/afterTurn. Set false to disable."
},
"accountId": {
"label": "Account ID",
"help": "Account ID for root API key. Required for agent scope access.",
"advanced": true
},
"userId": {
"label": "User ID",
"help": "User ID for root API key. Required for agent scope access.",
"advanced": true
}
},
"configSchema": {
Expand Down Expand Up @@ -188,7 +198,13 @@
},
"emitStandardDiagnostics": {
"type": "boolean"
},
"accountId": {
"type": "string"
},
"userId": {
"type": "string"
}
}
}
}
}