@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
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { RecallResourceType } from "../registries/recall-resource-types.js";
|
|
2
|
+
|
|
3
|
+
export function previewText(value: unknown, maxChars: number): string | undefined {
|
|
4
|
+
const text = typeof value === "string" ? value.replace(/\s+/g, " ").trim() : "";
|
|
5
|
+
if (!text) {
|
|
6
|
+
return undefined;
|
|
7
|
+
}
|
|
8
|
+
return text.length <= maxChars ? text : `${text.slice(0, Math.max(0, maxChars - 1))}…`;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function inferRecallResourceType(uri: string): RecallResourceType | undefined {
|
|
12
|
+
if (uri.startsWith("viking://resources")) return "resource";
|
|
13
|
+
if (uri.startsWith("viking://user/skills") || uri.startsWith("viking://skills")) return "agent";
|
|
14
|
+
if (uri.startsWith("viking://user/")) return "user";
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function createTraceId(source: string): string {
|
|
19
|
+
return `${source}-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function createMemoryStoreTempSessionId(): string {
|
|
23
|
+
return `memory-store-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function boundTraceQuery(query: string, maxChars: number): { query: string; queryTruncated?: boolean } {
|
|
27
|
+
if (query.length <= maxChars) {
|
|
28
|
+
return { query };
|
|
29
|
+
}
|
|
30
|
+
return { query: query.slice(0, maxChars), queryTruncated: true };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function extractToolSenderId(ctx: unknown): string | undefined {
|
|
34
|
+
if (!ctx || typeof ctx !== "object") {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
const toolCtx = ctx as Record<string, unknown>;
|
|
38
|
+
if (typeof toolCtx.requesterSenderId === "string") {
|
|
39
|
+
const trimmed = toolCtx.requesterSenderId.trim();
|
|
40
|
+
if (trimmed) {
|
|
41
|
+
return trimmed;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (typeof toolCtx.senderId === "string") {
|
|
45
|
+
const trimmed = toolCtx.senderId.trim();
|
|
46
|
+
if (trimmed) {
|
|
47
|
+
return trimmed;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function makeBypassedToolResult(toolName: string) {
|
|
54
|
+
return {
|
|
55
|
+
content: [
|
|
56
|
+
{
|
|
57
|
+
type: "text" as const,
|
|
58
|
+
text: `OpenViking is bypassed for this session by bypassSessionPatterns; ${toolName} was skipped.`,
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
details: {
|
|
62
|
+
action: "bypassed",
|
|
63
|
+
reason: "session_bypassed",
|
|
64
|
+
toolName,
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export type OpenVikingServiceLogger = {
|
|
2
|
+
info: (message: string) => void;
|
|
3
|
+
warn?: (message: string) => void;
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
export type OpenVikingServiceConfig = {
|
|
7
|
+
baseUrl: string;
|
|
8
|
+
targetUri: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type OpenVikingServiceClient = {
|
|
12
|
+
healthCheck: () => Promise<unknown>;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export type OpenVikingServiceOptions = {
|
|
16
|
+
cfg: OpenVikingServiceConfig;
|
|
17
|
+
getClient: () => Promise<OpenVikingServiceClient>;
|
|
18
|
+
logger: OpenVikingServiceLogger;
|
|
19
|
+
recallTraceHttpRoutesRegistered: boolean;
|
|
20
|
+
registerRecallTraceRoutes: (ctx?: unknown) => boolean;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export function createOpenVikingService({
|
|
24
|
+
cfg,
|
|
25
|
+
getClient,
|
|
26
|
+
logger,
|
|
27
|
+
recallTraceHttpRoutesRegistered,
|
|
28
|
+
registerRecallTraceRoutes,
|
|
29
|
+
}: OpenVikingServiceOptions) {
|
|
30
|
+
return {
|
|
31
|
+
id: "openviking",
|
|
32
|
+
start: async (ctx?: unknown) => {
|
|
33
|
+
const runtimeRouteRegistered = registerRecallTraceRoutes(ctx);
|
|
34
|
+
const routeRegistered = recallTraceHttpRoutesRegistered || runtimeRouteRegistered;
|
|
35
|
+
await (await getClient()).healthCheck().catch(() => {});
|
|
36
|
+
logger.info(
|
|
37
|
+
`openviking: initialized (url: ${cfg.baseUrl}, targetUri: ${cfg.targetUri}, search: hybrid endpoint)`,
|
|
38
|
+
);
|
|
39
|
+
if (routeRegistered) {
|
|
40
|
+
logger.info("openviking: registered recall trace Gateway routes");
|
|
41
|
+
} else {
|
|
42
|
+
logger.warn?.("openviking: recall trace Gateway route adapter unavailable; use ov_recall_trace tool or /ov-recall-trace command");
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
stop: () => {
|
|
46
|
+
logger.info("openviking: stopped");
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import type { QueryConfigContext } from "../query-config.js";
|
|
2
|
+
import {
|
|
3
|
+
createSessionAgentResolver,
|
|
4
|
+
openClawSessionToOvStorageId,
|
|
5
|
+
} from "../routing/identity-routing.js";
|
|
6
|
+
|
|
7
|
+
type Logger = {
|
|
8
|
+
info: (message: string) => void;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type SessionAgentLookup = {
|
|
12
|
+
agentId?: string;
|
|
13
|
+
sessionId?: string;
|
|
14
|
+
sessionKey?: string;
|
|
15
|
+
ovSessionId?: string;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export type PluginSessionRouting = {
|
|
19
|
+
sessionId?: string;
|
|
20
|
+
sessionKey?: string;
|
|
21
|
+
ovSessionId?: string;
|
|
22
|
+
agentId: string;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export function createOpenVikingSessionRoutingRuntime(options: {
|
|
26
|
+
peerPrefix: string;
|
|
27
|
+
logFindRequests: boolean;
|
|
28
|
+
logger: Logger;
|
|
29
|
+
}) {
|
|
30
|
+
const sessionAgentResolver = createSessionAgentResolver(options.peerPrefix);
|
|
31
|
+
|
|
32
|
+
const rememberSessionAgentId = (ctx: SessionAgentLookup) => {
|
|
33
|
+
sessionAgentResolver.remember(ctx);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const resolveAgentId = (
|
|
37
|
+
sessionId?: string,
|
|
38
|
+
sessionKey?: string,
|
|
39
|
+
ovSessionId?: string,
|
|
40
|
+
): string => {
|
|
41
|
+
const sid = typeof sessionId === "string" ? sessionId.trim() : "";
|
|
42
|
+
const sk = typeof sessionKey === "string" ? sessionKey.trim() : "";
|
|
43
|
+
const ovSid = typeof ovSessionId === "string" ? ovSessionId.trim() : "";
|
|
44
|
+
const result = sessionAgentResolver.resolve(sid, sk, ovSid);
|
|
45
|
+
if (options.logFindRequests) {
|
|
46
|
+
options.logger.info(
|
|
47
|
+
`openviking: resolveAgentId ${JSON.stringify({
|
|
48
|
+
sessionId: sid || "(empty)",
|
|
49
|
+
sessionKey: sk || "(empty)",
|
|
50
|
+
ovSessionId: ovSid || "(empty)",
|
|
51
|
+
parsedConfigPeerPrefix: options.peerPrefix,
|
|
52
|
+
mappedResolvedAgentId: result.mappedResolvedAgentId,
|
|
53
|
+
resolvedBeforeSanitize: result.resolvedBeforeSanitize,
|
|
54
|
+
resolved: result.resolved,
|
|
55
|
+
branch: result.branch,
|
|
56
|
+
aliases: result.aliases,
|
|
57
|
+
fromExplicitBinding: result.fromExplicitBinding,
|
|
58
|
+
})}`,
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
return result.resolved;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const resolvePluginSessionRouting = (ctx?: SessionAgentLookup): PluginSessionRouting => {
|
|
65
|
+
const sessionId = typeof ctx?.sessionId === "string" ? ctx.sessionId.trim() : "";
|
|
66
|
+
const sessionKey = typeof ctx?.sessionKey === "string" ? ctx.sessionKey.trim() : "";
|
|
67
|
+
let ovSessionId = typeof ctx?.ovSessionId === "string" ? ctx.ovSessionId.trim() : "";
|
|
68
|
+
|
|
69
|
+
if (!ovSessionId && (sessionId || sessionKey)) {
|
|
70
|
+
ovSessionId = openClawSessionToOvStorageId(
|
|
71
|
+
sessionId || undefined,
|
|
72
|
+
sessionKey || undefined,
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const session = {
|
|
77
|
+
agentId: ctx?.agentId,
|
|
78
|
+
sessionId: sessionId || undefined,
|
|
79
|
+
sessionKey: sessionKey || undefined,
|
|
80
|
+
ovSessionId: ovSessionId || undefined,
|
|
81
|
+
};
|
|
82
|
+
rememberSessionAgentId(session);
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
sessionId: session.sessionId,
|
|
86
|
+
sessionKey: session.sessionKey,
|
|
87
|
+
ovSessionId: session.ovSessionId,
|
|
88
|
+
agentId: resolveAgentId(session.sessionId, session.sessionKey, session.ovSessionId),
|
|
89
|
+
};
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const toQueryConfigContext = (session: PluginSessionRouting): QueryConfigContext => ({
|
|
93
|
+
peerId: session.agentId,
|
|
94
|
+
sessionId: session.sessionId,
|
|
95
|
+
sessionKey: session.sessionKey,
|
|
96
|
+
ovSessionId: session.ovSessionId,
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
return {
|
|
100
|
+
rememberSessionAgentId,
|
|
101
|
+
resolveAgentId,
|
|
102
|
+
resolvePluginSessionRouting,
|
|
103
|
+
toQueryConfigContext,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
import { Type } from "@sinclair/typebox";
|
|
2
|
+
|
|
3
|
+
export type OpenVikingToolResultToolContext = {
|
|
4
|
+
sessionKey?: string;
|
|
5
|
+
sessionId?: string;
|
|
6
|
+
agentId?: string;
|
|
7
|
+
senderId?: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export type OpenVikingToolResultSession = {
|
|
11
|
+
sessionId?: string;
|
|
12
|
+
sessionKey?: string;
|
|
13
|
+
ovSessionId?: string;
|
|
14
|
+
agentId: string;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type OpenVikingToolResultToolDefinition = {
|
|
18
|
+
name: string;
|
|
19
|
+
label: string;
|
|
20
|
+
description: string;
|
|
21
|
+
parameters: unknown;
|
|
22
|
+
execute: (_toolCallId: string, params: Record<string, unknown>) => Promise<unknown>;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export type OpenVikingToolResultClient = {
|
|
26
|
+
readToolResult: (
|
|
27
|
+
sessionId: string,
|
|
28
|
+
toolResultId: string,
|
|
29
|
+
options: { offset: number; limit: number; includeMetadata: boolean },
|
|
30
|
+
agentId?: string,
|
|
31
|
+
) => Promise<{
|
|
32
|
+
content: string;
|
|
33
|
+
offset: number;
|
|
34
|
+
limit: number;
|
|
35
|
+
total_chars: number;
|
|
36
|
+
has_more: boolean;
|
|
37
|
+
tool_result_id: string;
|
|
38
|
+
metadata?: unknown;
|
|
39
|
+
}>;
|
|
40
|
+
searchToolResult: (
|
|
41
|
+
sessionId: string,
|
|
42
|
+
toolResultId: string,
|
|
43
|
+
query: string,
|
|
44
|
+
options: { limit: number; contextChars: number },
|
|
45
|
+
agentId?: string,
|
|
46
|
+
) => Promise<{
|
|
47
|
+
tool_result_id: string;
|
|
48
|
+
matches?: Array<{ offset: number; snippet: string }>;
|
|
49
|
+
}>;
|
|
50
|
+
listToolResults: (
|
|
51
|
+
sessionId: string,
|
|
52
|
+
options: { toolName?: string; limit: number },
|
|
53
|
+
agentId?: string,
|
|
54
|
+
) => Promise<{
|
|
55
|
+
tool_results?: Array<{
|
|
56
|
+
storage_uri?: string;
|
|
57
|
+
tool_name?: string;
|
|
58
|
+
original_chars?: number;
|
|
59
|
+
created_at?: string;
|
|
60
|
+
}>;
|
|
61
|
+
}>;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export type OpenVikingToolResultToolsDeps = {
|
|
65
|
+
registerTool: (toolOrFactory: unknown, opts: { name: string }) => void;
|
|
66
|
+
getClient: () => Promise<OpenVikingToolResultClient>;
|
|
67
|
+
resolvePluginSessionRouting: (ctx?: OpenVikingToolResultToolContext) => OpenVikingToolResultSession;
|
|
68
|
+
isBypassedSession: (ctx?: OpenVikingToolResultToolContext) => boolean;
|
|
69
|
+
makeBypassedToolResult: (toolName: string) => unknown;
|
|
70
|
+
logger?: { warn?: (message: string) => void };
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
type ToolResultRef = {
|
|
74
|
+
sessionId: string;
|
|
75
|
+
toolResultId: string;
|
|
76
|
+
ref: string;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export function parseToolResultRef(value: unknown): ToolResultRef | null {
|
|
80
|
+
const raw = typeof value === "string" ? value.trim() : "";
|
|
81
|
+
if (!raw) {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
const match = raw.match(/^viking:\/\/session\/([^/]+)\/tool-results\/([^/?#]+)(?:[?#].*)?$/);
|
|
85
|
+
if (!match) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
const sessionId = decodeURIComponent(match[1]!);
|
|
89
|
+
const toolResultId = decodeURIComponent(match[2]!);
|
|
90
|
+
if (!sessionId || !toolResultId) {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
sessionId,
|
|
95
|
+
toolResultId,
|
|
96
|
+
ref: `viking://session/${encodeURIComponent(sessionId)}/tool-results/${encodeURIComponent(toolResultId)}`,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function getOptionalInteger(value: unknown, fallback: number): number {
|
|
101
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
102
|
+
return fallback;
|
|
103
|
+
}
|
|
104
|
+
return Math.floor(value);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function getPositiveInteger(value: unknown, fallback: number): number {
|
|
108
|
+
return Math.max(1, getOptionalInteger(value, fallback));
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function registerOpenVikingToolResultTools({
|
|
112
|
+
registerTool,
|
|
113
|
+
getClient,
|
|
114
|
+
resolvePluginSessionRouting,
|
|
115
|
+
isBypassedSession,
|
|
116
|
+
makeBypassedToolResult,
|
|
117
|
+
logger,
|
|
118
|
+
}: OpenVikingToolResultToolsDeps): void {
|
|
119
|
+
registerTool(
|
|
120
|
+
(ctx: OpenVikingToolResultToolContext): OpenVikingToolResultToolDefinition => ({
|
|
121
|
+
name: "openviking_tool_result_read",
|
|
122
|
+
label: "Tool Result Read (OpenViking)",
|
|
123
|
+
description:
|
|
124
|
+
"Restore the full original content of a tool result that was externalized by OpenViking. " +
|
|
125
|
+
"Use when a previous tool result was externalized and only a preview is visible — " +
|
|
126
|
+
"the preview contains a [tool-result-ref] or viking://session/.../tool-results/... URI. " +
|
|
127
|
+
"\"Read\" tool returns the same truncated preview; this tool returns the complete content. " +
|
|
128
|
+
"To read all content: pass offset=0 and a limit large enough to cover the whole result " +
|
|
129
|
+
"(e.g. limit=100000). Use offset/limit for paging only when you need a specific section.",
|
|
130
|
+
parameters: Type.Object({
|
|
131
|
+
tool_output_ref: Type.String({
|
|
132
|
+
description:
|
|
133
|
+
"Exact OV URI from the preview, e.g. viking://session/<session_id>/tool-results/<tool_result_id>",
|
|
134
|
+
}),
|
|
135
|
+
offset: Type.Optional(Type.Number({ description: "Unicode character offset. Default: 0" })),
|
|
136
|
+
limit: Type.Optional(Type.Number({ description: "Maximum Unicode characters to read. Default: 20000" })),
|
|
137
|
+
}),
|
|
138
|
+
async execute(_toolCallId: string, params: Record<string, unknown>) {
|
|
139
|
+
if (isBypassedSession(ctx)) {
|
|
140
|
+
return makeBypassedToolResult("openviking_tool_result_read");
|
|
141
|
+
}
|
|
142
|
+
const session = resolvePluginSessionRouting(ctx);
|
|
143
|
+
if (!session.ovSessionId) {
|
|
144
|
+
return {
|
|
145
|
+
content: [{ type: "text", text: "Error: no active session." }],
|
|
146
|
+
details: { error: "no_session" },
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const parsed = parseToolResultRef(params.tool_output_ref ?? params.ref ?? params.uri);
|
|
151
|
+
if (!parsed) {
|
|
152
|
+
return {
|
|
153
|
+
content: [{ type: "text", text: "Error: tool_output_ref must be a viking://session/.../tool-results/... URI." }],
|
|
154
|
+
details: { error: "invalid_tool_output_ref" },
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
if (parsed.sessionId !== session.ovSessionId) {
|
|
158
|
+
return {
|
|
159
|
+
content: [{ type: "text", text: "Error: refusing to read a tool result from another session." }],
|
|
160
|
+
details: {
|
|
161
|
+
error: "session_mismatch",
|
|
162
|
+
requestedSessionId: parsed.sessionId,
|
|
163
|
+
currentSessionId: session.ovSessionId,
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const offset = Math.max(0, getOptionalInteger(params.offset, 0));
|
|
169
|
+
const limit = getOptionalInteger(params.limit, 20_000);
|
|
170
|
+
if (limit < -1) {
|
|
171
|
+
return {
|
|
172
|
+
content: [{ type: "text", text: "Error: limit must be -1 or greater than or equal to 0." }],
|
|
173
|
+
details: { error: "invalid_limit", limit },
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
try {
|
|
178
|
+
const client = await getClient();
|
|
179
|
+
const result = await client.readToolResult(
|
|
180
|
+
session.ovSessionId,
|
|
181
|
+
parsed.toolResultId,
|
|
182
|
+
{ offset, limit, includeMetadata: true },
|
|
183
|
+
session.agentId,
|
|
184
|
+
);
|
|
185
|
+
const returnedChars = result.content.length;
|
|
186
|
+
const nextOffset = result.offset + returnedChars;
|
|
187
|
+
const text = result.content || "(empty tool result chunk)";
|
|
188
|
+
return {
|
|
189
|
+
content: [{ type: "text", text }],
|
|
190
|
+
details: {
|
|
191
|
+
action: "read",
|
|
192
|
+
tool_output_ref: parsed.ref,
|
|
193
|
+
tool_result_id: result.tool_result_id,
|
|
194
|
+
offset: result.offset,
|
|
195
|
+
limit: result.limit,
|
|
196
|
+
returned_chars: returnedChars,
|
|
197
|
+
total_chars: result.total_chars,
|
|
198
|
+
has_more: result.has_more,
|
|
199
|
+
next_offset: result.has_more ? nextOffset : null,
|
|
200
|
+
metadata: result.metadata ?? null,
|
|
201
|
+
},
|
|
202
|
+
};
|
|
203
|
+
} catch (err) {
|
|
204
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
205
|
+
logger?.warn?.(`openviking: openviking_tool_result_read failed: ${msg}`);
|
|
206
|
+
return {
|
|
207
|
+
content: [{ type: "text", text: `Failed to read tool result: ${msg}` }],
|
|
208
|
+
details: { error: msg, tool_output_ref: parsed.ref },
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
}),
|
|
213
|
+
{ name: "openviking_tool_result_read" },
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
registerTool(
|
|
217
|
+
(ctx: OpenVikingToolResultToolContext): OpenVikingToolResultToolDefinition => ({
|
|
218
|
+
name: "openviking_tool_result_search",
|
|
219
|
+
label: "Tool Result Search (OpenViking)",
|
|
220
|
+
description:
|
|
221
|
+
"Search inside an externalized tool result for a keyword. " +
|
|
222
|
+
"Use when you need to find specific content in a large externalized result, " +
|
|
223
|
+
"before reading it with openviking_tool_result_read. " +
|
|
224
|
+
"Returns matching snippets with their character offsets.",
|
|
225
|
+
parameters: Type.Object({
|
|
226
|
+
tool_output_ref: Type.String({
|
|
227
|
+
description:
|
|
228
|
+
"Exact OV URI from the preview, e.g. viking://session/<session_id>/tool-results/<tool_result_id>",
|
|
229
|
+
}),
|
|
230
|
+
query: Type.String({ description: "Keyword or exact text to search for" }),
|
|
231
|
+
limit: Type.Optional(Type.Number({ description: "Maximum matches. Default: 20" })),
|
|
232
|
+
context_chars: Type.Optional(Type.Number({ description: "Characters around each match. Default: 300" })),
|
|
233
|
+
}),
|
|
234
|
+
async execute(_toolCallId: string, params: Record<string, unknown>) {
|
|
235
|
+
if (isBypassedSession(ctx)) {
|
|
236
|
+
return makeBypassedToolResult("openviking_tool_result_search");
|
|
237
|
+
}
|
|
238
|
+
const session = resolvePluginSessionRouting(ctx);
|
|
239
|
+
if (!session.ovSessionId) {
|
|
240
|
+
return {
|
|
241
|
+
content: [{ type: "text", text: "Error: no active session." }],
|
|
242
|
+
details: { error: "no_session" },
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const parsed = parseToolResultRef(params.tool_output_ref ?? params.ref ?? params.uri);
|
|
247
|
+
if (!parsed) {
|
|
248
|
+
return {
|
|
249
|
+
content: [{ type: "text", text: "Error: tool_output_ref must be a viking://session/.../tool-results/... URI." }],
|
|
250
|
+
details: { error: "invalid_tool_output_ref" },
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
if (parsed.sessionId !== session.ovSessionId) {
|
|
254
|
+
return {
|
|
255
|
+
content: [{ type: "text", text: "Error: refusing to search a tool result from another session." }],
|
|
256
|
+
details: {
|
|
257
|
+
error: "session_mismatch",
|
|
258
|
+
requestedSessionId: parsed.sessionId,
|
|
259
|
+
currentSessionId: session.ovSessionId,
|
|
260
|
+
},
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const query = String(params.query ?? "").trim();
|
|
265
|
+
if (!query) {
|
|
266
|
+
return {
|
|
267
|
+
content: [{ type: "text", text: "Error: query is required." }],
|
|
268
|
+
details: { error: "missing_param", param: "query" },
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
const limit = getPositiveInteger(params.limit, 20);
|
|
272
|
+
const contextChars = Math.max(
|
|
273
|
+
0,
|
|
274
|
+
getOptionalInteger(params.context_chars ?? params.contextChars, 300),
|
|
275
|
+
);
|
|
276
|
+
|
|
277
|
+
try {
|
|
278
|
+
const client = await getClient();
|
|
279
|
+
const result = await client.searchToolResult(
|
|
280
|
+
session.ovSessionId,
|
|
281
|
+
parsed.toolResultId,
|
|
282
|
+
query,
|
|
283
|
+
{ limit, contextChars },
|
|
284
|
+
session.agentId,
|
|
285
|
+
);
|
|
286
|
+
const matches = result.matches ?? [];
|
|
287
|
+
const text = matches.length
|
|
288
|
+
? [
|
|
289
|
+
`Found ${matches.length} match(es) for "${query}" in ${parsed.ref}:`,
|
|
290
|
+
"",
|
|
291
|
+
...matches.map((match, index) =>
|
|
292
|
+
`## Match ${index + 1} (offset ${match.offset})\n${match.snippet}`,
|
|
293
|
+
),
|
|
294
|
+
].join("\n")
|
|
295
|
+
: `No matches found for "${query}" in ${parsed.ref}.`;
|
|
296
|
+
return {
|
|
297
|
+
content: [{ type: "text", text }],
|
|
298
|
+
details: {
|
|
299
|
+
action: "searched",
|
|
300
|
+
tool_output_ref: parsed.ref,
|
|
301
|
+
tool_result_id: result.tool_result_id,
|
|
302
|
+
query,
|
|
303
|
+
match_count: matches.length,
|
|
304
|
+
matches,
|
|
305
|
+
},
|
|
306
|
+
};
|
|
307
|
+
} catch (err) {
|
|
308
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
309
|
+
logger?.warn?.(`openviking: openviking_tool_result_search failed: ${msg}`);
|
|
310
|
+
return {
|
|
311
|
+
content: [{ type: "text", text: `Failed to search tool result: ${msg}` }],
|
|
312
|
+
details: { error: msg, tool_output_ref: parsed.ref, query },
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
},
|
|
316
|
+
}),
|
|
317
|
+
{ name: "openviking_tool_result_search" },
|
|
318
|
+
);
|
|
319
|
+
|
|
320
|
+
registerTool(
|
|
321
|
+
(ctx: OpenVikingToolResultToolContext): OpenVikingToolResultToolDefinition => ({
|
|
322
|
+
name: "openviking_tool_result_list",
|
|
323
|
+
label: "Tool Result List (OpenViking)",
|
|
324
|
+
description:
|
|
325
|
+
"List externalized tool results for the current session. " +
|
|
326
|
+
"Use to discover available refs before calling openviking_tool_result_read. " +
|
|
327
|
+
"Optionally filter by tool_name to narrow down results.",
|
|
328
|
+
parameters: Type.Object({
|
|
329
|
+
tool_name: Type.Optional(Type.String({ description: "Optional exact tool name filter" })),
|
|
330
|
+
limit: Type.Optional(Type.Number({ description: "Maximum results. Default: 50" })),
|
|
331
|
+
}),
|
|
332
|
+
async execute(_toolCallId: string, params: Record<string, unknown>) {
|
|
333
|
+
if (isBypassedSession(ctx)) {
|
|
334
|
+
return makeBypassedToolResult("openviking_tool_result_list");
|
|
335
|
+
}
|
|
336
|
+
const session = resolvePluginSessionRouting(ctx);
|
|
337
|
+
if (!session.ovSessionId) {
|
|
338
|
+
return {
|
|
339
|
+
content: [{ type: "text", text: "Error: no active session." }],
|
|
340
|
+
details: { error: "no_session" },
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
const toolName =
|
|
345
|
+
typeof params.tool_name === "string" && params.tool_name.trim()
|
|
346
|
+
? params.tool_name.trim()
|
|
347
|
+
: typeof params.toolName === "string" && params.toolName.trim()
|
|
348
|
+
? params.toolName.trim()
|
|
349
|
+
: undefined;
|
|
350
|
+
const limit = getPositiveInteger(params.limit, 50);
|
|
351
|
+
|
|
352
|
+
try {
|
|
353
|
+
const client = await getClient();
|
|
354
|
+
const result = await client.listToolResults(
|
|
355
|
+
session.ovSessionId,
|
|
356
|
+
{ toolName, limit },
|
|
357
|
+
session.agentId,
|
|
358
|
+
);
|
|
359
|
+
const items = result.tool_results ?? [];
|
|
360
|
+
const text = items.length
|
|
361
|
+
? [
|
|
362
|
+
`Found ${items.length} externalized tool result(s) in current session:`,
|
|
363
|
+
"",
|
|
364
|
+
...items.map((item, index) => {
|
|
365
|
+
const ref = typeof item.storage_uri === "string" ? item.storage_uri : "(missing ref)";
|
|
366
|
+
const name = typeof item.tool_name === "string" ? item.tool_name : "tool";
|
|
367
|
+
const chars = typeof item.original_chars === "number" ? item.original_chars : "unknown";
|
|
368
|
+
const created = typeof item.created_at === "string" ? ` created_at=${item.created_at}` : "";
|
|
369
|
+
return `${index + 1}. ${name} original_chars=${chars}${created}\nref: ${ref}`;
|
|
370
|
+
}),
|
|
371
|
+
].join("\n")
|
|
372
|
+
: toolName
|
|
373
|
+
? `No externalized tool results found for tool "${toolName}" in current session.`
|
|
374
|
+
: "No externalized tool results found in current session.";
|
|
375
|
+
return {
|
|
376
|
+
content: [{ type: "text", text }],
|
|
377
|
+
details: {
|
|
378
|
+
action: "listed",
|
|
379
|
+
session_id: session.ovSessionId,
|
|
380
|
+
tool_name: toolName ?? null,
|
|
381
|
+
count: items.length,
|
|
382
|
+
tool_results: items,
|
|
383
|
+
},
|
|
384
|
+
};
|
|
385
|
+
} catch (err) {
|
|
386
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
387
|
+
logger?.warn?.(`openviking: openviking_tool_result_list failed: ${msg}`);
|
|
388
|
+
return {
|
|
389
|
+
content: [{ type: "text", text: `Failed to list tool results: ${msg}` }],
|
|
390
|
+
details: { error: msg, session_id: session.ovSessionId, tool_name: toolName ?? null },
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
},
|
|
394
|
+
}),
|
|
395
|
+
{ name: "openviking_tool_result_list" },
|
|
396
|
+
);
|
|
397
|
+
}
|