diff --git a/examples/openclaw-plugin/client.ts b/examples/openclaw-plugin/client.ts index 1ea0a1b1c..913ff076e 100644 --- a/examples/openclaw-plugin/client.ts +++ b/examples/openclaw-plugin/client.ts @@ -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 { @@ -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"); } diff --git a/examples/openclaw-plugin/config.ts b/examples/openclaw-plugin/config.ts index 6a02fca23..e49be95b0 100644 --- a/examples/openclaw-plugin/config.ts +++ b/examples/openclaw-plugin/config.ts @@ -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; @@ -115,6 +119,8 @@ export const memoryOpenVikingConfigSchema = { "baseUrl", "agentId", "apiKey", + "accountId", + "userId", "targetUri", "timeoutMs", "autoCapture", @@ -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, diff --git a/examples/openclaw-plugin/index.ts b/examples/openclaw-plugin/index.ts index 68076f77b..edcaf9c10 100644 --- a/examples/openclaw-plugin/index.ts +++ b/examples/openclaw-plugin/index.ts @@ -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 = { @@ -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; @@ -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 => clientPromise; @@ -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") { @@ -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: [] }; diff --git a/examples/openclaw-plugin/openclaw.plugin.json b/examples/openclaw-plugin/openclaw.plugin.json index e6d918d4b..52dd7580f 100644 --- a/examples/openclaw-plugin/openclaw.plugin.json +++ b/examples/openclaw-plugin/openclaw.plugin.json @@ -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": { @@ -188,7 +198,13 @@ }, "emitStandardDiagnostics": { "type": "boolean" + }, + "accountId": { + "type": "string" + }, + "userId": { + "type": "string" } } } -} +} \ No newline at end of file