@openviking/openclaw-plugin 2026.8.7 → 2026.8.11

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/README.md CHANGED
@@ -46,8 +46,6 @@ Once installed, the plugin provides these agent tools:
46
46
  | `ov_read` | Read the full original content of one exact OpenViking URI |
47
47
  | `ov_multi_read` | Read the full original content of multiple OpenViking URIs |
48
48
  | `ov_list` | List OpenViking directories after search to inspect sibling chunks and overview files |
49
- | `search_experience` | Search reusable execution experiences for the current OpenViking user |
50
- | `read_experience` | Read one exact Experience returned by `search_experience` |
51
49
  | `openviking_tool_result_read` | Restore the full original content of an externalized tool result |
52
50
  | `openviking_tool_result_search` | Search inside an externalized tool result by keyword |
53
51
  | `openviking_tool_result_list` | List externalized tool results in the current session |
@@ -250,8 +248,6 @@ Beyond automatic behavior, the plugin exposes these tools directly:
250
248
  - `ov_read`: read one exact `viking://` URI returned by `ov_search` or `ov_list`
251
249
  - `ov_multi_read`: read multiple exact `viking://` URIs, useful for an overview plus sibling chunks
252
250
  - `ov_list`: list a hit's parent directory after `ov_search` to recover sibling chunks, `.overview.md`, and related split-document context
253
- - `search_experience`: search reusable execution experiences for the current OpenViking user
254
- - `read_experience`: read one exact Experience returned by `search_experience`
255
251
 
256
252
  They serve different roles:
257
253
 
@@ -265,7 +261,6 @@ They serve different roles:
265
261
  - `ov_read` turns a ranked hit into original evidence before answering precise documentation, codebase, configuration, or procedural questions
266
262
  - `ov_multi_read` reads overview and sibling chunks together when a split document needs more context than a single hit
267
263
  - `ov_list` complements `ov_search` when a ranked hit is only one chunk of a larger procedure or document
268
- - `search_experience` and `read_experience` provide the exact tool-call contract used by the bundled Experience Memory skill and usage reporting
269
264
 
270
265
  `ov_archive_expand` is especially important because `assemble()` normally returns archive summaries and indexes, not the full raw transcript.
271
266
 
package/config.ts CHANGED
@@ -170,8 +170,6 @@ export const OPENVIKING_DEFAULT_ENABLED_TOOL_NAMES = [
170
170
  "ov_read",
171
171
  "ov_multi_read",
172
172
  "ov_list",
173
- "search_experience",
174
- "read_experience",
175
173
  "memory_recall",
176
174
  "ov_recall_trace",
177
175
  "memory_store",
@@ -192,7 +190,9 @@ export const OPENVIKING_TOOL_GROUPS: Record<string, readonly OpenVikingToolName[
192
190
  default: OPENVIKING_DEFAULT_ENABLED_TOOL_NAMES,
193
191
  memory: ["memory_recall", "memory_store", "memory_forget"],
194
192
  resource_query: ["ov_search", "ov_read", "ov_multi_read", "ov_list"],
195
- experience: ["search_experience", "read_experience"],
193
+ // Migration alias for configurations that previously selected the removed
194
+ // search_experience/read_experience tools.
195
+ experience: ["ov_search", "ov_read"],
196
196
  import: ["add_resource", "add_skill"],
197
197
  recall_trace: ["ov_recall_trace"],
198
198
  archive: ["ov_archive_search", "ov_archive_expand"],
@@ -951,7 +951,7 @@ export const memoryOpenVikingConfigSchema = {
951
951
  enabledTools: {
952
952
  label: "Enabled Tools",
953
953
  placeholder: "default",
954
- help: "Agent-visible tool allowlist. Accepts tool names or groups: default, all, memory, resource_query, experience, import, recall_trace, archive, tool_result. add_resource also requires enableAddResourceTool=true.",
954
+ help: "Agent-visible tool allowlist. Accepts tool names or groups: default, all, memory, resource_query, experience (legacy alias), import, recall_trace, archive, tool_result. add_resource also requires enableAddResourceTool=true.",
955
955
  advanced: true,
956
956
  },
957
957
  disabledTools: {
package/dist/config.js CHANGED
@@ -35,8 +35,6 @@ export const OPENVIKING_DEFAULT_ENABLED_TOOL_NAMES = [
35
35
  "ov_read",
36
36
  "ov_multi_read",
37
37
  "ov_list",
38
- "search_experience",
39
- "read_experience",
40
38
  "memory_recall",
41
39
  "ov_recall_trace",
42
40
  "memory_store",
@@ -56,7 +54,9 @@ export const OPENVIKING_TOOL_GROUPS = {
56
54
  default: OPENVIKING_DEFAULT_ENABLED_TOOL_NAMES,
57
55
  memory: ["memory_recall", "memory_store", "memory_forget"],
58
56
  resource_query: ["ov_search", "ov_read", "ov_multi_read", "ov_list"],
59
- experience: ["search_experience", "read_experience"],
57
+ // Migration alias for configurations that previously selected the removed
58
+ // search_experience/read_experience tools.
59
+ experience: ["ov_search", "ov_read"],
60
60
  import: ["add_resource", "add_skill"],
61
61
  recall_trace: ["ov_recall_trace"],
62
62
  archive: ["ov_archive_search", "ov_archive_expand"],
@@ -653,7 +653,7 @@ export const memoryOpenVikingConfigSchema = {
653
653
  enabledTools: {
654
654
  label: "Enabled Tools",
655
655
  placeholder: "default",
656
- help: "Agent-visible tool allowlist. Accepts tool names or groups: default, all, memory, resource_query, experience, import, recall_trace, archive, tool_result. add_resource also requires enableAddResourceTool=true.",
656
+ help: "Agent-visible tool allowlist. Accepts tool names or groups: default, all, memory, resource_query, experience (legacy alias), import, recall_trace, archive, tool_result. add_resource also requires enableAddResourceTool=true.",
657
657
  advanced: true,
658
658
  },
659
659
  disabledTools: {
package/dist/index.js CHANGED
@@ -15,7 +15,6 @@ import { registerOpenVikingCommands } from "./plugin/command-registration.js";
15
15
  import { registerRecallTraceRoutes as registerRecallTraceRouteAdapters } from "./plugin/recall-trace-routes.js";
16
16
  import { createOpenVikingService } from "./plugin/openviking-services.js";
17
17
  import { registerOpenVikingArchiveTools } from "./plugin/openviking-archive-tools.js";
18
- import { registerOpenVikingExperienceTools } from "./plugin/openviking-experience-tools.js";
19
18
  import { createOpenVikingImportRuntime } from "./plugin/openviking-import-runtime.js";
20
19
  import { registerOpenVikingImportTools } from "./plugin/openviking-import-tools.js";
21
20
  import { registerOpenVikingLifecycleHooks } from "./plugin/openviking-lifecycle-hooks.js";
@@ -137,14 +136,6 @@ const contextEnginePlugin = {
137
136
  isBypassedSession,
138
137
  makeBypassedToolResult,
139
138
  });
140
- registerOpenVikingExperienceTools({
141
- registerTool: registerOpenVikingTool,
142
- getClient,
143
- resolvePluginSessionRouting,
144
- isBypassedSession,
145
- makeBypassedToolResult,
146
- userId: cfg.userId,
147
- });
148
139
  registerOpenVikingMemoryRecallTools({
149
140
  registerTool: registerOpenVikingTool,
150
141
  getClient,
@@ -346,7 +346,7 @@ export function extractNewTurnMessages(messages, startIndex) {
346
346
  toolName,
347
347
  toolInput,
348
348
  toolOutput: output,
349
- toolStatus: "completed",
349
+ toolStatus: msg.isError === true ? "error" : "completed",
350
350
  }],
351
351
  });
352
352
  }
package/index.ts CHANGED
@@ -19,7 +19,6 @@ import { registerOpenVikingCommands } from "./plugin/command-registration.js";
19
19
  import { registerRecallTraceRoutes as registerRecallTraceRouteAdapters } from "./plugin/recall-trace-routes.js";
20
20
  import { createOpenVikingService } from "./plugin/openviking-services.js";
21
21
  import { registerOpenVikingArchiveTools } from "./plugin/openviking-archive-tools.js";
22
- import { registerOpenVikingExperienceTools } from "./plugin/openviking-experience-tools.js";
23
22
  import { createOpenVikingImportRuntime } from "./plugin/openviking-import-runtime.js";
24
23
  import { registerOpenVikingImportTools } from "./plugin/openviking-import-tools.js";
25
24
  import { registerOpenVikingLifecycleHooks } from "./plugin/openviking-lifecycle-hooks.js";
@@ -281,15 +280,6 @@ const contextEnginePlugin = {
281
280
  makeBypassedToolResult,
282
281
  });
283
282
 
284
- registerOpenVikingExperienceTools({
285
- registerTool: registerOpenVikingTool,
286
- getClient,
287
- resolvePluginSessionRouting,
288
- isBypassedSession,
289
- makeBypassedToolResult,
290
- userId: cfg.userId,
291
- });
292
-
293
283
  registerOpenVikingMemoryRecallTools({
294
284
  registerTool: registerOpenVikingTool,
295
285
  getClient,
@@ -41,7 +41,6 @@
41
41
  ".gitignore",
42
42
  "skills/install-openviking-memory/SKILL.md",
43
43
  "skills/openviking-context-database/SKILL.md",
44
- "skills/ov-experience-memory/SKILL.md",
45
44
  "INSTALL-AGENT.md"
46
45
  ]
47
46
  },
@@ -19,8 +19,6 @@
19
19
  "ov_read",
20
20
  "ov_multi_read",
21
21
  "ov_list",
22
- "search_experience",
23
- "read_experience",
24
22
  "memory_recall",
25
23
  "ov_recall_trace",
26
24
  "memory_store",
@@ -254,7 +252,7 @@
254
252
  "enabledTools": {
255
253
  "label": "Enabled Tools",
256
254
  "placeholder": "default",
257
- "help": "Agent-visible tool allowlist. Accepts tool names or groups: default, all, memory, resource_query, experience, import, recall_trace, archive, tool_result. add_resource also requires enableAddResourceTool=true.",
255
+ "help": "Agent-visible tool allowlist. Accepts tool names or groups: default, all, memory, resource_query, import, recall_trace, archive, tool_result. add_resource also requires enableAddResourceTool=true.",
258
256
  "advanced": true
259
257
  },
260
258
  "disabledTools": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openviking/openclaw-plugin",
3
- "version": "2026.8.7",
3
+ "version": "2026.8.11",
4
4
  "displayName": "OpenViking",
5
5
  "description": "OpenClaw context-engine plugin — OpenViking AI memory, long-term memory, knowledge base, semantic search, RAG, context engine. 长期记忆 · 知识库 · 语义检索 · 上下文引擎",
6
6
  "type": "module",
@@ -1,7 +1,6 @@
1
1
  export type OpenVikingToolGroup =
2
2
  | "memory"
3
3
  | "resource_query"
4
- | "experience"
5
4
  | "import"
6
5
  | "recall_trace"
7
6
  | "archive"
@@ -14,8 +13,6 @@ export type OpenVikingToolName =
14
13
  | "ov_read"
15
14
  | "ov_multi_read"
16
15
  | "ov_list"
17
- | "search_experience"
18
- | "read_experience"
19
16
  | "memory_recall"
20
17
  | "ov_recall_trace"
21
18
  | "memory_store"
@@ -47,8 +44,6 @@ export const OPENVIKING_TOOL_SPECS = [
47
44
  { name: "ov_read", group: "resource_query", defaultEnabled: true },
48
45
  { name: "ov_multi_read", group: "resource_query", defaultEnabled: true },
49
46
  { name: "ov_list", group: "resource_query", defaultEnabled: true },
50
- { name: "search_experience", group: "experience", defaultEnabled: true },
51
- { name: "read_experience", group: "experience", defaultEnabled: true },
52
47
  { name: "memory_recall", group: "memory", defaultEnabled: true },
53
48
  { name: "ov_recall_trace", group: "recall_trace", defaultEnabled: true },
54
49
  { name: "memory_store", group: "memory", defaultEnabled: true },
@@ -69,7 +64,6 @@ export const OPENVIKING_DEFAULT_ENABLED_TOOL_NAMES = OPENVIKING_TOOL_SPECS
69
64
  const OPENVIKING_TOOL_GROUP_ORDER: readonly OpenVikingToolGroup[] = [
70
65
  "memory",
71
66
  "resource_query",
72
- "experience",
73
67
  "import",
74
68
  "recall_trace",
75
69
  "archive",
@@ -79,6 +73,8 @@ const OPENVIKING_TOOL_GROUP_ORDER: readonly OpenVikingToolGroup[] = [
79
73
  export const OPENVIKING_TOOL_GROUPS: Record<string, readonly OpenVikingToolName[]> = {
80
74
  all: OPENVIKING_ALL_TOOL_NAMES,
81
75
  default: OPENVIKING_DEFAULT_ENABLED_TOOL_NAMES,
76
+ // Migration alias for the removed dedicated Experience tools.
77
+ experience: ["ov_search", "ov_read"],
82
78
  ...Object.fromEntries(
83
79
  OPENVIKING_TOOL_GROUP_ORDER.map((group) => [
84
80
  group,
package/text-utils.ts CHANGED
@@ -411,7 +411,7 @@ export function extractNewTurnMessages(
411
411
  toolName,
412
412
  toolInput,
413
413
  toolOutput: output,
414
- toolStatus: "completed",
414
+ toolStatus: msg.isError === true ? "error" : "completed",
415
415
  }],
416
416
  });
417
417
  }
@@ -1,105 +0,0 @@
1
- import { Type } from "@sinclair/typebox";
2
- const EXPERIENCE_TARGET_URI = "viking://user/memories/experiences/";
3
- const DEFAULT_LIMIT = 5;
4
- const MAX_LIMIT = 20;
5
- const EXPERIENCE_SIDECAR_FILENAMES = new Set([".abstract.md", ".overview.md", ".relations.json"]);
6
- function clampLimit(value) {
7
- const parsed = Number.isFinite(Number(value)) ? Math.trunc(Number(value)) : DEFAULT_LIMIT;
8
- return Math.max(1, Math.min(MAX_LIMIT, parsed));
9
- }
10
- function experienceRelativePath(uri) {
11
- return uri.match(/^viking:\/\/user\/[^/]+\/memories\/experiences\/(.+)$/)?.[1] ?? "";
12
- }
13
- export function isCanonicalExperienceUri(uri, expectedUserId) {
14
- const value = typeof uri === "string" ? uri.trim() : "";
15
- if (!value || value.includes("?") || value.includes("#")) {
16
- return false;
17
- }
18
- const owner = value.match(/^viking:\/\/user\/([^/]+)\//)?.[1] ?? "";
19
- if (expectedUserId?.trim() && owner !== expectedUserId.trim()) {
20
- return false;
21
- }
22
- const relative = experienceRelativePath(value);
23
- const segments = relative.split("/");
24
- const basename = segments.at(-1) ?? "";
25
- return Boolean(relative
26
- && segments.every((segment) => segment && segment !== "." && segment !== "..")
27
- && !EXPERIENCE_SIDECAR_FILENAMES.has(basename));
28
- }
29
- function titleFromUri(uri) {
30
- const basename = uri.split("/").at(-1) ?? uri;
31
- const title = basename.replace(/\.md$/i, "");
32
- try {
33
- return decodeURIComponent(title);
34
- }
35
- catch {
36
- return title;
37
- }
38
- }
39
- function jsonToolResult(payload) {
40
- return {
41
- content: [{ type: "text", text: JSON.stringify(payload) }],
42
- };
43
- }
44
- export function registerOpenVikingExperienceTools(deps) {
45
- deps.registerTool((ctx) => ({
46
- name: "search_experience",
47
- label: "Search Experience (OpenViking)",
48
- description: "Search reusable task-execution experiences for the current OpenViking user. " +
49
- "Use before executing operational or multi-step tasks, then call read_experience for selected results.",
50
- parameters: Type.Object({
51
- query: Type.String({ description: "Current task, situation, or execution problem to search for" }),
52
- limit: Type.Optional(Type.Integer({
53
- description: `Maximum results to return. Default: ${DEFAULT_LIMIT}; maximum: ${MAX_LIMIT}`,
54
- minimum: 1,
55
- maximum: MAX_LIMIT,
56
- })),
57
- }, { additionalProperties: false }),
58
- async execute(_toolCallId, params) {
59
- if (deps.isBypassedSession(ctx)) {
60
- return deps.makeBypassedToolResult("search_experience");
61
- }
62
- const query = typeof params.query === "string" ? params.query.trim() : "";
63
- if (!query) {
64
- throw new Error("query is required");
65
- }
66
- const session = deps.resolvePluginSessionRouting(ctx);
67
- const client = await deps.getClient();
68
- const result = await client.find(query, {
69
- targetUri: EXPERIENCE_TARGET_URI,
70
- limit: clampLimit(params.limit),
71
- }, session.actorPeerId);
72
- const results = (result.memories ?? [])
73
- .filter((item) => isCanonicalExperienceUri(item.uri, deps.userId))
74
- .map((item) => ({
75
- uri: item.uri,
76
- title: titleFromUri(item.uri),
77
- score: typeof item.score === "number" ? item.score : 0,
78
- snippet: item.abstract || item.overview || "",
79
- }));
80
- return jsonToolResult({ results });
81
- },
82
- }), { name: "search_experience" });
83
- deps.registerTool((ctx) => ({
84
- name: "read_experience",
85
- label: "Read Experience (OpenViking)",
86
- description: "Read the complete Markdown body of one Experience returned by search_experience and use it as execution guidance.",
87
- parameters: Type.Object({
88
- uri: Type.String({ description: "Exact canonical Experience URI returned by search_experience" }),
89
- }, { additionalProperties: false }),
90
- async execute(_toolCallId, params) {
91
- if (deps.isBypassedSession(ctx)) {
92
- return deps.makeBypassedToolResult("read_experience");
93
- }
94
- const uri = typeof params.uri === "string" ? params.uri.trim() : "";
95
- if (!isCanonicalExperienceUri(uri, deps.userId)) {
96
- throw new Error("uri must be a canonical OpenViking Experience URI returned by search_experience");
97
- }
98
- const session = deps.resolvePluginSessionRouting(ctx);
99
- const client = await deps.getClient();
100
- const content = await client.read(uri, session.actorPeerId);
101
- const text = typeof content === "string" ? content : JSON.stringify(content, null, 2);
102
- return jsonToolResult({ uri, content: text });
103
- },
104
- }), { name: "read_experience" });
105
- }
@@ -1,160 +0,0 @@
1
- import { Type } from "@sinclair/typebox";
2
-
3
- import type { FindResult } from "../client.js";
4
-
5
- const EXPERIENCE_TARGET_URI = "viking://user/memories/experiences/";
6
- const DEFAULT_LIMIT = 5;
7
- const MAX_LIMIT = 20;
8
- const EXPERIENCE_SIDECAR_FILENAMES = new Set([".abstract.md", ".overview.md", ".relations.json"]);
9
-
10
- export type OpenVikingExperienceToolContext = {
11
- sessionKey?: string;
12
- sessionId?: string;
13
- agentId?: string;
14
- senderId?: string;
15
- requesterSenderId?: string;
16
- };
17
-
18
- export type OpenVikingExperienceSession = {
19
- sessionId?: string;
20
- sessionKey?: string;
21
- ovSessionId?: string;
22
- agentId: string;
23
- actorPeerId?: string;
24
- };
25
-
26
- type OpenVikingExperienceClient = {
27
- find: (
28
- query: string,
29
- options: { targetUri: string; limit: number; scoreThreshold?: number },
30
- actorPeerId?: string,
31
- ) => Promise<FindResult>;
32
- read: (uri: string, actorPeerId?: string) => Promise<unknown>;
33
- };
34
-
35
- export type OpenVikingExperienceToolsDeps = {
36
- registerTool: (toolOrFactory: unknown, opts: { name: string }) => void;
37
- getClient: () => Promise<OpenVikingExperienceClient>;
38
- resolvePluginSessionRouting: (ctx?: OpenVikingExperienceToolContext) => OpenVikingExperienceSession;
39
- isBypassedSession: (ctx?: OpenVikingExperienceToolContext) => boolean;
40
- makeBypassedToolResult: (toolName: string) => unknown;
41
- userId?: string;
42
- };
43
-
44
- function clampLimit(value: unknown): number {
45
- const parsed = Number.isFinite(Number(value)) ? Math.trunc(Number(value)) : DEFAULT_LIMIT;
46
- return Math.max(1, Math.min(MAX_LIMIT, parsed));
47
- }
48
-
49
- function experienceRelativePath(uri: string): string {
50
- return uri.match(/^viking:\/\/user\/[^/]+\/memories\/experiences\/(.+)$/)?.[1] ?? "";
51
- }
52
-
53
- export function isCanonicalExperienceUri(uri: unknown, expectedUserId?: string): uri is string {
54
- const value = typeof uri === "string" ? uri.trim() : "";
55
- if (!value || value.includes("?") || value.includes("#")) {
56
- return false;
57
- }
58
- const owner = value.match(/^viking:\/\/user\/([^/]+)\//)?.[1] ?? "";
59
- if (expectedUserId?.trim() && owner !== expectedUserId.trim()) {
60
- return false;
61
- }
62
- const relative = experienceRelativePath(value);
63
- const segments = relative.split("/");
64
- const basename = segments.at(-1) ?? "";
65
- return Boolean(
66
- relative
67
- && segments.every((segment) => segment && segment !== "." && segment !== "..")
68
- && !EXPERIENCE_SIDECAR_FILENAMES.has(basename)
69
- );
70
- }
71
-
72
- function titleFromUri(uri: string): string {
73
- const basename = uri.split("/").at(-1) ?? uri;
74
- const title = basename.replace(/\.md$/i, "");
75
- try {
76
- return decodeURIComponent(title);
77
- } catch {
78
- return title;
79
- }
80
- }
81
-
82
- function jsonToolResult(payload: Record<string, unknown>): {
83
- content: Array<{ type: "text"; text: string }>;
84
- } {
85
- return {
86
- content: [{ type: "text", text: JSON.stringify(payload) }],
87
- };
88
- }
89
-
90
- export function registerOpenVikingExperienceTools(deps: OpenVikingExperienceToolsDeps): void {
91
- deps.registerTool(
92
- (ctx: OpenVikingExperienceToolContext) => ({
93
- name: "search_experience",
94
- label: "Search Experience (OpenViking)",
95
- description:
96
- "Search reusable task-execution experiences for the current OpenViking user. " +
97
- "Use before executing operational or multi-step tasks, then call read_experience for selected results.",
98
- parameters: Type.Object({
99
- query: Type.String({ description: "Current task, situation, or execution problem to search for" }),
100
- limit: Type.Optional(Type.Integer({
101
- description: `Maximum results to return. Default: ${DEFAULT_LIMIT}; maximum: ${MAX_LIMIT}`,
102
- minimum: 1,
103
- maximum: MAX_LIMIT,
104
- })),
105
- }, { additionalProperties: false }),
106
- async execute(_toolCallId: string, params: Record<string, unknown>) {
107
- if (deps.isBypassedSession(ctx)) {
108
- return deps.makeBypassedToolResult("search_experience");
109
- }
110
- const query = typeof params.query === "string" ? params.query.trim() : "";
111
- if (!query) {
112
- throw new Error("query is required");
113
- }
114
- const session = deps.resolvePluginSessionRouting(ctx);
115
- const client = await deps.getClient();
116
- const result = await client.find(query, {
117
- targetUri: EXPERIENCE_TARGET_URI,
118
- limit: clampLimit(params.limit),
119
- }, session.actorPeerId);
120
- const results = (result.memories ?? [])
121
- .filter((item) => isCanonicalExperienceUri(item.uri, deps.userId))
122
- .map((item) => ({
123
- uri: item.uri,
124
- title: titleFromUri(item.uri),
125
- score: typeof item.score === "number" ? item.score : 0,
126
- snippet: item.abstract || item.overview || "",
127
- }));
128
- return jsonToolResult({ results });
129
- },
130
- }),
131
- { name: "search_experience" },
132
- );
133
-
134
- deps.registerTool(
135
- (ctx: OpenVikingExperienceToolContext) => ({
136
- name: "read_experience",
137
- label: "Read Experience (OpenViking)",
138
- description:
139
- "Read the complete Markdown body of one Experience returned by search_experience and use it as execution guidance.",
140
- parameters: Type.Object({
141
- uri: Type.String({ description: "Exact canonical Experience URI returned by search_experience" }),
142
- }, { additionalProperties: false }),
143
- async execute(_toolCallId: string, params: Record<string, unknown>) {
144
- if (deps.isBypassedSession(ctx)) {
145
- return deps.makeBypassedToolResult("read_experience");
146
- }
147
- const uri = typeof params.uri === "string" ? params.uri.trim() : "";
148
- if (!isCanonicalExperienceUri(uri, deps.userId)) {
149
- throw new Error("uri must be a canonical OpenViking Experience URI returned by search_experience");
150
- }
151
- const session = deps.resolvePluginSessionRouting(ctx);
152
- const client = await deps.getClient();
153
- const content = await client.read(uri, session.actorPeerId);
154
- const text = typeof content === "string" ? content : JSON.stringify(content, null, 2);
155
- return jsonToolResult({ uri, content: text });
156
- },
157
- }),
158
- { name: "read_experience" },
159
- );
160
- }
@@ -1,156 +0,0 @@
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.