@openviking/openclaw-plugin 2026.7.11 → 2026.8.6-1
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.
- package/INSTALL-ZH.md +39 -0
- package/INSTALL.md +39 -0
- package/README.md +5 -0
- package/auto-recall.ts +5 -4
- package/config.ts +121 -6
- package/context-engine.ts +0 -1
- package/dist/auto-recall.js +4 -4
- package/dist/config.js +78 -4
- package/dist/context-engine.js +0 -1
- package/dist/index.js +13 -4
- package/dist/plugin/openviking-archive-tools.js +1 -2
- package/dist/plugin/openviking-command-definitions.js +3 -3
- package/dist/plugin/openviking-experience-tools.js +105 -0
- package/dist/plugin/openviking-import-tools.js +2 -2
- package/dist/plugin/openviking-memory-recall-tools.js +4 -4
- package/dist/plugin/openviking-memory-tools.js +11 -6
- package/dist/plugin/openviking-query-runtime.js +1 -1
- package/dist/plugin/openviking-query-tools.js +4 -4
- package/dist/plugin/openviking-recall-trace-runtime.js +3 -3
- package/dist/plugin/openviking-session-routing-runtime.js +9 -2
- package/dist/plugin/openviking-tool-result-tools.js +3 -3
- package/dist/routing/identity-routing.js +27 -0
- package/dist/routing/memory-uri.js +1 -0
- package/dist/services/context-lifecycle-service.js +21 -16
- package/dist/services/context-message-adapter.js +2 -9
- package/index.ts +13 -3
- package/install-manifest.json +1 -0
- package/openclaw.plugin.json +34 -3
- package/package.json +1 -1
- package/plugin/command-registration.ts +2 -0
- package/plugin/openviking-archive-tools.ts +1 -4
- package/plugin/openviking-command-definitions.ts +4 -3
- package/plugin/openviking-experience-tools.ts +160 -0
- package/plugin/openviking-import-tools.ts +4 -2
- package/plugin/openviking-memory-recall-tools.ts +6 -4
- package/plugin/openviking-memory-tools.ts +18 -10
- package/plugin/openviking-query-runtime.ts +1 -1
- package/plugin/openviking-query-tools.ts +6 -4
- package/plugin/openviking-recall-trace-runtime.ts +4 -3
- package/plugin/openviking-recall-trace-tools.ts +2 -0
- package/plugin/openviking-session-routing-runtime.ts +15 -1
- package/plugin/openviking-tool-result-tools.ts +0 -6
- package/registries/openviking-tools.ts +6 -0
- package/routing/identity-routing.ts +41 -0
- package/routing/memory-uri.ts +1 -0
- package/services/context-lifecycle-service.ts +27 -18
- package/services/context-message-adapter.ts +2 -9
- package/skills/ov-experience-memory/SKILL.md +156 -0
|
@@ -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
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export type OpenVikingToolGroup =
|
|
2
2
|
| "memory"
|
|
3
3
|
| "resource_query"
|
|
4
|
+
| "experience"
|
|
4
5
|
| "import"
|
|
5
6
|
| "recall_trace"
|
|
6
7
|
| "archive"
|
|
@@ -13,6 +14,8 @@ export type OpenVikingToolName =
|
|
|
13
14
|
| "ov_read"
|
|
14
15
|
| "ov_multi_read"
|
|
15
16
|
| "ov_list"
|
|
17
|
+
| "search_experience"
|
|
18
|
+
| "read_experience"
|
|
16
19
|
| "memory_recall"
|
|
17
20
|
| "ov_recall_trace"
|
|
18
21
|
| "memory_store"
|
|
@@ -44,6 +47,8 @@ export const OPENVIKING_TOOL_SPECS = [
|
|
|
44
47
|
{ name: "ov_read", group: "resource_query", defaultEnabled: true },
|
|
45
48
|
{ name: "ov_multi_read", group: "resource_query", defaultEnabled: true },
|
|
46
49
|
{ name: "ov_list", group: "resource_query", defaultEnabled: true },
|
|
50
|
+
{ name: "search_experience", group: "experience", defaultEnabled: true },
|
|
51
|
+
{ name: "read_experience", group: "experience", defaultEnabled: true },
|
|
47
52
|
{ name: "memory_recall", group: "memory", defaultEnabled: true },
|
|
48
53
|
{ name: "ov_recall_trace", group: "recall_trace", defaultEnabled: true },
|
|
49
54
|
{ name: "memory_store", group: "memory", defaultEnabled: true },
|
|
@@ -64,6 +69,7 @@ export const OPENVIKING_DEFAULT_ENABLED_TOOL_NAMES = OPENVIKING_TOOL_SPECS
|
|
|
64
69
|
const OPENVIKING_TOOL_GROUP_ORDER: readonly OpenVikingToolGroup[] = [
|
|
65
70
|
"memory",
|
|
66
71
|
"resource_query",
|
|
72
|
+
"experience",
|
|
67
73
|
"import",
|
|
68
74
|
"recall_trace",
|
|
69
75
|
"archive",
|
|
@@ -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"
|
package/routing/memory-uri.ts
CHANGED
|
@@ -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 {
|
|
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
|
|
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
|
|
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
|
-
|
|
908
|
+
undefined,
|
|
903
909
|
createdAt,
|
|
904
|
-
|
|
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
|
|
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,
|
|
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
|
|
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
|
|
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),
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { OVMessage } from "../client.js";
|
|
2
|
+
import { sanitizeOpenVikingPeerId } from "../routing/identity-routing.js";
|
|
2
3
|
import { sanitizeToolUseResultPairing } from "../session-transcript-repair.js";
|
|
3
4
|
|
|
4
5
|
export type AgentMessage = {
|
|
@@ -8,15 +9,7 @@ export type AgentMessage = {
|
|
|
8
9
|
};
|
|
9
10
|
|
|
10
11
|
export function toRoleId(senderId: string | undefined): string | undefined {
|
|
11
|
-
|
|
12
|
-
return undefined;
|
|
13
|
-
}
|
|
14
|
-
const normalized = senderId
|
|
15
|
-
.trim()
|
|
16
|
-
.replace(/[^a-zA-Z0-9_-]+/g, "_")
|
|
17
|
-
.replace(/^_+|_+$/g, "")
|
|
18
|
-
.replace(/_+/g, "_");
|
|
19
|
-
return normalized || undefined;
|
|
12
|
+
return sanitizeOpenVikingPeerId(senderId);
|
|
20
13
|
}
|
|
21
14
|
|
|
22
15
|
/**
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ov-experience-memory
|
|
3
|
+
description: >
|
|
4
|
+
Use OpenViking experience memories during task execution. Search relevant
|
|
5
|
+
experiences with search_experience, read selected experiences with
|
|
6
|
+
read_experience, and leave standard tool parts in the committed session so
|
|
7
|
+
OpenViking can report recall and injection usage.
|
|
8
|
+
version: 2026.7.9
|
|
9
|
+
tags:
|
|
10
|
+
- openviking
|
|
11
|
+
- experience-memory
|
|
12
|
+
- agent-memory
|
|
13
|
+
- usage-reporting
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# OpenViking Experience Memory
|
|
17
|
+
|
|
18
|
+
Use this skill when the current user request starts or continues an executable
|
|
19
|
+
task, especially tasks involving tools, files, code changes, data operations,
|
|
20
|
+
workflow decisions, or multi-step actions.
|
|
21
|
+
|
|
22
|
+
Do not use this skill for casual chat, pure explanation, or one-off factual Q&A
|
|
23
|
+
that does not require operational guidance.
|
|
24
|
+
|
|
25
|
+
## Runtime Contract
|
|
26
|
+
|
|
27
|
+
The agent runtime must expose two tools with these exact names:
|
|
28
|
+
|
|
29
|
+
- `search_experience`
|
|
30
|
+
- `read_experience`
|
|
31
|
+
|
|
32
|
+
OpenViking usage reporting recognizes only completed tool parts with these exact
|
|
33
|
+
tool names. Calls to generic `find`, `search`, `read`, `ov_search`, or `ov_read`
|
|
34
|
+
do not count as experience recall or injection events.
|
|
35
|
+
|
|
36
|
+
## Tool: search_experience
|
|
37
|
+
|
|
38
|
+
Purpose: search reusable execution experiences from the OpenViking experience
|
|
39
|
+
library before assembling task context.
|
|
40
|
+
|
|
41
|
+
Input schema:
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"query": "string",
|
|
46
|
+
"limit": 5
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Output schema:
|
|
51
|
+
|
|
52
|
+
```json
|
|
53
|
+
{
|
|
54
|
+
"results": [
|
|
55
|
+
{
|
|
56
|
+
"uri": "viking://user/<current_user_id>/memories/experiences/example.md",
|
|
57
|
+
"title": "example",
|
|
58
|
+
"score": 0.82,
|
|
59
|
+
"snippet": "Short summary or matched situation"
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Implementation:
|
|
66
|
+
|
|
67
|
+
The runtime tool calls OpenViking `POST /api/v1/search/find` with `target_uri`
|
|
68
|
+
fixed to the current-user shorthand `viking://user/memories/experiences/`.
|
|
69
|
+
Callers provide only `query` and optional `limit`; they cannot override or pass
|
|
70
|
+
`target_uri`. OpenViking resolves the fixed shorthand against the authenticated
|
|
71
|
+
request user. Return only canonical experience memory URIs for that user; never
|
|
72
|
+
hardcode `default` or another user ID.
|
|
73
|
+
|
|
74
|
+
Usage reporting:
|
|
75
|
+
|
|
76
|
+
A completed `search_experience` tool part is counted as an experience recall
|
|
77
|
+
event for every `results[].uri` value.
|
|
78
|
+
|
|
79
|
+
## Tool: read_experience
|
|
80
|
+
|
|
81
|
+
Purpose: read the full Markdown body of a selected experience and inject it into
|
|
82
|
+
the agent prompt as task execution guidance.
|
|
83
|
+
|
|
84
|
+
Input schema:
|
|
85
|
+
|
|
86
|
+
```json
|
|
87
|
+
{
|
|
88
|
+
"uri": "viking://user/<current_user_id>/memories/experiences/example.md"
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Output schema:
|
|
93
|
+
|
|
94
|
+
```json
|
|
95
|
+
{
|
|
96
|
+
"uri": "viking://user/<current_user_id>/memories/experiences/example.md",
|
|
97
|
+
"content": "Experience Markdown body"
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Implementation:
|
|
102
|
+
|
|
103
|
+
Call OpenViking `GET /api/v1/content/read?uri=<encoded_uri>` for the selected
|
|
104
|
+
experience URI. Always pass the canonical URI returned by `search_experience`;
|
|
105
|
+
do not construct a URI with a hardcoded user ID. The returned content should be
|
|
106
|
+
inserted into the prompt as operational guidance, not as user profile facts.
|
|
107
|
+
|
|
108
|
+
Usage reporting:
|
|
109
|
+
|
|
110
|
+
A completed `read_experience` tool part is counted as an experience injection
|
|
111
|
+
event for `tool_input.uri` or `tool_output.uri`. In this design, reading an
|
|
112
|
+
experience through `read_experience` means the experience was injected into the
|
|
113
|
+
prompt.
|
|
114
|
+
|
|
115
|
+
## Recommended Flow
|
|
116
|
+
|
|
117
|
+
1. When a task begins, build a short query from the latest user instruction,
|
|
118
|
+
current plan, active skill name, and important tool/environment context.
|
|
119
|
+
2. Call `search_experience` before final prompt assembly.
|
|
120
|
+
3. Review returned titles/snippets and select only experiences likely to affect
|
|
121
|
+
execution.
|
|
122
|
+
4. Call `read_experience` for selected experience URIs.
|
|
123
|
+
5. Inject the returned Markdown into the prompt under an explicit experience
|
|
124
|
+
section.
|
|
125
|
+
6. Continue task execution.
|
|
126
|
+
7. Commit the session normally. The committed session must include the
|
|
127
|
+
`search_experience` and `read_experience` tool parts so OpenViking can report
|
|
128
|
+
usage.
|
|
129
|
+
|
|
130
|
+
## Prompt Injection Format
|
|
131
|
+
|
|
132
|
+
Use a compact and explicit block:
|
|
133
|
+
|
|
134
|
+
```text
|
|
135
|
+
<openviking-experience-memory>
|
|
136
|
+
The following guidance was retrieved from prior task execution experience.
|
|
137
|
+
Use it as operational guidance. Do not treat it as user identity or preference.
|
|
138
|
+
|
|
139
|
+
<experience uri="viking://user/<current_user_id>/memories/experiences/example.md">
|
|
140
|
+
...experience markdown...
|
|
141
|
+
</experience>
|
|
142
|
+
</openviking-experience-memory>
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Commit Requirements
|
|
146
|
+
|
|
147
|
+
The session committed to OpenViking must preserve tool parts with:
|
|
148
|
+
|
|
149
|
+
- `tool_name`
|
|
150
|
+
- `tool_status`
|
|
151
|
+
- `tool_input`
|
|
152
|
+
- `tool_output`
|
|
153
|
+
- `tool_id`
|
|
154
|
+
|
|
155
|
+
Only `tool_status == "completed"` is counted. Failed, cancelled, or skipped tool
|
|
156
|
+
parts are ignored by usage reporting.
|