@openviking/openclaw-plugin 2026.8.6 → 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/INSTALL-ZH.md +1 -1
- package/INSTALL.md +1 -1
- package/README.md +0 -5
- package/config.ts +22 -46
- package/dist/config.js +15 -38
- package/dist/index.js +0 -9
- package/dist/text-utils.js +1 -1
- package/index.ts +0 -10
- package/install-manifest.json +0 -1
- package/openclaw.plugin.json +2 -16
- package/package.json +1 -1
- package/registries/openviking-tools.ts +2 -6
- package/text-utils.ts +1 -1
- package/dist/plugin/openviking-experience-tools.js +0 -105
- package/plugin/openviking-experience-tools.ts +0 -160
- package/skills/ov-experience-memory/SKILL.md +0 -156
package/INSTALL-ZH.md
CHANGED
|
@@ -238,7 +238,7 @@ openclaw openviking setup --base-url <OPENVIKING_URL> --api-key <API_KEY> --peer
|
|
|
238
238
|
| --- | --- | --- |
|
|
239
239
|
| `env` | `{ "source": "env", "id": "OPENVIKING_API_KEY" }` | 启动时读取同名环境变量。 |
|
|
240
240
|
| `file` | `{ "source": "file", "id": "/etc/secrets/openviking.key" }` | 以 UTF-8 读取并去除首尾空白;`~` 可展开,适配 Kubernetes `secretKeyRef` 卷挂载、0600 权限文件。 |
|
|
241
|
-
| `exec` |
|
|
241
|
+
| `exec` | 打包版插件不支持(应用市场安装扫描会拦截子进程执行) | 改用命令包一层环境变量:`OPENVIKING_API_KEY=$(op read op://vault/openviking/credential)`,然后配 `env`。 |
|
|
242
242
|
|
|
243
243
|
仍可使用纯字符串形式(含 `${ENV_VAR}` 插值)作为向后兼容路径;此时请限制文件权限或通过受控 Secret 卷提供,并在修改后重启 Gateway、容器或 Pod。
|
|
244
244
|
|
package/INSTALL.md
CHANGED
|
@@ -182,7 +182,7 @@ If the `openclaw` CLI cannot run inside the container, merge the following field
|
|
|
182
182
|
| --- | --- | --- |
|
|
183
183
|
| `env` | `{ "source": "env", "id": "OPENVIKING_API_KEY" }` | Reads the named env var at plugin load time. |
|
|
184
184
|
| `file` | `{ "source": "file", "id": "/etc/secrets/openviking.key" }` | Reads UTF-8, trims whitespace. `~` is expanded; ideal for Kubernetes `secretKeyRef` volumes and 0600-managed files. |
|
|
185
|
-
| `exec` |
|
|
185
|
+
| `exec` | not supported in the packaged plugin (marketplace install scanners block subprocess execution) | Wrap the CLI instead: `OPENVIKING_API_KEY=$(op read op://vault/openviking/credential)` and use `env`. |
|
|
186
186
|
|
|
187
187
|
A plain `string` (including `${ENV_VAR}` interpolation) is still accepted, but only as a backward-compatibility path; in that case, restrict file permissions or provide the file through a managed Secret volume, then restart the Gateway, container, or Pod.
|
|
188
188
|
|
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
|
@@ -16,11 +16,11 @@ import { getEnv } from "./runtime-utils.js";
|
|
|
16
16
|
* leading/trailing whitespace trimmed — convenient for
|
|
17
17
|
* Kubernetes `secretKeyRef` mount volumes and
|
|
18
18
|
* file-permission-only deployments.
|
|
19
|
-
* source: "exec" ->
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
19
|
+
* source: "exec" -> NOT supported in the packaged plugin. Marketplace
|
|
20
|
+
* install scanners (OpenClaw/ArkClaw) block any plugin
|
|
21
|
+
* whose shipped code can spawn subprocesses, so the exec
|
|
22
|
+
* resolver was removed from this build; configuring it
|
|
23
|
+
* fails with a clear error pointing at env/file instead.
|
|
24
24
|
*/
|
|
25
25
|
export type OpenVikingSecretRef =
|
|
26
26
|
| { source: "env"; id: string }
|
|
@@ -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
|
-
|
|
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"],
|
|
@@ -232,13 +232,10 @@ function resolvePeerPrefix(configured: unknown): string {
|
|
|
232
232
|
* Missing / unreadable files propagate the original node error with an
|
|
233
233
|
* error prefix that names the OpenViking field, so the user knows which
|
|
234
234
|
* secretRef failed to load.
|
|
235
|
-
* * `exec`:
|
|
236
|
-
*
|
|
237
|
-
*
|
|
238
|
-
*
|
|
239
|
-
* best-effort; failures surface with an error prefix so users can
|
|
240
|
-
* distinguish `provider not installed` from `provider configured but id
|
|
241
|
-
* missing`.
|
|
235
|
+
* * `exec`: rejected with a "not supported" error. The subprocess-based
|
|
236
|
+
* resolver was removed because marketplace install scanners block plugins
|
|
237
|
+
* whose shipped code can spawn processes; wrap the secret-manager CLI
|
|
238
|
+
* output into an env var or file instead (`OPENVIKING_API_KEY=$(op ...)`).
|
|
242
239
|
*/
|
|
243
240
|
function resolveSecret(
|
|
244
241
|
value: string | OpenVikingSecretRef | undefined | null,
|
|
@@ -249,7 +246,7 @@ function resolveSecret(
|
|
|
249
246
|
if (!value || typeof value !== "object") {
|
|
250
247
|
throw new Error(
|
|
251
248
|
`OpenViking ${label} must be a plain string or a SecretRef object ` +
|
|
252
|
-
`({source:"env"|"file"
|
|
249
|
+
`({source:"env"|"file", id})`,
|
|
253
250
|
);
|
|
254
251
|
}
|
|
255
252
|
const obj = value as Record<string, unknown>;
|
|
@@ -280,39 +277,18 @@ function resolveSecret(
|
|
|
280
277
|
}
|
|
281
278
|
}
|
|
282
279
|
case "exec": {
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
);
|
|
290
|
-
}
|
|
291
|
-
try {
|
|
292
|
-
// Avoid top-level `import "node:child_process"` — this branch is rare
|
|
293
|
-
// and keeping the require lazy makes startup marginally faster for
|
|
294
|
-
// the 95% of users who pick env/file.
|
|
295
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
296
|
-
const { execFileSync } = require("node:child_process") as typeof import("node:child_process");
|
|
297
|
-
const out = execFileSync(provider, [id], {
|
|
298
|
-
encoding: "utf8",
|
|
299
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
300
|
-
timeout: 15_000,
|
|
301
|
-
env: process.env,
|
|
302
|
-
}) as string;
|
|
303
|
-
return out.trim();
|
|
304
|
-
} catch (err) {
|
|
305
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
306
|
-
throw new Error(
|
|
307
|
-
`OpenViking ${label} SecretRef exec source: provider "${provider}" failed for id "${id}" (${msg})`,
|
|
308
|
-
);
|
|
309
|
-
}
|
|
280
|
+
throw new Error(
|
|
281
|
+
`OpenViking ${label} SecretRef exec source is not supported in the packaged plugin ` +
|
|
282
|
+
`(marketplace install scanners block subprocess execution). Export the secret to an ` +
|
|
283
|
+
`environment variable ({source:"env"}) or a file ({source:"file"}) instead, e.g. ` +
|
|
284
|
+
`OPENVIKING_API_KEY=$(op read ${id}).`,
|
|
285
|
+
);
|
|
310
286
|
}
|
|
311
287
|
default:
|
|
312
288
|
throw new Error(
|
|
313
289
|
`OpenViking ${label} SecretRef has unknown source "${String(
|
|
314
290
|
(obj as Record<string, unknown>).source,
|
|
315
|
-
)}". Supported: "env" | "file"
|
|
291
|
+
)}". Supported: "env" | "file".`,
|
|
316
292
|
);
|
|
317
293
|
}
|
|
318
294
|
}
|
|
@@ -816,7 +792,7 @@ export const memoryOpenVikingConfigSchema = {
|
|
|
816
792
|
placeholder: "${OPENVIKING_API_KEY}",
|
|
817
793
|
help:
|
|
818
794
|
"Optional API key for OpenViking server. Accepts a plain string, " +
|
|
819
|
-
"${ENV_VAR} interpolation, or a SecretRef object ({source: env/file
|
|
795
|
+
"${ENV_VAR} interpolation, or a SecretRef object ({source: env/file, id}). " +
|
|
820
796
|
"Prefer the SecretRef shapes so the key never sits as plaintext in openclaw.json.",
|
|
821
797
|
},
|
|
822
798
|
headers: {
|
|
@@ -975,7 +951,7 @@ export const memoryOpenVikingConfigSchema = {
|
|
|
975
951
|
enabledTools: {
|
|
976
952
|
label: "Enabled Tools",
|
|
977
953
|
placeholder: "default",
|
|
978
|
-
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.",
|
|
979
955
|
advanced: true,
|
|
980
956
|
},
|
|
981
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
|
-
|
|
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"],
|
|
@@ -94,13 +94,10 @@ function resolvePeerPrefix(configured) {
|
|
|
94
94
|
* Missing / unreadable files propagate the original node error with an
|
|
95
95
|
* error prefix that names the OpenViking field, so the user knows which
|
|
96
96
|
* secretRef failed to load.
|
|
97
|
-
* * `exec`:
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
* best-effort; failures surface with an error prefix so users can
|
|
102
|
-
* distinguish `provider not installed` from `provider configured but id
|
|
103
|
-
* missing`.
|
|
97
|
+
* * `exec`: rejected with a "not supported" error. The subprocess-based
|
|
98
|
+
* resolver was removed because marketplace install scanners block plugins
|
|
99
|
+
* whose shipped code can spawn processes; wrap the secret-manager CLI
|
|
100
|
+
* output into an env var or file instead (`OPENVIKING_API_KEY=$(op ...)`).
|
|
104
101
|
*/
|
|
105
102
|
function resolveSecret(value, label) {
|
|
106
103
|
if (value === undefined || value === null)
|
|
@@ -109,7 +106,7 @@ function resolveSecret(value, label) {
|
|
|
109
106
|
return value;
|
|
110
107
|
if (!value || typeof value !== "object") {
|
|
111
108
|
throw new Error(`OpenViking ${label} must be a plain string or a SecretRef object ` +
|
|
112
|
-
`({source:"env"|"file"
|
|
109
|
+
`({source:"env"|"file", id})`);
|
|
113
110
|
}
|
|
114
111
|
const obj = value;
|
|
115
112
|
if (typeof obj.id !== "string" || !obj.id) {
|
|
@@ -136,33 +133,13 @@ function resolveSecret(value, label) {
|
|
|
136
133
|
}
|
|
137
134
|
}
|
|
138
135
|
case "exec": {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
: ""
|
|
142
|
-
|
|
143
|
-
throw new Error(`OpenViking ${label} SecretRef exec source requires a "provider" field naming the secret-manager CLI on PATH`);
|
|
144
|
-
}
|
|
145
|
-
try {
|
|
146
|
-
// Avoid top-level `import "node:child_process"` — this branch is rare
|
|
147
|
-
// and keeping the require lazy makes startup marginally faster for
|
|
148
|
-
// the 95% of users who pick env/file.
|
|
149
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
150
|
-
const { execFileSync } = require("node:child_process");
|
|
151
|
-
const out = execFileSync(provider, [id], {
|
|
152
|
-
encoding: "utf8",
|
|
153
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
154
|
-
timeout: 15_000,
|
|
155
|
-
env: process.env,
|
|
156
|
-
});
|
|
157
|
-
return out.trim();
|
|
158
|
-
}
|
|
159
|
-
catch (err) {
|
|
160
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
161
|
-
throw new Error(`OpenViking ${label} SecretRef exec source: provider "${provider}" failed for id "${id}" (${msg})`);
|
|
162
|
-
}
|
|
136
|
+
throw new Error(`OpenViking ${label} SecretRef exec source is not supported in the packaged plugin ` +
|
|
137
|
+
`(marketplace install scanners block subprocess execution). Export the secret to an ` +
|
|
138
|
+
`environment variable ({source:"env"}) or a file ({source:"file"}) instead, e.g. ` +
|
|
139
|
+
`OPENVIKING_API_KEY=$(op read ${id}).`);
|
|
163
140
|
}
|
|
164
141
|
default:
|
|
165
|
-
throw new Error(`OpenViking ${label} SecretRef has unknown source "${String(obj.source)}". Supported: "env" | "file"
|
|
142
|
+
throw new Error(`OpenViking ${label} SecretRef has unknown source "${String(obj.source)}". Supported: "env" | "file".`);
|
|
166
143
|
}
|
|
167
144
|
}
|
|
168
145
|
function resolvePeerRole(configured) {
|
|
@@ -519,7 +496,7 @@ export const memoryOpenVikingConfigSchema = {
|
|
|
519
496
|
sensitive: true,
|
|
520
497
|
placeholder: "${OPENVIKING_API_KEY}",
|
|
521
498
|
help: "Optional API key for OpenViking server. Accepts a plain string, " +
|
|
522
|
-
"${ENV_VAR} interpolation, or a SecretRef object ({source: env/file
|
|
499
|
+
"${ENV_VAR} interpolation, or a SecretRef object ({source: env/file, id}). " +
|
|
523
500
|
"Prefer the SecretRef shapes so the key never sits as plaintext in openclaw.json.",
|
|
524
501
|
},
|
|
525
502
|
headers: {
|
|
@@ -676,7 +653,7 @@ export const memoryOpenVikingConfigSchema = {
|
|
|
676
653
|
enabledTools: {
|
|
677
654
|
label: "Enabled Tools",
|
|
678
655
|
placeholder: "default",
|
|
679
|
-
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.",
|
|
680
657
|
advanced: true,
|
|
681
658
|
},
|
|
682
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,
|
package/dist/text-utils.js
CHANGED
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,
|
package/install-manifest.json
CHANGED
package/openclaw.plugin.json
CHANGED
|
@@ -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",
|
|
@@ -100,7 +98,7 @@
|
|
|
100
98
|
"label": "OpenViking API Key",
|
|
101
99
|
"sensitive": true,
|
|
102
100
|
"placeholder": "${OPENVIKING_API_KEY}",
|
|
103
|
-
"help": "Optional API key for OpenViking server. Accepts a plain string, ${ENV_VAR} interpolation, or a SecretRef object ({source: env/file
|
|
101
|
+
"help": "Optional API key for OpenViking server. Accepts a plain string, ${ENV_VAR} interpolation, or a SecretRef object ({source: env/file, id}). Prefer a SecretRef so the key is never stored as plaintext in openclaw.json."
|
|
104
102
|
},
|
|
105
103
|
"headers": {
|
|
106
104
|
"label": "Headers",
|
|
@@ -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,
|
|
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": {
|
|
@@ -320,18 +318,6 @@
|
|
|
320
318
|
"source": { "type": "string", "const": "file" },
|
|
321
319
|
"id": { "type": "string", "description": "Absolute file path or ~/relative path. Example: /etc/secrets/openviking.key." }
|
|
322
320
|
}
|
|
323
|
-
},
|
|
324
|
-
{
|
|
325
|
-
"type": "object",
|
|
326
|
-
"title": "SecretRef (exec)",
|
|
327
|
-
"description": "Read the API key by shelling out to a secret-manager CLI. Matches the shape used by OpenClaw's core provider configs so 1Password, HashiCorp Vault, gopass, etc. can manage the OpenViking key alongside LLM/TTS/MCP credentials.",
|
|
328
|
-
"additionalProperties": false,
|
|
329
|
-
"required": ["source", "provider", "id"],
|
|
330
|
-
"properties": {
|
|
331
|
-
"source": { "type": "string", "const": "exec" },
|
|
332
|
-
"provider": { "type": "string", "description": "CLI binary name on PATH. Examples: op, vault, gopass." },
|
|
333
|
-
"id": { "type": "string", "description": "Argument passed to the provider CLI to select the specific secret, e.g. 'vault kv get -field=key secret/openviking' in plain-arg form; this implementation passes id as a single arg." }
|
|
334
|
-
}
|
|
335
321
|
}
|
|
336
322
|
]
|
|
337
323
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openviking/openclaw-plugin",
|
|
3
|
-
"version": "2026.8.
|
|
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
|
@@ -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.
|