@openviking/openclaw-plugin 2026.7.11 → 2026.7.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/auto-recall.ts +5 -4
  2. package/context-engine.ts +0 -1
  3. package/dist/auto-recall.js +4 -4
  4. package/dist/context-engine.js +0 -1
  5. package/dist/index.js +4 -4
  6. package/dist/plugin/openviking-archive-tools.js +1 -2
  7. package/dist/plugin/openviking-command-definitions.js +3 -3
  8. package/dist/plugin/openviking-import-tools.js +2 -2
  9. package/dist/plugin/openviking-memory-recall-tools.js +4 -4
  10. package/dist/plugin/openviking-memory-tools.js +11 -6
  11. package/dist/plugin/openviking-query-runtime.js +1 -1
  12. package/dist/plugin/openviking-query-tools.js +4 -4
  13. package/dist/plugin/openviking-recall-trace-runtime.js +3 -3
  14. package/dist/plugin/openviking-session-routing-runtime.js +9 -2
  15. package/dist/plugin/openviking-tool-result-tools.js +3 -3
  16. package/dist/routing/identity-routing.js +27 -0
  17. package/dist/routing/memory-uri.js +1 -0
  18. package/dist/services/context-lifecycle-service.js +21 -16
  19. package/dist/services/context-message-adapter.js +2 -9
  20. package/index.ts +3 -3
  21. package/package.json +1 -1
  22. package/plugin/command-registration.ts +2 -0
  23. package/plugin/openviking-archive-tools.ts +1 -4
  24. package/plugin/openviking-command-definitions.ts +4 -3
  25. package/plugin/openviking-import-tools.ts +4 -2
  26. package/plugin/openviking-memory-recall-tools.ts +6 -4
  27. package/plugin/openviking-memory-tools.ts +18 -10
  28. package/plugin/openviking-query-runtime.ts +1 -1
  29. package/plugin/openviking-query-tools.ts +6 -4
  30. package/plugin/openviking-recall-trace-runtime.ts +4 -3
  31. package/plugin/openviking-recall-trace-tools.ts +2 -0
  32. package/plugin/openviking-session-routing-runtime.ts +15 -1
  33. package/plugin/openviking-tool-result-tools.ts +0 -6
  34. package/routing/identity-routing.ts +41 -0
  35. package/routing/memory-uri.ts +1 -0
  36. package/services/context-lifecycle-service.ts +27 -18
  37. package/services/context-message-adapter.ts +2 -9
@@ -26,7 +26,7 @@ export type OpenVikingArchiveClient = {
26
26
  grepSessionArchives: (
27
27
  sessionId: string,
28
28
  pattern: string,
29
- options: { archiveId?: string; caseInsensitive: boolean; agentId?: string },
29
+ options: { archiveId?: string; caseInsensitive: boolean },
30
30
  ) => Promise<{
31
31
  count?: number;
32
32
  matches?: OpenVikingArchiveMatch[];
@@ -34,7 +34,6 @@ export type OpenVikingArchiveClient = {
34
34
  getSessionArchive: (
35
35
  sessionId: string,
36
36
  archiveId: string,
37
- agentId?: string,
38
37
  ) => Promise<{
39
38
  archive_id: string;
40
39
  abstract?: string;
@@ -128,7 +127,6 @@ export function registerOpenVikingArchiveTools(deps: OpenVikingArchiveToolsDeps)
128
127
  const result = await client.grepSessionArchives(ovSessionId, escapedQuery, {
129
128
  archiveId,
130
129
  caseInsensitive: true,
131
- agentId,
132
130
  });
133
131
  const traceResults: RecallTraceResult[] = (result.matches ?? []).slice(0, deps.traceRecallMaxResultsPerSearch).map((match) => ({
134
132
  uri: match.uri,
@@ -263,7 +261,6 @@ export function registerOpenVikingArchiveTools(deps: OpenVikingArchiveToolsDeps)
263
261
  const detail = await client.getSessionArchive(
264
262
  session.ovSessionId,
265
263
  archiveId,
266
- session.agentId,
267
264
  );
268
265
 
269
266
  const header = [
@@ -6,6 +6,7 @@ export type OpenVikingCommandSession = {
6
6
  sessionKey?: string;
7
7
  ovSessionId?: string;
8
8
  agentId: string;
9
+ actorPeerId?: string;
9
10
  };
10
11
 
11
12
  export type OpenVikingCommandToolResult = {
@@ -217,7 +218,7 @@ export function createOpenVikingCommandDefinitions(
217
218
  }
218
219
  const session = deps.resolvePluginSessionRouting(ctx);
219
220
  const input = deps.parseAddResourceCommandArgs(ctx.args ?? "");
220
- return toCommandResult(await deps.addResourceOpenViking(input, session.agentId));
221
+ return toCommandResult(await deps.addResourceOpenViking(input, session.actorPeerId));
221
222
  } catch (err) {
222
223
  return { text: `OpenViking add resource failed: ${err instanceof Error ? err.message : String(err)}` };
223
224
  }
@@ -234,7 +235,7 @@ export function createOpenVikingCommandDefinitions(
234
235
  }
235
236
  const session = deps.resolvePluginSessionRouting(ctx);
236
237
  const input = deps.parseAddSkillCommandArgs(ctx.args ?? "");
237
- return toCommandResult(await deps.addSkillOpenViking(input, session.agentId));
238
+ return toCommandResult(await deps.addSkillOpenViking(input, session.actorPeerId));
238
239
  } catch (err) {
239
240
  return { text: `OpenViking add skill failed: ${err instanceof Error ? err.message : String(err)}` };
240
241
  }
@@ -251,7 +252,7 @@ export function createOpenVikingCommandDefinitions(
251
252
  }
252
253
  const session = deps.resolvePluginSessionRouting(ctx);
253
254
  const input = deps.parseOVSearchCommandArgs(ctx.args ?? "");
254
- return toCommandResult(await deps.searchOpenViking(input, session.agentId, session));
255
+ return toCommandResult(await deps.searchOpenViking(input, session.actorPeerId, session));
255
256
  } catch (err) {
256
257
  return { text: `OpenViking search failed: ${err instanceof Error ? err.message : String(err)}` };
257
258
  }
@@ -12,6 +12,7 @@ export type OpenVikingImportToolContext = {
12
12
  sessionId?: string;
13
13
  agentId?: string;
14
14
  senderId?: string;
15
+ requesterSenderId?: string;
15
16
  };
16
17
 
17
18
  export type OpenVikingImportSession = {
@@ -19,6 +20,7 @@ export type OpenVikingImportSession = {
19
20
  sessionKey?: string;
20
21
  ovSessionId?: string;
21
22
  agentId: string;
23
+ actorPeerId?: string;
22
24
  };
23
25
 
24
26
  export type OpenVikingImportClient = {
@@ -80,7 +82,7 @@ export function registerOpenVikingImportTools(deps: OpenVikingImportToolsDeps):
80
82
  instruction: typeof params.instruction === "string" ? params.instruction : undefined,
81
83
  wait: typeof params.wait === "boolean" ? params.wait : undefined,
82
84
  timeout: typeof params.timeout === "number" ? params.timeout : undefined,
83
- }, session.agentId);
85
+ }, session.actorPeerId);
84
86
  return {
85
87
  content: [{ type: "text" as const, text: formatResourceImportText(result) }],
86
88
  details: {
@@ -118,7 +120,7 @@ export function registerOpenVikingImportTools(deps: OpenVikingImportToolsDeps):
118
120
  data: params.data,
119
121
  wait: typeof params.wait === "boolean" ? params.wait : undefined,
120
122
  timeout: typeof params.timeout === "number" ? params.timeout : undefined,
121
- }, session.agentId);
123
+ }, session.actorPeerId);
122
124
  return {
123
125
  content: [{ type: "text" as const, text: formatSkillImportText(result) }],
124
126
  details: {
@@ -15,6 +15,7 @@ export type OpenVikingMemoryRecallToolContext = {
15
15
  sessionId?: string;
16
16
  agentId?: string;
17
17
  senderId?: string;
18
+ requesterSenderId?: string;
18
19
  };
19
20
 
20
21
  export type OpenVikingMemoryRecallSession = {
@@ -22,6 +23,7 @@ export type OpenVikingMemoryRecallSession = {
22
23
  sessionKey?: string;
23
24
  ovSessionId?: string;
24
25
  agentId: string;
26
+ actorPeerId?: string;
25
27
  };
26
28
 
27
29
  export type OpenVikingMemoryRecallClient = {
@@ -163,7 +165,7 @@ export function registerOpenVikingMemoryRecallTools(
163
165
  const recallClient = await deps.getClient();
164
166
  if (deps.cfg.logFindRequests) {
165
167
  deps.logger.info?.(
166
- `openviking: memory_recall X-OpenViking-Actor-Peer="${session.agentId}" ` +
168
+ `openviking: memory_recall X-OpenViking-Actor-Peer="${session.actorPeerId ?? "none"}" ` +
167
169
  `(plugin defaultAgentId="${recallClient.getDefaultAgentId()}" is unused when session context is present)`,
168
170
  );
169
171
  }
@@ -177,7 +179,7 @@ export function registerOpenVikingMemoryRecallTools(
177
179
  targetUri,
178
180
  limit: requestLimit,
179
181
  scoreThreshold: 0,
180
- actorPeerId: session.agentId,
182
+ actorPeerId: session.actorPeerId,
181
183
  },
182
184
  );
183
185
  const traceResults = [
@@ -207,7 +209,7 @@ export function registerOpenVikingMemoryRecallTools(
207
209
  limit: requestLimit,
208
210
  scoreThreshold: 0,
209
211
  contextType: search.contextType,
210
- actorPeerId: session.agentId,
212
+ actorPeerId: session.actorPeerId,
211
213
  },
212
214
  ),
213
215
  ));
@@ -319,7 +321,7 @@ export function registerOpenVikingMemoryRecallTools(
319
321
  }
320
322
  const { lines: memoryLines } = await deps.buildMemoryLinesWithBudget(
321
323
  memories,
322
- (uri) => recallClient.read(uri, session.agentId),
324
+ (uri) => recallClient.read(uri, session.actorPeerId),
323
325
  {
324
326
  recallPreferAbstract: false,
325
327
  recallMaxInjectedChars: queryConfig.maxInjectedChars,
@@ -2,6 +2,10 @@ import { Type } from "@sinclair/typebox";
2
2
 
3
3
  import type { CommitSessionResult, FindResultItem } from "../client.js";
4
4
  import { clampScore, postProcessMemories } from "../memory-ranking.js";
5
+ import {
6
+ resolveOpenVikingMessagePeerId,
7
+ type OpenVikingPeerRole,
8
+ } from "../routing/identity-routing.js";
5
9
  import { isMemoryUri } from "../routing/memory-uri.js";
6
10
 
7
11
  export type OpenVikingMemoryToolContext = {
@@ -17,6 +21,7 @@ export type OpenVikingMemorySession = {
17
21
  sessionKey?: string;
18
22
  ovSessionId?: string;
19
23
  agentId: string;
24
+ actorPeerId?: string;
20
25
  };
21
26
 
22
27
  export type OpenVikingMemoryClient = {
@@ -30,7 +35,7 @@ export type OpenVikingMemoryClient = {
30
35
  ) => Promise<void>;
31
36
  commitSession: (
32
37
  sessionId: string,
33
- options: { wait: true; agentId: string; keepRecentCount: number },
38
+ options: { wait: true; agentId?: string; keepRecentCount: number },
34
39
  ) => Promise<CommitSessionResult>;
35
40
  deleteUri: (uri: string, agentId?: string) => Promise<void>;
36
41
  find: (
@@ -45,8 +50,7 @@ export type OpenVikingMemoryToolsDeps = {
45
50
  getClient: () => Promise<OpenVikingMemoryClient>;
46
51
  normalizeSessionId: (sessionId: string) => string;
47
52
  createTempSessionId: () => string;
48
- extractSenderId: (ctx?: OpenVikingMemoryToolContext) => string | undefined;
49
- toRoleId: (senderId?: string) => string | undefined;
53
+ peerRole: OpenVikingPeerRole;
50
54
  resolvePluginSessionRouting: (ctx?: OpenVikingMemoryToolContext) => OpenVikingMemorySession;
51
55
  isBypassedSession: (ctx?: OpenVikingMemoryToolContext) => boolean;
52
56
  makeBypassedToolResult: (toolName: string) => unknown;
@@ -107,18 +111,22 @@ export function registerOpenVikingMemoryTools(deps: OpenVikingMemoryToolsDeps):
107
111
  sessionId = deps.createTempSessionId();
108
112
  usedTempSession = true;
109
113
  }
110
- const roleId = role === "user" ? deps.toRoleId(deps.extractSenderId(ctx)) : undefined;
114
+ const peerId = resolveOpenVikingMessagePeerId({
115
+ peerRole: deps.peerRole,
116
+ role,
117
+ personPeerId: session.actorPeerId,
118
+ assistantPeerId: session.actorPeerId,
119
+ });
111
120
  await client.addSessionMessage(
112
121
  sessionId,
113
122
  role,
114
123
  [{ type: "text", text }],
115
- session.agentId,
116
124
  undefined,
117
- roleId,
125
+ undefined,
126
+ peerId,
118
127
  );
119
128
  const commitResult = await client.commitSession(sessionId, {
120
129
  wait: true,
121
- agentId: session.agentId,
122
130
  keepRecentCount: 0,
123
131
  });
124
132
  const memoriesCount = totalCommitMemories(commitResult);
@@ -216,7 +224,7 @@ export function registerOpenVikingMemoryTools(deps: OpenVikingMemoryToolsDeps):
216
224
  details: { action: "rejected", uri },
217
225
  };
218
226
  }
219
- await client.deleteUri(uri, session.agentId);
227
+ await client.deleteUri(uri, session.actorPeerId);
220
228
  return {
221
229
  content: [{ type: "text", text: `Forgotten: ${uri}` }],
222
230
  details: { action: "deleted", uri },
@@ -252,7 +260,7 @@ export function registerOpenVikingMemoryTools(deps: OpenVikingMemoryToolsDeps):
252
260
  limit: requestLimit,
253
261
  scoreThreshold: 0,
254
262
  },
255
- session.agentId,
263
+ session.actorPeerId,
256
264
  );
257
265
  const candidates = postProcessMemories(result.memories ?? [], {
258
266
  limit: requestLimit,
@@ -272,7 +280,7 @@ export function registerOpenVikingMemoryTools(deps: OpenVikingMemoryToolsDeps):
272
280
  }
273
281
  const top = candidates[0];
274
282
  if (candidates.length === 1 && clampScore(top.score) >= 0.85) {
275
- await client.deleteUri(top.uri, session.agentId);
283
+ await client.deleteUri(top.uri, session.actorPeerId);
276
284
  return {
277
285
  content: [{ type: "text", text: `Forgotten: ${top.uri}` }],
278
286
  details: { action: "deleted", uri: top.uri, score: top.score ?? 0 },
@@ -445,7 +445,7 @@ export function createOpenVikingQueryRuntime<TQueryConfigContext>(deps: OpenViki
445
445
  sessionId: traceCtx?.sessionId,
446
446
  sessionKey: traceCtx?.sessionKey,
447
447
  ovSessionId: traceCtx?.ovSessionId,
448
- agentId,
448
+ agentId: traceCtx?.agentId,
449
449
  source: "ov_search",
450
450
  operationType: "semantic_find",
451
451
  resourceTypes: [...new Set(searches.map((search) => search.resourceType).filter((resourceType): resourceType is RecallResourceType => resourceType !== "archive"))],
@@ -5,6 +5,7 @@ export type OpenVikingQueryToolContext = {
5
5
  sessionId?: string;
6
6
  agentId?: string;
7
7
  senderId?: string;
8
+ requesterSenderId?: string;
8
9
  };
9
10
 
10
11
  export type OpenVikingQuerySession = {
@@ -12,6 +13,7 @@ export type OpenVikingQuerySession = {
12
13
  sessionKey?: string;
13
14
  ovSessionId?: string;
14
15
  agentId: string;
16
+ actorPeerId?: string;
15
17
  };
16
18
 
17
19
  export type OVSearchInput = {
@@ -74,7 +76,7 @@ export function registerOpenVikingQueryTools(deps: OpenVikingQueryToolsDeps): vo
74
76
  query: String((params as { query?: unknown }).query ?? ""),
75
77
  uri: typeof params.uri === "string" ? params.uri : undefined,
76
78
  limit: typeof params.limit === "number" ? params.limit : undefined,
77
- }, session.agentId, session);
79
+ }, session.actorPeerId, session);
78
80
  },
79
81
  }),
80
82
  { name: "ov_search" },
@@ -99,7 +101,7 @@ export function registerOpenVikingQueryTools(deps: OpenVikingQueryToolsDeps): vo
99
101
  const session = deps.resolvePluginSessionRouting(ctx);
100
102
  return deps.readOpenVikingContent({
101
103
  uri: String((params as { uri?: unknown }).uri ?? ""),
102
- }, session.agentId);
104
+ }, session.actorPeerId);
103
105
  },
104
106
  }),
105
107
  { name: "ov_read" },
@@ -125,7 +127,7 @@ export function registerOpenVikingQueryTools(deps: OpenVikingQueryToolsDeps): vo
125
127
  const uris = Array.isArray((params as { uris?: unknown }).uris)
126
128
  ? (params as { uris: unknown[] }).uris.map((uri) => String(uri))
127
129
  : [];
128
- return deps.multiReadOpenVikingContent({ uris }, session.agentId);
130
+ return deps.multiReadOpenVikingContent({ uris }, session.actorPeerId);
129
131
  },
130
132
  }),
131
133
  { name: "ov_multi_read" },
@@ -153,7 +155,7 @@ export function registerOpenVikingQueryTools(deps: OpenVikingQueryToolsDeps): vo
153
155
  recursive: typeof params.recursive === "boolean" ? params.recursive : undefined,
154
156
  simple: typeof params.simple === "boolean" ? params.simple : undefined,
155
157
  limit: typeof params.limit === "number" ? params.limit : undefined,
156
- }, session.agentId);
158
+ }, session.actorPeerId);
157
159
  },
158
160
  }),
159
161
  { name: "ov_list" },
@@ -26,6 +26,7 @@ export type OpenVikingRecallTraceSession = {
26
26
  sessionKey?: string;
27
27
  ovSessionId?: string;
28
28
  agentId: string;
29
+ actorPeerId?: string;
29
30
  };
30
31
 
31
32
  export type OpenVikingRecallTraceQueryResult = {
@@ -248,11 +249,11 @@ export function createOpenVikingRecallTraceRuntime(deps: OpenVikingRecallTraceRu
248
249
  for (const fallbackQuery of fallbackIdentities) {
249
250
  const fallback = await deps.traceRecorder.queryWithFallback(fallbackQuery);
250
251
  if (fallback.entries.length > 0) {
251
- return enrichTraceEntriesWithContent(fallback, shouldIncludeTraceContent(input), session.agentId);
252
+ return enrichTraceEntriesWithContent(fallback, shouldIncludeTraceContent(input), session.actorPeerId);
252
253
  }
253
254
  }
254
255
  }
255
- return enrichTraceEntriesWithContent(base, shouldIncludeTraceContent(input), session.agentId);
256
+ return enrichTraceEntriesWithContent(base, shouldIncludeTraceContent(input), session.actorPeerId);
256
257
  };
257
258
 
258
259
  const handleUriDetail = async (request?: RecallTraceRouteRequest) => {
@@ -298,7 +299,7 @@ export function createOpenVikingRecallTraceRuntime(deps: OpenVikingRecallTraceRu
298
299
  }
299
300
  try {
300
301
  const client = await deps.getClient();
301
- const content = await client.read(uri, toString(query.agentId) ?? session.agentId);
302
+ const content = await client.read(uri, session.actorPeerId);
302
303
  const text = typeof content === "string" ? content : JSON.stringify(content, null, 2);
303
304
  const chars = Array.from(text);
304
305
  const slice = chars.slice(offset, offset + contentLimit).join("");
@@ -11,6 +11,7 @@ export type OpenVikingRecallTraceToolContext = {
11
11
  sessionId?: string;
12
12
  agentId?: string;
13
13
  senderId?: string;
14
+ requesterSenderId?: string;
14
15
  };
15
16
 
16
17
  export type OpenVikingRecallTraceSession = {
@@ -18,6 +19,7 @@ export type OpenVikingRecallTraceSession = {
18
19
  sessionKey?: string;
19
20
  ovSessionId?: string;
20
21
  agentId: string;
22
+ actorPeerId?: string;
21
23
  };
22
24
 
23
25
  export type RecallTraceToolInput = {
@@ -2,6 +2,9 @@ import type { QueryConfigContext } from "../query-config.js";
2
2
  import {
3
3
  createSessionAgentResolver,
4
4
  openClawSessionToOvStorageId,
5
+ resolveOpenVikingActorPeerId,
6
+ sanitizeOpenVikingPeerId,
7
+ type OpenVikingPeerRole,
5
8
  } from "../routing/identity-routing.js";
6
9
 
7
10
  type Logger = {
@@ -10,6 +13,8 @@ type Logger = {
10
13
 
11
14
  export type SessionAgentLookup = {
12
15
  agentId?: string;
16
+ senderId?: string;
17
+ requesterSenderId?: string;
13
18
  sessionId?: string;
14
19
  sessionKey?: string;
15
20
  ovSessionId?: string;
@@ -20,13 +25,16 @@ export type PluginSessionRouting = {
20
25
  sessionKey?: string;
21
26
  ovSessionId?: string;
22
27
  agentId: string;
28
+ actorPeerId?: string;
23
29
  };
24
30
 
25
31
  export function createOpenVikingSessionRoutingRuntime(options: {
32
+ peerRole?: OpenVikingPeerRole;
26
33
  peerPrefix: string;
27
34
  logFindRequests: boolean;
28
35
  logger: Logger;
29
36
  }) {
37
+ const peerRole = options.peerRole ?? "assistant";
30
38
  const sessionAgentResolver = createSessionAgentResolver(options.peerPrefix);
31
39
 
32
40
  const rememberSessionAgentId = (ctx: SessionAgentLookup) => {
@@ -81,11 +89,17 @@ export function createOpenVikingSessionRoutingRuntime(options: {
81
89
  };
82
90
  rememberSessionAgentId(session);
83
91
 
92
+ const agentId = resolveAgentId(session.sessionId, session.sessionKey, session.ovSessionId);
84
93
  return {
85
94
  sessionId: session.sessionId,
86
95
  sessionKey: session.sessionKey,
87
96
  ovSessionId: session.ovSessionId,
88
- agentId: resolveAgentId(session.sessionId, session.sessionKey, session.ovSessionId),
97
+ agentId,
98
+ actorPeerId: resolveOpenVikingActorPeerId({
99
+ peerRole,
100
+ personPeerId: sanitizeOpenVikingPeerId(ctx?.requesterSenderId ?? ctx?.senderId),
101
+ assistantPeerId: agentId,
102
+ }),
89
103
  };
90
104
  };
91
105
 
@@ -27,7 +27,6 @@ export type OpenVikingToolResultClient = {
27
27
  sessionId: string,
28
28
  toolResultId: string,
29
29
  options: { offset: number; limit: number; includeMetadata: boolean },
30
- agentId?: string,
31
30
  ) => Promise<{
32
31
  content: string;
33
32
  offset: number;
@@ -42,7 +41,6 @@ export type OpenVikingToolResultClient = {
42
41
  toolResultId: string,
43
42
  query: string,
44
43
  options: { limit: number; contextChars: number },
45
- agentId?: string,
46
44
  ) => Promise<{
47
45
  tool_result_id: string;
48
46
  matches?: Array<{ offset: number; snippet: string }>;
@@ -50,7 +48,6 @@ export type OpenVikingToolResultClient = {
50
48
  listToolResults: (
51
49
  sessionId: string,
52
50
  options: { toolName?: string; limit: number },
53
- agentId?: string,
54
51
  ) => Promise<{
55
52
  tool_results?: Array<{
56
53
  storage_uri?: string;
@@ -180,7 +177,6 @@ export function registerOpenVikingToolResultTools({
180
177
  session.ovSessionId,
181
178
  parsed.toolResultId,
182
179
  { offset, limit, includeMetadata: true },
183
- session.agentId,
184
180
  );
185
181
  const returnedChars = result.content.length;
186
182
  const nextOffset = result.offset + returnedChars;
@@ -281,7 +277,6 @@ export function registerOpenVikingToolResultTools({
281
277
  parsed.toolResultId,
282
278
  query,
283
279
  { limit, contextChars },
284
- session.agentId,
285
280
  );
286
281
  const matches = result.matches ?? [];
287
282
  const text = matches.length
@@ -354,7 +349,6 @@ export function registerOpenVikingToolResultTools({
354
349
  const result = await client.listToolResults(
355
350
  session.ovSessionId,
356
351
  { toolName, limit },
357
- session.agentId,
358
352
  );
359
353
  const items = result.tool_results ?? [];
360
354
  const text = items.length
@@ -15,6 +15,47 @@ export type SessionAgentLookup = {
15
15
  ovSessionId?: string;
16
16
  };
17
17
 
18
+ export type OpenVikingPeerRole = "none" | "assistant" | "person";
19
+
20
+ export function sanitizeOpenVikingPeerId(raw?: string): string | undefined {
21
+ const normalized = raw
22
+ ?.trim()
23
+ .replace(/[^a-zA-Z0-9_-]+/g, "_")
24
+ .replace(/^_+|_+$/g, "")
25
+ .replace(/_+/g, "_");
26
+ return normalized || undefined;
27
+ }
28
+
29
+ export function resolveOpenVikingMessagePeerId(params: {
30
+ peerRole: OpenVikingPeerRole;
31
+ role?: string;
32
+ personPeerId?: string;
33
+ assistantPeerId?: string;
34
+ }): string | undefined {
35
+ if (params.peerRole === "person" && params.role === "user") {
36
+ return params.personPeerId;
37
+ }
38
+ if (params.peerRole === "assistant" && params.role === "assistant") {
39
+ return params.assistantPeerId;
40
+ }
41
+ return undefined;
42
+ }
43
+
44
+ export function resolveOpenVikingActorPeerId(params: {
45
+ peerRole: OpenVikingPeerRole;
46
+ personPeerId?: string;
47
+ assistantPeerId?: string;
48
+ }): string | undefined {
49
+ const actorPeerId = resolveOpenVikingMessagePeerId({
50
+ ...params,
51
+ role: params.peerRole === "person" ? "user" : "assistant",
52
+ });
53
+ if (params.peerRole === "person" && !actorPeerId) {
54
+ throw new Error("openviking: peer_role=person requires a sender identity");
55
+ }
56
+ return actorPeerId;
57
+ }
58
+
18
59
  export type SessionAgentResolveBranch =
19
60
  | "session_resolved"
20
61
  | "config_only_fallback"
@@ -1,5 +1,6 @@
1
1
  const MEMORY_URI_PATTERNS = [
2
2
  /^viking:\/\/user\/(?:[^/]+(?:\/agent\/[^/]+)?\/)?memories(?:\/|$)/,
3
+ /^viking:\/\/user\/[^/]+\/peers\/[^/]+\/memories(?:\/|$)/,
3
4
  /^viking:\/\/agent\/(?:[^/]+(?:\/user\/[^/]+)?\/)?memories(?:\/|$)/,
4
5
  ];
5
6
 
@@ -3,7 +3,13 @@ import { DEFAULT_PHASE2_POLL_TIMEOUT_MS, type OpenVikingClient, type OVMessage }
3
3
  import type { EffectiveQueryConfig } from "../query-config.js";
4
4
  import { buildAutoRecallContext, prepareRecallQuery } from "../auto-recall.js";
5
5
  import { toJsonLog } from "../memory-ranking.js";
6
- import { openClawSessionToOvStorageId } from "../routing/identity-routing.js";
6
+ import {
7
+ openClawSessionToOvStorageId,
8
+ resolveOpenVikingActorPeerId,
9
+ resolveOpenVikingMessagePeerId,
10
+ sanitizeOpenVikingPeerId,
11
+ type OpenVikingPeerRole,
12
+ } from "../routing/identity-routing.js";
7
13
  import { extractNewTurnMessages } from "../text-utils.js";
8
14
  import { estimateAgentMessageTokens, estimateTextTokens } from "../token-estimator.js";
9
15
  import {
@@ -26,7 +32,6 @@ export type CommitOpenVikingSessionParams = {
26
32
  sessionKey?: string;
27
33
  getClient: () => Promise<Pick<OpenVikingClient, "commitSession">>;
28
34
  logger: ContextEngineLifecycleLogger;
29
- resolveAgentId: (sessionId: string, sessionKey?: string, ovSessionId?: string) => string;
30
35
  rememberSessionAgentId?: (ctx: {
31
36
  agentId?: string;
32
37
  sessionId?: string;
@@ -131,6 +136,7 @@ export type AfterTurnOpenVikingSessionParams = {
131
136
  commitTokenThresholdRatio: number;
132
137
  commitKeepRecentCount: number;
133
138
  logFindRequests: boolean;
139
+ peer_role?: OpenVikingPeerRole;
134
140
  };
135
141
  getClient: () => Promise<AfterTurnClient>;
136
142
  logger: ContextEngineLifecycleLogger;
@@ -177,7 +183,6 @@ function sleep(ms: number): Promise<void> {
177
183
  async function pollPhase2ExtractionOutcome(
178
184
  client: AfterTurnClient,
179
185
  taskId: string,
180
- agentId: string,
181
186
  logger: ContextEngineLifecycleLogger,
182
187
  sessionLabel: string,
183
188
  ): Promise<void> {
@@ -185,7 +190,7 @@ async function pollPhase2ExtractionOutcome(
185
190
  try {
186
191
  while (Date.now() < deadline) {
187
192
  await sleep(PHASE2_POLL_INTERVAL_MS);
188
- const task = await client.getTask(taskId, agentId).catch((e) => {
193
+ const task = await client.getTask(taskId).catch((e) => {
189
194
  logger.warn?.(`openviking: phase2 getTask failed task_id=${taskId}: ${String(e)}`);
190
195
  return null;
191
196
  });
@@ -340,7 +345,6 @@ export async function commitOpenVikingSession({
340
345
  sessionKey,
341
346
  getClient,
342
347
  logger,
343
- resolveAgentId,
344
348
  rememberSessionAgentId,
345
349
  isBypassedSession,
346
350
  }: CommitOpenVikingSessionParams): Promise<boolean> {
@@ -358,10 +362,8 @@ export async function commitOpenVikingSession({
358
362
  sessionKey,
359
363
  ovSessionId: ovId,
360
364
  });
361
- const agentId = resolveAgentId(sessionId, sessionKey, ovId);
362
365
  const commitResult = await client.commitSession(ovId, {
363
366
  wait: true,
364
- agentId,
365
367
  keepRecentCount: 0,
366
368
  });
367
369
  const memCount = totalExtractedMemories(commitResult.memories_extracted);
@@ -492,6 +494,11 @@ export async function assembleOpenVikingSession({
492
494
  const client = await getClient();
493
495
  const routingRef = sessionId ?? sessionKey ?? ovSessionId;
494
496
  const agentId = resolveAgentId(routingRef, sessionKey, ovSessionId);
497
+ const actorPeerId = resolveOpenVikingActorPeerId({
498
+ peerRole: cfg.peer_role ?? "assistant",
499
+ personPeerId: sanitizeOpenVikingPeerId(sender.senderId),
500
+ assistantPeerId: agentId,
501
+ });
495
502
  const queryConfig = await queryConfigStore?.getEffective({
496
503
  agentId,
497
504
  sessionId,
@@ -503,6 +510,7 @@ export async function assembleOpenVikingSession({
503
510
  queryConfig,
504
511
  client,
505
512
  agentId,
513
+ actorPeerId,
506
514
  queryText: recallQuery.query,
507
515
  logger,
508
516
  verbose: (message) => logger.info(message),
@@ -553,9 +561,7 @@ export async function assembleOpenVikingSession({
553
561
 
554
562
  try {
555
563
  const client = await getClient();
556
- const routingRef = sessionId ?? sessionKey ?? ovSessionId;
557
- const agentId = resolveAgentId(routingRef, sessionKey, ovSessionId);
558
- const ctx = await client.getSessionContext(ovSessionId, tokenBudget, agentId);
564
+ const ctx = await client.getSessionContext(ovSessionId, tokenBudget);
559
565
 
560
566
  const preAbstracts = ctx?.pre_archive_abstracts ?? [];
561
567
  const hasArchives = !!ctx?.latest_archive_overview || preAbstracts.length > 0;
@@ -899,14 +905,19 @@ export async function afterTurnOpenVikingSession({
899
905
  ovSessionId,
900
906
  msg.role,
901
907
  ovParts,
902
- agentId,
908
+ undefined,
903
909
  createdAt,
904
- msg.role === "user" ? senderRoleId : undefined,
910
+ resolveOpenVikingMessagePeerId({
911
+ peerRole: cfg.peer_role ?? "assistant",
912
+ role: msg.role,
913
+ personPeerId: senderRoleId,
914
+ assistantPeerId: agentId,
915
+ }),
905
916
  );
906
917
  }
907
918
  }
908
919
 
909
- const session = await client.getSession(ovSessionId, agentId);
920
+ const session = await client.getSession(ovSessionId);
910
921
  const pendingTokens = session.pending_tokens ?? 0;
911
922
 
912
923
  const commitTokenThreshold = Math.floor(tokenBudget * cfg.commitTokenThresholdRatio);
@@ -926,7 +937,6 @@ export async function afterTurnOpenVikingSession({
926
937
 
927
938
  const commitResult = await client.commitSession(ovSessionId, {
928
939
  wait: false,
929
- agentId,
930
940
  keepRecentCount: cfg.commitKeepRecentCount,
931
941
  });
932
942
  logger.info(
@@ -952,7 +962,7 @@ export async function afterTurnOpenVikingSession({
952
962
  `openviking: Phase2 memory extraction runs asynchronously on the server (task_id=${commitResult.task_id}). ` +
953
963
  "memories_extracted appears only after that task completes — not in this immediate response.",
954
964
  );
955
- void pollPhase2ExtractionOutcome(client, commitResult.task_id, agentId, logger, ovSessionId);
965
+ void pollPhase2ExtractionOutcome(client, commitResult.task_id, logger, ovSessionId);
956
966
  }
957
967
  } catch (err) {
958
968
  logger.warn?.(`openviking: afterTurn failed: ${String(err)}`);
@@ -1033,7 +1043,7 @@ export async function compactOpenVikingSession({
1033
1043
  let preCommitEstimatedTokens: number | undefined;
1034
1044
  if (typeof tokensBeforeOriginal !== "number") {
1035
1045
  try {
1036
- const preCtx = await client.getSessionContext(ovSessionId, tokenBudget, agentId);
1046
+ const preCtx = await client.getSessionContext(ovSessionId, tokenBudget);
1037
1047
  if (typeof preCtx.estimatedTokens === "number" && Number.isFinite(preCtx.estimatedTokens)) {
1038
1048
  preCommitEstimatedTokens = preCtx.estimatedTokens;
1039
1049
  }
@@ -1053,7 +1063,6 @@ export async function compactOpenVikingSession({
1053
1063
  );
1054
1064
  const commitResult = await client.commitSession(ovSessionId, {
1055
1065
  wait: true,
1056
- agentId,
1057
1066
  keepRecentCount: 0,
1058
1067
  });
1059
1068
  const memCount = totalExtractedMemories(commitResult.memories_extracted);
@@ -1129,7 +1138,7 @@ export async function compactOpenVikingSession({
1129
1138
  let contextFetchError: string | undefined;
1130
1139
 
1131
1140
  try {
1132
- const ctx = await client.getSessionContext(ovSessionId, tokenBudget, agentId);
1141
+ const ctx = await client.getSessionContext(ovSessionId, tokenBudget);
1133
1142
  logger.info(
1134
1143
  `openviking: compact getSessionContext raw result for ${ovSessionId}: ` +
1135
1144
  JSON.stringify(ctx, null, 2),