@openviking/openclaw-plugin 2026.5.26 → 2026.6.17-dev.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-AGENT.md +355 -355
- package/INSTALL-ZH.md +405 -345
- package/INSTALL.md +366 -362
- package/README.md +364 -338
- package/adapters/http-transport.ts +3 -0
- package/adapters/resource-packager.ts +141 -0
- package/auto-recall.ts +518 -257
- package/client.ts +963 -939
- package/commands/setup.ts +1169 -1002
- package/config/feature-gates.json +10 -0
- package/config.ts +819 -476
- package/context-engine.ts +408 -1737
- package/dist/adapters/http-transport.js +1 -0
- package/dist/adapters/resource-packager.js +114 -0
- package/dist/auto-recall.js +228 -32
- package/dist/client.js +125 -161
- package/dist/commands/setup.js +170 -32
- package/dist/config.js +285 -64
- package/dist/context-engine.js +64 -1179
- package/dist/index.js +209 -1470
- package/dist/memory-ranking.js +35 -12
- package/dist/plugin/command-registration.js +5 -0
- package/dist/plugin/openviking-archive-tools.js +210 -0
- package/dist/plugin/openviking-bypass-runtime.js +8 -0
- package/dist/plugin/openviking-client-runtime.js +28 -0
- package/dist/plugin/openviking-command-args.js +146 -0
- package/dist/plugin/openviking-command-definitions.js +206 -0
- package/dist/plugin/openviking-context-engine-ref.js +11 -0
- package/dist/plugin/openviking-context-engine-registration.js +23 -0
- package/dist/plugin/openviking-feature-gates.js +250 -0
- package/dist/plugin/openviking-import-runtime.js +50 -0
- package/dist/plugin/openviking-import-tools.js +86 -0
- package/dist/plugin/openviking-lifecycle-hooks.js +33 -0
- package/dist/plugin/openviking-memory-recall-tools.js +233 -0
- package/dist/plugin/openviking-memory-tools.js +199 -0
- package/dist/plugin/openviking-query-config-command.js +203 -0
- package/dist/plugin/openviking-query-runtime.js +367 -0
- package/dist/plugin/openviking-query-tools.js +91 -0
- package/dist/plugin/openviking-recall-trace-runtime.js +387 -0
- package/dist/plugin/openviking-recall-trace-tools.js +38 -0
- package/dist/plugin/openviking-runtime-state.js +26 -0
- package/dist/plugin/openviking-runtime-utils.js +62 -0
- package/dist/plugin/openviking-services.js +20 -0
- package/dist/plugin/openviking-session-routing-runtime.js +61 -0
- package/dist/plugin/openviking-tool-result-tools.js +268 -0
- package/dist/plugin/recall-trace-routes.js +77 -0
- package/dist/plugin/tool-registration.js +23 -0
- package/dist/process-manager.js +5 -17
- package/dist/query-config.js +336 -0
- package/dist/recall-trace.js +309 -0
- package/dist/registries/recall-resource-types.js +58 -0
- package/dist/routing/identity-routing.js +152 -0
- package/dist/routing/memory-uri.js +7 -0
- package/dist/services/context-lifecycle-service.js +847 -0
- package/dist/services/context-message-adapter.js +340 -0
- package/dist/session-transcript-repair.js +0 -1
- package/dist/text-utils.js +14 -31
- package/dist/token-estimator.js +51 -0
- package/index.ts +408 -1985
- package/install-manifest.json +57 -47
- package/memory-ranking.ts +303 -267
- package/openclaw.plugin.json +497 -335
- package/package.json +86 -76
- package/plugin/command-registration.ts +34 -0
- package/plugin/openviking-archive-tools.ts +301 -0
- package/plugin/openviking-bypass-runtime.ts +26 -0
- package/plugin/openviking-client-runtime.ts +74 -0
- package/plugin/openviking-command-args.ts +187 -0
- package/plugin/openviking-command-definitions.ts +294 -0
- package/plugin/openviking-context-engine-ref.ts +16 -0
- package/plugin/openviking-context-engine-registration.ts +97 -0
- package/plugin/openviking-feature-gates.ts +335 -0
- package/plugin/openviking-import-runtime.ts +105 -0
- package/plugin/openviking-import-tools.ts +133 -0
- package/plugin/openviking-lifecycle-hooks.ts +65 -0
- package/plugin/openviking-memory-recall-tools.ts +368 -0
- package/plugin/openviking-memory-tools.ts +299 -0
- package/plugin/openviking-query-config-command.ts +230 -0
- package/plugin/openviking-query-formatters.ts +108 -0
- package/plugin/openviking-query-runtime.ts +476 -0
- package/plugin/openviking-query-tools.ts +161 -0
- package/plugin/openviking-recall-trace-runtime.ts +482 -0
- package/plugin/openviking-recall-trace-tools.ts +99 -0
- package/plugin/openviking-runtime-state.ts +52 -0
- package/plugin/openviking-runtime-utils.ts +67 -0
- package/plugin/openviking-services.ts +49 -0
- package/plugin/openviking-session-routing-runtime.ts +105 -0
- package/plugin/openviking-tool-result-tools.ts +397 -0
- package/plugin/recall-trace-routes.ts +133 -0
- package/plugin/tool-registration.ts +51 -0
- package/process-manager.ts +41 -45
- package/query-config.ts +400 -0
- package/recall-trace.ts +442 -0
- package/registries/openviking-tools.ts +84 -0
- package/registries/recall-resource-types.ts +74 -0
- package/routing/identity-routing.ts +210 -0
- package/routing/memory-uri.ts +8 -0
- package/runtime-utils.ts +5 -5
- package/services/context-lifecycle-service.ts +1209 -0
- package/services/context-message-adapter.ts +375 -0
- package/services/setup/config-writer.ts +125 -0
- package/services/setup/exit-utils.ts +5 -0
- package/services/setup/package-metadata.ts +56 -0
- package/services/setup/probe-service.ts +143 -0
- package/services/setup/setup-flow.ts +306 -0
- package/services/setup/version-compatibility.ts +41 -0
- package/session-transcript-repair.ts +528 -530
- package/skills/install-openviking-memory/SKILL.md +752 -665
- package/skills/openviking-context-database/SKILL.md +286 -0
- package/text-utils.ts +488 -507
- package/token-estimator.ts +65 -0
- package/tool-call-id.ts +331 -331
package/package.json
CHANGED
|
@@ -1,76 +1,86 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@openviking/openclaw-plugin",
|
|
3
|
-
"version": "2026.
|
|
4
|
-
"displayName": "OpenViking",
|
|
5
|
-
"description": "OpenClaw context-engine plugin — OpenViking AI memory, long-term memory, knowledge base, semantic search, RAG, context engine. 长期记忆 · 知识库 · 语义检索 · 上下文引擎",
|
|
6
|
-
"type": "module",
|
|
7
|
-
"keywords": [
|
|
8
|
-
"openclaw",
|
|
9
|
-
"openviking",
|
|
10
|
-
"plugin",
|
|
11
|
-
"context-engine",
|
|
12
|
-
"memory",
|
|
13
|
-
"remote-memory",
|
|
14
|
-
"RAG",
|
|
15
|
-
"semantic-retrieval",
|
|
16
|
-
"context-database",
|
|
17
|
-
"long-term-memory",
|
|
18
|
-
"auto-recall",
|
|
19
|
-
"auto-capture"
|
|
20
|
-
],
|
|
21
|
-
"files": [
|
|
22
|
-
"dist/",
|
|
23
|
-
"*.ts",
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
"
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
"
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
"
|
|
57
|
-
|
|
58
|
-
"
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
"
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
"
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@openviking/openclaw-plugin",
|
|
3
|
+
"version": "2026.6.17-dev.1",
|
|
4
|
+
"displayName": "OpenViking",
|
|
5
|
+
"description": "OpenClaw context-engine plugin — OpenViking AI memory, long-term memory, knowledge base, semantic search, RAG, context engine. 长期记忆 · 知识库 · 语义检索 · 上下文引擎",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"openclaw",
|
|
9
|
+
"openviking",
|
|
10
|
+
"plugin",
|
|
11
|
+
"context-engine",
|
|
12
|
+
"memory",
|
|
13
|
+
"remote-memory",
|
|
14
|
+
"RAG",
|
|
15
|
+
"semantic-retrieval",
|
|
16
|
+
"context-database",
|
|
17
|
+
"long-term-memory",
|
|
18
|
+
"auto-recall",
|
|
19
|
+
"auto-capture"
|
|
20
|
+
],
|
|
21
|
+
"files": [
|
|
22
|
+
"dist/",
|
|
23
|
+
"*.ts",
|
|
24
|
+
"adapters/",
|
|
25
|
+
"commands/setup.ts",
|
|
26
|
+
"config/feature-gates.json",
|
|
27
|
+
"registries/",
|
|
28
|
+
"routing/",
|
|
29
|
+
"plugin/",
|
|
30
|
+
"services/",
|
|
31
|
+
"!vitest.config.ts",
|
|
32
|
+
"install-manifest.json",
|
|
33
|
+
"openclaw.plugin.json",
|
|
34
|
+
"package.json",
|
|
35
|
+
"README.md",
|
|
36
|
+
"INSTALL.md",
|
|
37
|
+
"INSTALL-ZH.md",
|
|
38
|
+
"INSTALL-AGENT.md",
|
|
39
|
+
"images/",
|
|
40
|
+
"skills/"
|
|
41
|
+
],
|
|
42
|
+
"scripts": {
|
|
43
|
+
"build": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\" && tsc -p tsconfig.build.json",
|
|
44
|
+
"prepack": "npm run build",
|
|
45
|
+
"test": "vitest run",
|
|
46
|
+
"typecheck": "tsc -p tsconfig.json",
|
|
47
|
+
"test:watch": "vitest"
|
|
48
|
+
},
|
|
49
|
+
"engines": {
|
|
50
|
+
"openclaw": ">=2026.4.8"
|
|
51
|
+
},
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"@sinclair/typebox": "0.34.48",
|
|
54
|
+
"fflate": "^0.8.2"
|
|
55
|
+
},
|
|
56
|
+
"repository": {
|
|
57
|
+
"type": "git",
|
|
58
|
+
"url": "https://github.com/volcengine/OpenViking"
|
|
59
|
+
},
|
|
60
|
+
"overrides": {
|
|
61
|
+
"axios": "^1.16.1"
|
|
62
|
+
},
|
|
63
|
+
"homepage": "https://github.com/volcengine/OpenViking/tree/main/examples/openclaw-plugin",
|
|
64
|
+
"license": "MIT",
|
|
65
|
+
"author": "OpenViking Contributors",
|
|
66
|
+
"openclaw": {
|
|
67
|
+
"extensions": [
|
|
68
|
+
"./dist/index.js"
|
|
69
|
+
],
|
|
70
|
+
"setupEntry": "./dist/commands/setup.js",
|
|
71
|
+
"compat": {
|
|
72
|
+
"pluginApi": ">=2026.4.8",
|
|
73
|
+
"minGatewayVersion": "2026.4.8"
|
|
74
|
+
},
|
|
75
|
+
"build": {
|
|
76
|
+
"openclawVersion": "2026.4.8",
|
|
77
|
+
"pluginSdkVersion": "2026.4.8"
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
"devDependencies": {
|
|
81
|
+
"@types/node": "^25.3.5",
|
|
82
|
+
"@volcengine/tos-sdk": "^2.9.1",
|
|
83
|
+
"typescript": "^5.8.0",
|
|
84
|
+
"vitest": "^4.1.0"
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export type PluginCommandContext = {
|
|
2
|
+
args?: string;
|
|
3
|
+
commandBody?: string;
|
|
4
|
+
sessionKey?: string;
|
|
5
|
+
sessionId?: string;
|
|
6
|
+
agentId?: string;
|
|
7
|
+
ovSessionId?: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export type CommandResult = {
|
|
11
|
+
text: string;
|
|
12
|
+
details?: Record<string, unknown>;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export type CommandDefinition = {
|
|
16
|
+
name: string;
|
|
17
|
+
description: string;
|
|
18
|
+
acceptsArgs?: boolean;
|
|
19
|
+
requireAuth?: boolean;
|
|
20
|
+
handler: (ctx: PluginCommandContext) => CommandResult | Promise<CommandResult>;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export type OpenVikingCommandRegistrationApi = {
|
|
24
|
+
registerCommand?: (command: CommandDefinition) => void;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export function registerOpenVikingCommands(
|
|
28
|
+
api: OpenVikingCommandRegistrationApi,
|
|
29
|
+
commands: CommandDefinition[],
|
|
30
|
+
): void {
|
|
31
|
+
for (const command of commands) {
|
|
32
|
+
api.registerCommand?.(command);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import { Type } from "@sinclair/typebox";
|
|
2
|
+
import type { OVMessage } from "../client.js";
|
|
3
|
+
import type { RecallTraceEntry, RecallTraceResult } from "../recall-trace.js";
|
|
4
|
+
|
|
5
|
+
export type OpenVikingArchiveToolContext = {
|
|
6
|
+
sessionKey?: string;
|
|
7
|
+
sessionId?: string;
|
|
8
|
+
agentId?: string;
|
|
9
|
+
senderId?: string;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export type OpenVikingArchiveSession = {
|
|
13
|
+
sessionId?: string;
|
|
14
|
+
sessionKey?: string;
|
|
15
|
+
ovSessionId?: string;
|
|
16
|
+
agentId: string;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
type OpenVikingArchiveMatch = {
|
|
20
|
+
uri: string;
|
|
21
|
+
line: number;
|
|
22
|
+
content: string;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export type OpenVikingArchiveClient = {
|
|
26
|
+
grepSessionArchives: (
|
|
27
|
+
sessionId: string,
|
|
28
|
+
pattern: string,
|
|
29
|
+
options: { archiveId?: string; caseInsensitive: boolean; agentId?: string },
|
|
30
|
+
) => Promise<{
|
|
31
|
+
count?: number;
|
|
32
|
+
matches?: OpenVikingArchiveMatch[];
|
|
33
|
+
}>;
|
|
34
|
+
getSessionArchive: (
|
|
35
|
+
sessionId: string,
|
|
36
|
+
archiveId: string,
|
|
37
|
+
agentId?: string,
|
|
38
|
+
) => Promise<{
|
|
39
|
+
archive_id: string;
|
|
40
|
+
abstract?: string;
|
|
41
|
+
messages: OVMessage[];
|
|
42
|
+
}>;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export type OpenVikingArchiveToolsDeps = {
|
|
46
|
+
registerTool: (toolOrFactory: unknown, opts: { name: string }) => void;
|
|
47
|
+
getClient: () => Promise<OpenVikingArchiveClient>;
|
|
48
|
+
rememberSessionAgentId: (ctx: OpenVikingArchiveToolContext) => void;
|
|
49
|
+
toOvSessionId: (sessionId?: string, sessionKey?: string) => string;
|
|
50
|
+
resolveAgentId: (sessionId?: string, sessionKey?: string, ovSessionId?: string) => string;
|
|
51
|
+
resolvePluginSessionRouting: (ctx?: OpenVikingArchiveToolContext) => OpenVikingArchiveSession;
|
|
52
|
+
isBypassedSession: (ctx?: OpenVikingArchiveToolContext) => boolean;
|
|
53
|
+
makeBypassedToolResult: (toolName: string) => unknown;
|
|
54
|
+
formatMessage: (message: OVMessage) => string;
|
|
55
|
+
traceRecorder?: { recordAndFlush: (trace: RecallTraceEntry) => Promise<unknown> | unknown };
|
|
56
|
+
traceRecallMaxResultsPerSearch: number;
|
|
57
|
+
traceRecallPreviewChars: number;
|
|
58
|
+
createTraceId: (source: string) => string;
|
|
59
|
+
logger?: {
|
|
60
|
+
info?: (message: string) => void;
|
|
61
|
+
warn?: (message: string) => void;
|
|
62
|
+
error?: (message: string) => void;
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
function previewText(value: unknown, maxChars: number): string | undefined {
|
|
67
|
+
const text = typeof value === "string" ? value.replace(/\s+/g, " ").trim() : "";
|
|
68
|
+
if (!text) {
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
return text.length <= maxChars ? text : `${text.slice(0, Math.max(0, maxChars - 1))}…`;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function registerOpenVikingArchiveTools(deps: OpenVikingArchiveToolsDeps): void {
|
|
75
|
+
deps.registerTool(
|
|
76
|
+
(ctx: OpenVikingArchiveToolContext) => ({
|
|
77
|
+
name: "ov_archive_search",
|
|
78
|
+
label: "Archive Search (OpenViking)",
|
|
79
|
+
description:
|
|
80
|
+
"Keyword-grep across all archived original conversation messages of the current session. " +
|
|
81
|
+
"Use this whenever the [Session History Summary] does not contain the specific detail " +
|
|
82
|
+
"the user is asking about. Extract 2-3 concrete entity words from the question " +
|
|
83
|
+
"(names, places, objects, dates) and search each separately. " +
|
|
84
|
+
"Only conclude information is unavailable after trying at least 2 different keyword variations.",
|
|
85
|
+
parameters: Type.Object({
|
|
86
|
+
query: Type.String({
|
|
87
|
+
description:
|
|
88
|
+
"A single keyword or short phrase to grep. Use concrete nouns, names, dates, " +
|
|
89
|
+
"or distinctive phrases. Case-insensitive. Prefer entity words over full sentences.",
|
|
90
|
+
}),
|
|
91
|
+
archiveId: Type.Optional(
|
|
92
|
+
Type.String({
|
|
93
|
+
description: 'Optional: limit search to one archive (e.g. "archive_005")',
|
|
94
|
+
}),
|
|
95
|
+
),
|
|
96
|
+
}),
|
|
97
|
+
async execute(_toolCallId: string, params: Record<string, unknown>) {
|
|
98
|
+
if (deps.isBypassedSession(ctx)) {
|
|
99
|
+
return deps.makeBypassedToolResult("ov_archive_search");
|
|
100
|
+
}
|
|
101
|
+
deps.rememberSessionAgentId(ctx);
|
|
102
|
+
const sessionId = ctx.sessionId ?? "";
|
|
103
|
+
const sessionKey = ctx.sessionKey ?? "";
|
|
104
|
+
if (!sessionId && !sessionKey) {
|
|
105
|
+
return {
|
|
106
|
+
content: [{ type: "text", text: "Error: no active session." }],
|
|
107
|
+
details: { error: "no_session" },
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
const ovSessionId = deps.toOvSessionId(ctx.sessionId, ctx.sessionKey);
|
|
111
|
+
const query = String((params as { query?: string }).query ?? "").trim();
|
|
112
|
+
const archiveId = (params as { archiveId?: string }).archiveId;
|
|
113
|
+
|
|
114
|
+
if (!query) {
|
|
115
|
+
return {
|
|
116
|
+
content: [{ type: "text", text: "Error: query is required." }],
|
|
117
|
+
details: { error: "missing_param", param: "query" },
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const escapedQuery = query.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
122
|
+
deps.logger?.info?.(`openviking: ov_archive_search query="${query}" escaped="${escapedQuery}" archive=${archiveId ?? "all"} session=${ovSessionId}`);
|
|
123
|
+
|
|
124
|
+
try {
|
|
125
|
+
const client = await deps.getClient();
|
|
126
|
+
const agentId = deps.resolveAgentId(ctx.sessionId, ctx.sessionKey);
|
|
127
|
+
const started = Date.now();
|
|
128
|
+
const result = await client.grepSessionArchives(ovSessionId, escapedQuery, {
|
|
129
|
+
archiveId,
|
|
130
|
+
caseInsensitive: true,
|
|
131
|
+
agentId,
|
|
132
|
+
});
|
|
133
|
+
const traceResults: RecallTraceResult[] = (result.matches ?? []).slice(0, deps.traceRecallMaxResultsPerSearch).map((match) => ({
|
|
134
|
+
uri: match.uri,
|
|
135
|
+
resourceType: "archive",
|
|
136
|
+
abstractPreview: previewText(match.content, deps.traceRecallPreviewChars),
|
|
137
|
+
resultType: "archive_match",
|
|
138
|
+
}));
|
|
139
|
+
|
|
140
|
+
const recordArchiveTrace = async (displayed: OpenVikingArchiveMatch[]) => {
|
|
141
|
+
await deps.traceRecorder?.recordAndFlush({
|
|
142
|
+
schemaVersion: "1.0",
|
|
143
|
+
traceId: deps.createTraceId("ov_archive_search"),
|
|
144
|
+
ts: Date.now(),
|
|
145
|
+
sessionId: ctx.sessionId,
|
|
146
|
+
sessionKey: ctx.sessionKey,
|
|
147
|
+
ovSessionId,
|
|
148
|
+
agentId,
|
|
149
|
+
source: "ov_archive_search",
|
|
150
|
+
operationType: "archive_grep",
|
|
151
|
+
resourceTypes: ["session"],
|
|
152
|
+
trigger: { query, derivedKeywords: [query] },
|
|
153
|
+
searches: [{
|
|
154
|
+
resourceType: "archive",
|
|
155
|
+
targetUriResolved: archiveId ? `viking://session/${ovSessionId}/history/${archiveId}` : `viking://session/${ovSessionId}/history`,
|
|
156
|
+
limit: deps.traceRecallMaxResultsPerSearch,
|
|
157
|
+
durationMs: Date.now() - started,
|
|
158
|
+
total: result.matches?.length ?? result.count ?? 0,
|
|
159
|
+
results: traceResults,
|
|
160
|
+
archiveId,
|
|
161
|
+
caseInsensitive: true,
|
|
162
|
+
}],
|
|
163
|
+
selected: displayed.map((match) => ({
|
|
164
|
+
uri: match.uri,
|
|
165
|
+
resourceType: "archive",
|
|
166
|
+
line: match.line,
|
|
167
|
+
abstractPreview: previewText(match.content, deps.traceRecallPreviewChars),
|
|
168
|
+
displayed: true,
|
|
169
|
+
})),
|
|
170
|
+
stats: {
|
|
171
|
+
candidateCount: result.matches?.length ?? result.count ?? 0,
|
|
172
|
+
selectedCount: displayed.length,
|
|
173
|
+
injectedCount: 0,
|
|
174
|
+
},
|
|
175
|
+
});
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
if (!result.matches || result.matches.length === 0) {
|
|
179
|
+
await recordArchiveTrace([]);
|
|
180
|
+
return {
|
|
181
|
+
content: [{
|
|
182
|
+
type: "text",
|
|
183
|
+
text: `No matches found for "${query}". Try a different keyword — ` +
|
|
184
|
+
"the original conversation may use different wording than the question. " +
|
|
185
|
+
"Try synonyms, related terms, or shorter fragments.",
|
|
186
|
+
}],
|
|
187
|
+
details: { query, matchCount: 0 },
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const MAX_MATCHES = 12;
|
|
192
|
+
const MAX_LINE_LEN = 1500;
|
|
193
|
+
const shown = result.matches.slice(0, MAX_MATCHES);
|
|
194
|
+
await recordArchiveTrace(shown);
|
|
195
|
+
const blocks = shown.map((m, i) => {
|
|
196
|
+
const archiveTag = m.uri.match(/archive_\d+/)?.[0] ?? "unknown";
|
|
197
|
+
const truncated = m.content.length > MAX_LINE_LEN
|
|
198
|
+
? m.content.slice(0, MAX_LINE_LEN) + "…(truncated)"
|
|
199
|
+
: m.content;
|
|
200
|
+
return `## Match ${i + 1}: ${archiveTag} (line ${m.line})\n${truncated}`;
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
const header = `Found ${result.matches.length} match(es) for "${query}"` +
|
|
204
|
+
(result.matches.length > MAX_MATCHES ? ` (showing first ${MAX_MATCHES})` : "") + ":";
|
|
205
|
+
|
|
206
|
+
return {
|
|
207
|
+
content: [{ type: "text", text: header + "\n\n" + blocks.join("\n\n") }],
|
|
208
|
+
details: { query, matchCount: result.matches.length },
|
|
209
|
+
};
|
|
210
|
+
} catch (err: unknown) {
|
|
211
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
212
|
+
deps.logger?.error?.(`openviking: ov_archive_search error: ${msg}`);
|
|
213
|
+
return {
|
|
214
|
+
content: [{ type: "text", text: `Archive search failed: ${msg}` }],
|
|
215
|
+
details: { error: msg },
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
},
|
|
219
|
+
}),
|
|
220
|
+
{ name: "ov_archive_search" },
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
deps.registerTool((ctx: OpenVikingArchiveToolContext) => ({
|
|
224
|
+
name: "ov_archive_expand",
|
|
225
|
+
label: "Archive Expand (OpenViking)",
|
|
226
|
+
description:
|
|
227
|
+
"Retrieve original messages from a compressed session archive. " +
|
|
228
|
+
"Use when a session summary lacks specific details " +
|
|
229
|
+
"such as exact commands, file paths, code snippets, or config values. " +
|
|
230
|
+
"Check [Archive Index] to find the right archive ID.",
|
|
231
|
+
parameters: Type.Object({
|
|
232
|
+
archiveId: Type.String({
|
|
233
|
+
description:
|
|
234
|
+
'Archive ID from [Archive Index] (e.g. "archive_002")',
|
|
235
|
+
}),
|
|
236
|
+
}),
|
|
237
|
+
async execute(_toolCallId: string, params: Record<string, unknown>) {
|
|
238
|
+
if (deps.isBypassedSession(ctx)) {
|
|
239
|
+
return deps.makeBypassedToolResult("ov_archive_expand");
|
|
240
|
+
}
|
|
241
|
+
const session = deps.resolvePluginSessionRouting(ctx);
|
|
242
|
+
const archiveId = String((params as { archiveId?: string }).archiveId ?? "").trim();
|
|
243
|
+
const sessionId = session.sessionId ?? "";
|
|
244
|
+
deps.logger?.info?.(`openviking: ov_archive_expand invoked (archiveId=${archiveId || "(empty)"}, sessionId=${sessionId || "(empty)"})`);
|
|
245
|
+
|
|
246
|
+
if (!archiveId) {
|
|
247
|
+
deps.logger?.warn?.("openviking: ov_archive_expand missing archiveId");
|
|
248
|
+
return {
|
|
249
|
+
content: [{ type: "text", text: "Error: archiveId is required." }],
|
|
250
|
+
details: { error: "missing_param", param: "archiveId" },
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (!session.ovSessionId) {
|
|
255
|
+
return {
|
|
256
|
+
content: [{ type: "text", text: "Error: no active session." }],
|
|
257
|
+
details: { error: "no_session" },
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
try {
|
|
262
|
+
const client = await deps.getClient();
|
|
263
|
+
const detail = await client.getSessionArchive(
|
|
264
|
+
session.ovSessionId,
|
|
265
|
+
archiveId,
|
|
266
|
+
session.agentId,
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
const header = [
|
|
270
|
+
`## ${detail.archive_id}`,
|
|
271
|
+
detail.abstract ? `**Summary**: ${detail.abstract}` : "",
|
|
272
|
+
`**Messages**: ${detail.messages.length}`,
|
|
273
|
+
"",
|
|
274
|
+
].filter(Boolean).join("\n");
|
|
275
|
+
|
|
276
|
+
const body = detail.messages
|
|
277
|
+
.map((message) => deps.formatMessage(message))
|
|
278
|
+
.join("\n\n");
|
|
279
|
+
|
|
280
|
+
deps.logger?.info?.(`openviking: ov_archive_expand expanded ${detail.archive_id}, messages=${detail.messages.length}, chars=${body.length}, sessionId=${sessionId}`);
|
|
281
|
+
return {
|
|
282
|
+
content: [{ type: "text", text: `${header}\n${body}` }],
|
|
283
|
+
details: {
|
|
284
|
+
action: "expanded",
|
|
285
|
+
archiveId: detail.archive_id,
|
|
286
|
+
messageCount: detail.messages.length,
|
|
287
|
+
sessionId,
|
|
288
|
+
ovSessionId: session.ovSessionId,
|
|
289
|
+
},
|
|
290
|
+
};
|
|
291
|
+
} catch (err) {
|
|
292
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
293
|
+
deps.logger?.warn?.(`openviking: ov_archive_expand failed (archiveId=${archiveId}, sessionId=${sessionId}): ${msg}`);
|
|
294
|
+
return {
|
|
295
|
+
content: [{ type: "text", text: `Failed to expand ${archiveId}: ${msg}` }],
|
|
296
|
+
details: { error: msg, archiveId, sessionId, ovSessionId: session.ovSessionId },
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
},
|
|
300
|
+
}), { name: "ov_archive_expand" });
|
|
301
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import {
|
|
2
|
+
compileSessionPatterns,
|
|
3
|
+
shouldBypassSession,
|
|
4
|
+
} from "../text-utils.js";
|
|
5
|
+
|
|
6
|
+
type BypassRuntimeConfig = {
|
|
7
|
+
bypassSessionPatterns: string[];
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
type SessionBypassContext = {
|
|
11
|
+
sessionId?: string;
|
|
12
|
+
sessionKey?: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export function createOpenVikingBypassRuntime<TConfig extends BypassRuntimeConfig>(options: {
|
|
16
|
+
cfg: TConfig;
|
|
17
|
+
}) {
|
|
18
|
+
const bypassSessionPatterns = compileSessionPatterns(options.cfg.bypassSessionPatterns);
|
|
19
|
+
|
|
20
|
+
const isBypassedSession = (ctx?: SessionBypassContext): boolean =>
|
|
21
|
+
shouldBypassSession(ctx ?? {}, bypassSessionPatterns);
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
isBypassedSession,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { OpenVikingClient } from "../client.js";
|
|
2
|
+
import type { HttpTransport } from "../adapters/http-transport.js";
|
|
3
|
+
|
|
4
|
+
type Logger = {
|
|
5
|
+
info: (message: string) => void;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
type ClientRuntimeConfig = {
|
|
9
|
+
baseUrl: string;
|
|
10
|
+
apiKey: string;
|
|
11
|
+
peer_role: "none" | "assistant" | "person";
|
|
12
|
+
peer_prefix: string;
|
|
13
|
+
timeoutMs: number;
|
|
14
|
+
accountId?: string;
|
|
15
|
+
userId?: string;
|
|
16
|
+
logFindRequests: boolean;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export function createOpenVikingClientRuntime(options: {
|
|
20
|
+
cfg: ClientRuntimeConfig;
|
|
21
|
+
rawPeerPrefix: unknown;
|
|
22
|
+
logger: Logger;
|
|
23
|
+
transport?: HttpTransport;
|
|
24
|
+
}) {
|
|
25
|
+
const { cfg, logger } = options;
|
|
26
|
+
|
|
27
|
+
if (cfg.logFindRequests) {
|
|
28
|
+
logger.info(
|
|
29
|
+
"openviking: routing debug logging enabled (config logFindRequests, or env OPENVIKING_LOG_ROUTING=1 / OPENVIKING_DEBUG=1)",
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const verboseRoutingInfo = (message: string) => {
|
|
34
|
+
if (cfg.logFindRequests) {
|
|
35
|
+
logger.info(message);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
verboseRoutingInfo(
|
|
40
|
+
`openviking: loaded plugin config peer_role="${cfg.peer_role}" peer_prefix="${cfg.peer_prefix}" ` +
|
|
41
|
+
`(raw peer_prefix=${JSON.stringify(options.rawPeerPrefix ?? "(missing)")}; ` +
|
|
42
|
+
`${
|
|
43
|
+
cfg.peer_prefix
|
|
44
|
+
? 'non-empty → assistant peer_id is <peer_prefix>_<ctx.agentId> when peer_role="assistant", or <peer_prefix>_main when ctx.agentId is unknown'
|
|
45
|
+
: 'empty → assistant peer_id follows OpenClaw ctx.agentId when peer_role="assistant", or "main" when ctx.agentId is unknown'
|
|
46
|
+
})`,
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
const routingDebugLog = cfg.logFindRequests
|
|
50
|
+
? (msg: string) => {
|
|
51
|
+
logger.info(msg);
|
|
52
|
+
}
|
|
53
|
+
: undefined;
|
|
54
|
+
|
|
55
|
+
const clientPromise = Promise.resolve(
|
|
56
|
+
new OpenVikingClient(
|
|
57
|
+
cfg.baseUrl,
|
|
58
|
+
cfg.apiKey,
|
|
59
|
+
cfg.peer_prefix,
|
|
60
|
+
cfg.timeoutMs,
|
|
61
|
+
cfg.accountId,
|
|
62
|
+
cfg.userId,
|
|
63
|
+
routingDebugLog,
|
|
64
|
+
{ transport: options.transport },
|
|
65
|
+
),
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
const getClient = (): Promise<OpenVikingClient> => clientPromise;
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
getClient,
|
|
72
|
+
verboseRoutingInfo,
|
|
73
|
+
};
|
|
74
|
+
}
|