@rivus/agent 0.1.0
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/LICENSE +22 -0
- package/README.md +1051 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +22 -0
- package/dist/index.d.ts +3423 -0
- package/dist/index.js +7337 -0
- package/dist/rivus-daemon-cli.js +2599 -0
- package/dist/rivus-plugin-registry.js +316 -0
- package/dist/rivus-plugin-testkit.d.ts +291 -0
- package/dist/rivus-plugin-testkit.js +62 -0
- package/dist/testing/index.d.ts +55 -0
- package/dist/testing/index.js +94 -0
- package/examples/current-weather.mjs +143 -0
- package/examples/html-drive-tools.mjs +262 -0
- package/examples/langfuse-drive-e2e.mjs +175 -0
- package/examples/pi-feishu-deployment.bootstrap.ts +542 -0
- package/examples/pi-feishu.bootstrap.ts +225 -0
- package/examples/rivus-agents.plugin.mjs +238 -0
- package/examples/rivus-langfuse-demo.config.json +36 -0
- package/examples/rivus.config.json +83 -0
- package/package.json +112 -0
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
//#region src/domain/rivus-plugin.ts
|
|
3
|
+
const RIVUS_PLUGIN_API_VERSION = "1";
|
|
4
|
+
function requiresToolApproval(risk) {
|
|
5
|
+
return risk === "irreversible" || risk === "host-control";
|
|
6
|
+
}
|
|
7
|
+
var RivusToolInputRejected = class extends Error {
|
|
8
|
+
name = "RivusToolInputRejected";
|
|
9
|
+
};
|
|
10
|
+
var InvalidRivusPlugin = class extends Error {
|
|
11
|
+
name = "InvalidRivusPlugin";
|
|
12
|
+
};
|
|
13
|
+
//#endregion
|
|
14
|
+
//#region src/domain/agent-memory.ts
|
|
15
|
+
const MEMORY_SCOPES = [
|
|
16
|
+
"conversation",
|
|
17
|
+
"agent-private",
|
|
18
|
+
"shared-user-profile"
|
|
19
|
+
];
|
|
20
|
+
const RIVUS_MEMORY_TOOL_ID = "memory";
|
|
21
|
+
const RIVUS_MEMORY_TOOL_PLUGIN_ID = "rivus-core";
|
|
22
|
+
const RIVUS_MEMORY_TOOL_VERSION = "1.0.0";
|
|
23
|
+
function createMemoryNamespace(binding) {
|
|
24
|
+
const encode = (value) => encodeURIComponent(value);
|
|
25
|
+
switch (binding.scope) {
|
|
26
|
+
case "conversation": return [
|
|
27
|
+
binding.tenantId,
|
|
28
|
+
binding.agentId,
|
|
29
|
+
binding.subjectId,
|
|
30
|
+
binding.conversationId ?? "",
|
|
31
|
+
binding.scope
|
|
32
|
+
].map(encode).join("/");
|
|
33
|
+
case "agent-private": return [
|
|
34
|
+
binding.tenantId,
|
|
35
|
+
binding.agentId,
|
|
36
|
+
binding.subjectId,
|
|
37
|
+
binding.scope
|
|
38
|
+
].map(encode).join("/");
|
|
39
|
+
case "shared-user-profile": return [
|
|
40
|
+
binding.tenantId,
|
|
41
|
+
binding.subjectId,
|
|
42
|
+
binding.scope
|
|
43
|
+
].map(encode).join("/");
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function restrictMemoryScopesForAudience(scopes, audience) {
|
|
47
|
+
return audience === "group" ? scopes.filter((scope) => scope === "conversation") : [...scopes];
|
|
48
|
+
}
|
|
49
|
+
function createRivusMemoryToolContract(scopes) {
|
|
50
|
+
return Object.freeze({
|
|
51
|
+
description: "Search and read Memory inside Host-bound scopes; propose or request forgetting only in writable private scopes.",
|
|
52
|
+
digest: "sha256:rivus-memory-v3",
|
|
53
|
+
id: RIVUS_MEMORY_TOOL_ID,
|
|
54
|
+
idempotency: "required",
|
|
55
|
+
inputSchema: Object.freeze({
|
|
56
|
+
additionalProperties: false,
|
|
57
|
+
properties: {
|
|
58
|
+
command: {
|
|
59
|
+
description: "One of search, read, propose, or forget_request.",
|
|
60
|
+
enum: [
|
|
61
|
+
"search",
|
|
62
|
+
"read",
|
|
63
|
+
"propose",
|
|
64
|
+
"forget_request"
|
|
65
|
+
],
|
|
66
|
+
type: "string"
|
|
67
|
+
},
|
|
68
|
+
id: {
|
|
69
|
+
description: "Required for read and forget_request.",
|
|
70
|
+
minLength: 1,
|
|
71
|
+
type: "string"
|
|
72
|
+
},
|
|
73
|
+
input: {
|
|
74
|
+
additionalProperties: false,
|
|
75
|
+
description: "Required for propose.",
|
|
76
|
+
properties: { content: {
|
|
77
|
+
minLength: 1,
|
|
78
|
+
type: "string"
|
|
79
|
+
} },
|
|
80
|
+
required: ["content"],
|
|
81
|
+
type: "object"
|
|
82
|
+
},
|
|
83
|
+
query: {
|
|
84
|
+
additionalProperties: false,
|
|
85
|
+
description: "Required for search.",
|
|
86
|
+
properties: { query: { type: "string" } },
|
|
87
|
+
required: ["query"],
|
|
88
|
+
type: "object"
|
|
89
|
+
},
|
|
90
|
+
reason: {
|
|
91
|
+
description: "Optional reason for forget_request.",
|
|
92
|
+
type: "string"
|
|
93
|
+
},
|
|
94
|
+
...scopes.length === 0 ? {} : { scope: {
|
|
95
|
+
description: "Optional Host-granted scope for search or propose. Shared User Profile is read-only to the model.",
|
|
96
|
+
enum: [...scopes],
|
|
97
|
+
type: "string"
|
|
98
|
+
} }
|
|
99
|
+
},
|
|
100
|
+
required: ["command"],
|
|
101
|
+
type: "object"
|
|
102
|
+
}),
|
|
103
|
+
risk: "mutate",
|
|
104
|
+
version: RIVUS_MEMORY_TOOL_VERSION
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
//#endregion
|
|
108
|
+
//#region src/application/plugin/deep-freeze.ts
|
|
109
|
+
function deepFreeze(value) {
|
|
110
|
+
if (value !== null && typeof value === "object" && !Object.isFrozen(value)) {
|
|
111
|
+
Object.freeze(value);
|
|
112
|
+
for (const child of Object.values(value)) deepFreeze(child);
|
|
113
|
+
}
|
|
114
|
+
return value;
|
|
115
|
+
}
|
|
116
|
+
//#endregion
|
|
117
|
+
//#region src/application/plugin/rivus-plugin-registry.ts
|
|
118
|
+
function createRivusPluginCatalog() {
|
|
119
|
+
const plugins = /* @__PURE__ */ new Map();
|
|
120
|
+
const profiles = /* @__PURE__ */ new Map();
|
|
121
|
+
const tools = /* @__PURE__ */ new Map();
|
|
122
|
+
const skills = /* @__PURE__ */ new Map();
|
|
123
|
+
const automations = /* @__PURE__ */ new Map();
|
|
124
|
+
return {
|
|
125
|
+
registerPlugin: (plugin) => {
|
|
126
|
+
validateManifest(plugin.manifest);
|
|
127
|
+
rejectDuplicate(plugins, plugin.manifest.id, "plugin");
|
|
128
|
+
const pendingProfiles = [];
|
|
129
|
+
const pendingTools = [];
|
|
130
|
+
const pendingSkills = [];
|
|
131
|
+
const pendingAutomations = [];
|
|
132
|
+
const pendingIds = /* @__PURE__ */ new Set();
|
|
133
|
+
const register = (kind, definition, catalog, destination, namespaced) => {
|
|
134
|
+
validateIdentifier(definition.id, kind);
|
|
135
|
+
if (namespaced && !definition.id.startsWith(`${plugin.manifest.id}/`)) throw new InvalidRivusPlugin(`${kind} id ${definition.id} must use plugin namespace ${plugin.manifest.id}/`);
|
|
136
|
+
const key = `${kind}:${definition.id}`;
|
|
137
|
+
if (pendingIds.has(key) || catalog.has(definition.id)) throw new InvalidRivusPlugin(`duplicate ${kind} id: ${definition.id}`);
|
|
138
|
+
pendingIds.add(key);
|
|
139
|
+
destination.push(deepFreeze({
|
|
140
|
+
...definition,
|
|
141
|
+
pluginId: plugin.manifest.id
|
|
142
|
+
}));
|
|
143
|
+
};
|
|
144
|
+
plugin.register({
|
|
145
|
+
registerAgentProfile: (profile) => register("profile", profile, profiles, pendingProfiles, false),
|
|
146
|
+
registerAutomation: (automation) => register("automation", automation, automations, pendingAutomations, true),
|
|
147
|
+
registerSkill: (skill) => register("skill", skill, skills, pendingSkills, true),
|
|
148
|
+
registerTool: (tool) => register("tool", tool, tools, pendingTools, true)
|
|
149
|
+
});
|
|
150
|
+
const availableToolIds = /* @__PURE__ */ new Set([...tools.keys(), ...pendingTools.map(({ id }) => id)]);
|
|
151
|
+
const availableSkillIds = /* @__PURE__ */ new Set([...skills.keys(), ...pendingSkills.map(({ id }) => id)]);
|
|
152
|
+
const availableProfileIds = /* @__PURE__ */ new Set([...profiles.keys(), ...pendingProfiles.map(({ id }) => id)]);
|
|
153
|
+
for (const profile of pendingProfiles) {
|
|
154
|
+
validateMemoryScopes(profile.memory.scopes, `profile ${profile.id}`);
|
|
155
|
+
validateReferences(profile.tools.allow, availableToolIds, `profile ${profile.id}`, "tool");
|
|
156
|
+
validateReferences(profile.skills.allow, availableSkillIds, `profile ${profile.id}`, "skill");
|
|
157
|
+
}
|
|
158
|
+
for (const automation of pendingAutomations) {
|
|
159
|
+
if (!availableProfileIds.has(automation.profileId)) throw new InvalidRivusPlugin(`automation ${automation.id} references unknown profile: ${automation.profileId}`);
|
|
160
|
+
validateReferences(automation.requestedToolIds, availableToolIds, `automation ${automation.id}`, "tool");
|
|
161
|
+
validateReferences(automation.requestedSkillIds, availableSkillIds, `automation ${automation.id}`, "skill");
|
|
162
|
+
}
|
|
163
|
+
plugins.set(plugin.manifest.id, deepFreeze({ ...plugin.manifest }));
|
|
164
|
+
for (const profile of pendingProfiles) profiles.set(profile.id, profile);
|
|
165
|
+
for (const tool of pendingTools) tools.set(tool.id, tool);
|
|
166
|
+
for (const skill of pendingSkills) skills.set(skill.id, skill);
|
|
167
|
+
for (const automation of pendingAutomations) automations.set(automation.id, automation);
|
|
168
|
+
},
|
|
169
|
+
snapshot: () => deepFreeze({
|
|
170
|
+
automations: [...automations.values()],
|
|
171
|
+
plugins: [...plugins.values()],
|
|
172
|
+
profiles: [...profiles.values()],
|
|
173
|
+
skills: [...skills.values()],
|
|
174
|
+
tools: [...tools.values()]
|
|
175
|
+
})
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
function resolveRivusAgentDefinition(catalog, deployment) {
|
|
179
|
+
const snapshot = catalog.snapshot();
|
|
180
|
+
const plugin = snapshot.plugins.find((candidate) => candidate.id === deployment.pluginId);
|
|
181
|
+
if (!plugin) throw new InvalidRivusPlugin(`unknown deployment plugin: ${deployment.pluginId}`);
|
|
182
|
+
const profile = snapshot.profiles.find((candidate) => candidate.id === deployment.profileId && candidate.pluginId === deployment.pluginId);
|
|
183
|
+
if (!profile) throw new InvalidRivusPlugin(`unknown profile ${deployment.profileId} for plugin ${deployment.pluginId}`);
|
|
184
|
+
const requestedTools = uniqueExactIds(deployment.tools.allow, "deployment tool allowlist");
|
|
185
|
+
const catalogTools = new Map(snapshot.tools.map((tool) => [tool.id, tool]));
|
|
186
|
+
for (const id of requestedTools) if (!catalogTools.has(id)) throw new InvalidRivusPlugin(`unknown deployment tool: ${id}`);
|
|
187
|
+
const profileToolIds = uniqueExactIds(profile.tools.allow, "profile tool allowlist");
|
|
188
|
+
for (const id of profileToolIds) if (!catalogTools.has(id)) throw new InvalidRivusPlugin(`profile ${profile.id} references unknown tool: ${id}`);
|
|
189
|
+
const toolIds = profileToolIds.filter((id) => requestedTools.includes(id)).sort();
|
|
190
|
+
const profileMemoryScopes = validateMemoryScopes(profile.memory.scopes, `profile ${profile.id}`);
|
|
191
|
+
const requestedMemoryScopes = validateMemoryScopes(deployment.memory?.scopes ?? [], `deployment ${deployment.agentId}`);
|
|
192
|
+
const memoryScopes = profileMemoryScopes.filter((scope) => requestedMemoryScopes.includes(scope));
|
|
193
|
+
const memoryTool = deployment.memory?.tool === true;
|
|
194
|
+
if (memoryTool && memoryScopes.length === 0) throw new InvalidRivusPlugin(`deployment ${deployment.agentId} Memory Tool requires at least one granted scope`);
|
|
195
|
+
const memoryToolContract = createRivusMemoryToolContract(memoryScopes);
|
|
196
|
+
const resolvedToolIds = [...toolIds, ...memoryTool ? [memoryToolContract.id] : []].sort();
|
|
197
|
+
const tools = resolvedToolIds.map((id) => id === memoryToolContract.id ? {
|
|
198
|
+
...memoryToolContract,
|
|
199
|
+
pluginId: RIVUS_MEMORY_TOOL_PLUGIN_ID
|
|
200
|
+
} : toResolvedTool(catalogTools.get(id)));
|
|
201
|
+
const requestedSkills = uniqueExactIds(deployment.skills.allow, "deployment skill allowlist");
|
|
202
|
+
const catalogSkills = new Map(snapshot.skills.map((skill) => [skill.id, skill]));
|
|
203
|
+
for (const id of requestedSkills) if (!catalogSkills.has(id)) throw new InvalidRivusPlugin(`unknown deployment skill: ${id}`);
|
|
204
|
+
const skillIds = uniqueExactIds(profile.skills.allow, "profile skill allowlist").filter((id) => requestedSkills.includes(id)).sort();
|
|
205
|
+
const skills = skillIds.map((id) => {
|
|
206
|
+
const skill = catalogSkills.get(id);
|
|
207
|
+
if (!skill) throw new InvalidRivusPlugin(`profile ${profile.id} references unknown skill: ${id}`);
|
|
208
|
+
return skill;
|
|
209
|
+
});
|
|
210
|
+
const profileRevision = digest({
|
|
211
|
+
memory: {
|
|
212
|
+
scopes: memoryScopes,
|
|
213
|
+
tool: memoryTool
|
|
214
|
+
},
|
|
215
|
+
model: profile.model,
|
|
216
|
+
plugin,
|
|
217
|
+
profileId: profile.id,
|
|
218
|
+
skills: skills.map(({ content, digest: skillDigest, id, pluginId, title, version }) => ({
|
|
219
|
+
content,
|
|
220
|
+
digest: skillDigest,
|
|
221
|
+
id,
|
|
222
|
+
pluginId,
|
|
223
|
+
title,
|
|
224
|
+
version
|
|
225
|
+
})),
|
|
226
|
+
systemPrompt: profile.systemPrompt,
|
|
227
|
+
tools
|
|
228
|
+
});
|
|
229
|
+
const toolGrantSet = deepFreeze({
|
|
230
|
+
revision: digest({
|
|
231
|
+
profileRevision,
|
|
232
|
+
toolIds: resolvedToolIds
|
|
233
|
+
}),
|
|
234
|
+
toolIds: resolvedToolIds
|
|
235
|
+
});
|
|
236
|
+
const skillGrantSet = deepFreeze({
|
|
237
|
+
revision: digest({
|
|
238
|
+
profileRevision,
|
|
239
|
+
skillIds
|
|
240
|
+
}),
|
|
241
|
+
skillIds
|
|
242
|
+
});
|
|
243
|
+
return deepFreeze({
|
|
244
|
+
agentId: deployment.agentId,
|
|
245
|
+
endpointIds: [...deployment.endpointIds],
|
|
246
|
+
memory: {
|
|
247
|
+
scopes: memoryScopes,
|
|
248
|
+
tool: memoryTool
|
|
249
|
+
},
|
|
250
|
+
model: profile.model,
|
|
251
|
+
pluginId: deployment.pluginId,
|
|
252
|
+
profileId: deployment.profileId,
|
|
253
|
+
profileRevision,
|
|
254
|
+
skillGrantSet,
|
|
255
|
+
skills,
|
|
256
|
+
systemPrompt: profile.systemPrompt,
|
|
257
|
+
toolGrantSet,
|
|
258
|
+
tools
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
function validateMemoryScopes(scopes, owner) {
|
|
262
|
+
const result = /* @__PURE__ */ new Set();
|
|
263
|
+
for (const scope of scopes) {
|
|
264
|
+
if (!MEMORY_SCOPES.includes(scope)) throw new InvalidRivusPlugin(`${owner} references unsupported Memory scope: ${String(scope)}`);
|
|
265
|
+
if (result.has(scope)) throw new InvalidRivusPlugin(`${owner} contains duplicate Memory scope: ${scope}`);
|
|
266
|
+
result.add(scope);
|
|
267
|
+
}
|
|
268
|
+
return [...result];
|
|
269
|
+
}
|
|
270
|
+
function validateManifest(manifest) {
|
|
271
|
+
validateIdentifier(manifest.id, "plugin");
|
|
272
|
+
if (manifest.apiVersion !== "1") throw new InvalidRivusPlugin(`unsupported plugin API version ${manifest.apiVersion}; expected 1`);
|
|
273
|
+
if (manifest.version.trim() === "") throw new InvalidRivusPlugin("plugin version must not be empty");
|
|
274
|
+
}
|
|
275
|
+
function validateIdentifier(id, kind) {
|
|
276
|
+
if (!/^[a-z0-9][a-z0-9._/-]*$/.test(id) || id.includes("*") || id.includes("//")) throw new InvalidRivusPlugin(`invalid ${kind} id: ${id}`);
|
|
277
|
+
}
|
|
278
|
+
function rejectDuplicate(map, id, kind) {
|
|
279
|
+
if (map.has(id)) throw new InvalidRivusPlugin(`duplicate ${kind} id: ${id}`);
|
|
280
|
+
}
|
|
281
|
+
function uniqueExactIds(ids, label) {
|
|
282
|
+
const result = /* @__PURE__ */ new Set();
|
|
283
|
+
for (const id of ids) {
|
|
284
|
+
if (id.includes("*")) throw new InvalidRivusPlugin(`${label} does not support wildcard id: ${id}`);
|
|
285
|
+
validateIdentifier(id, label);
|
|
286
|
+
if (result.has(id)) throw new InvalidRivusPlugin(`duplicate id in ${label}: ${id}`);
|
|
287
|
+
result.add(id);
|
|
288
|
+
}
|
|
289
|
+
return [...result];
|
|
290
|
+
}
|
|
291
|
+
function validateReferences(ids, available, owner, kind) {
|
|
292
|
+
for (const id of uniqueExactIds(ids, `${owner} ${kind} references`)) if (!available.has(id)) throw new InvalidRivusPlugin(`${owner} references unknown ${kind}: ${id}`);
|
|
293
|
+
}
|
|
294
|
+
function toResolvedTool(tool) {
|
|
295
|
+
const { createExecutor: _createExecutor, description, digest: toolDigest, id, idempotency, inputSchema, pluginId, risk, version } = tool;
|
|
296
|
+
return deepFreeze({
|
|
297
|
+
description,
|
|
298
|
+
digest: toolDigest,
|
|
299
|
+
id,
|
|
300
|
+
idempotency,
|
|
301
|
+
inputSchema,
|
|
302
|
+
pluginId,
|
|
303
|
+
risk,
|
|
304
|
+
version
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
function digest(value) {
|
|
308
|
+
return `sha256:${createHash("sha256").update(stableJson(value)).digest("hex")}`;
|
|
309
|
+
}
|
|
310
|
+
function stableJson(value) {
|
|
311
|
+
if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`;
|
|
312
|
+
if (value !== null && typeof value === "object") return `{${Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, child]) => `${JSON.stringify(key)}:${stableJson(child)}`).join(",")}}`;
|
|
313
|
+
return JSON.stringify(value);
|
|
314
|
+
}
|
|
315
|
+
//#endregion
|
|
316
|
+
export { RIVUS_MEMORY_TOOL_ID as a, createMemoryNamespace as c, InvalidRivusPlugin as d, RIVUS_PLUGIN_API_VERSION as f, MEMORY_SCOPES as i, createRivusMemoryToolContract as l, requiresToolApproval as m, resolveRivusAgentDefinition as n, RIVUS_MEMORY_TOOL_PLUGIN_ID as o, RivusToolInputRejected as p, deepFreeze as r, RIVUS_MEMORY_TOOL_VERSION as s, createRivusPluginCatalog as t, restrictMemoryScopesForAudience as u };
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
//#region src/domain/agent-memory.d.ts
|
|
2
|
+
declare const MEMORY_SCOPES: readonly ["conversation", "agent-private", "shared-user-profile"];
|
|
3
|
+
declare const RIVUS_MEMORY_TOOL_ID = "memory";
|
|
4
|
+
declare const RIVUS_MEMORY_TOOL_PLUGIN_ID = "rivus-core";
|
|
5
|
+
declare const RIVUS_MEMORY_TOOL_VERSION = "1.0.0";
|
|
6
|
+
type MemoryScope = (typeof MEMORY_SCOPES)[number];
|
|
7
|
+
type MemoryState = "proposed" | "confirmed" | "superseded" | "tombstoned";
|
|
8
|
+
type MemoryInvocationAudience = "group" | "private";
|
|
9
|
+
interface AgentMemoryIdentity {
|
|
10
|
+
readonly audience: MemoryInvocationAudience;
|
|
11
|
+
readonly conversationId?: string;
|
|
12
|
+
readonly subjectId: string;
|
|
13
|
+
readonly tenantId: string;
|
|
14
|
+
}
|
|
15
|
+
interface AgentMemoryAuthority extends AgentMemoryIdentity {
|
|
16
|
+
readonly scopes: ReadonlyArray<MemoryScope>;
|
|
17
|
+
}
|
|
18
|
+
interface MemoryBinding {
|
|
19
|
+
readonly agentId: string;
|
|
20
|
+
readonly conversationId?: string;
|
|
21
|
+
readonly scope: MemoryScope;
|
|
22
|
+
readonly subjectId: string;
|
|
23
|
+
readonly tenantId: string;
|
|
24
|
+
}
|
|
25
|
+
interface MemoryRecord {
|
|
26
|
+
readonly content: string;
|
|
27
|
+
readonly conversationSafe: boolean;
|
|
28
|
+
readonly id: string;
|
|
29
|
+
readonly revision: number;
|
|
30
|
+
readonly scope: MemoryScope;
|
|
31
|
+
readonly state: MemoryState;
|
|
32
|
+
readonly tombstoneReason?: string;
|
|
33
|
+
}
|
|
34
|
+
interface AgentMemorySnapshot {
|
|
35
|
+
readonly binding: MemoryBinding;
|
|
36
|
+
readonly record: MemoryRecord;
|
|
37
|
+
}
|
|
38
|
+
declare function createMemoryNamespace(binding: MemoryBinding): string;
|
|
39
|
+
declare function restrictMemoryScopesForAudience(scopes: ReadonlyArray<MemoryScope>, audience: MemoryInvocationAudience): ReadonlyArray<MemoryScope>;
|
|
40
|
+
declare function createRivusMemoryToolContract(scopes: ReadonlyArray<MemoryScope>): Readonly<{
|
|
41
|
+
description: "Search and read Memory inside Host-bound scopes; propose or request forgetting only in writable private scopes.";
|
|
42
|
+
digest: "sha256:rivus-memory-v3";
|
|
43
|
+
id: "memory";
|
|
44
|
+
idempotency: "required";
|
|
45
|
+
inputSchema: Readonly<{
|
|
46
|
+
additionalProperties: false;
|
|
47
|
+
properties: {
|
|
48
|
+
scope?: {
|
|
49
|
+
description: string;
|
|
50
|
+
enum: ("conversation" | "agent-private" | "shared-user-profile")[];
|
|
51
|
+
type: string;
|
|
52
|
+
};
|
|
53
|
+
command: {
|
|
54
|
+
description: string;
|
|
55
|
+
enum: string[];
|
|
56
|
+
type: string;
|
|
57
|
+
};
|
|
58
|
+
id: {
|
|
59
|
+
description: string;
|
|
60
|
+
minLength: number;
|
|
61
|
+
type: string;
|
|
62
|
+
};
|
|
63
|
+
input: {
|
|
64
|
+
additionalProperties: boolean;
|
|
65
|
+
description: string;
|
|
66
|
+
properties: {
|
|
67
|
+
content: {
|
|
68
|
+
minLength: number;
|
|
69
|
+
type: string;
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
required: string[];
|
|
73
|
+
type: string;
|
|
74
|
+
};
|
|
75
|
+
query: {
|
|
76
|
+
additionalProperties: boolean;
|
|
77
|
+
description: string;
|
|
78
|
+
properties: {
|
|
79
|
+
query: {
|
|
80
|
+
type: string;
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
required: string[];
|
|
84
|
+
type: string;
|
|
85
|
+
};
|
|
86
|
+
reason: {
|
|
87
|
+
description: string;
|
|
88
|
+
type: string;
|
|
89
|
+
};
|
|
90
|
+
};
|
|
91
|
+
required: string[];
|
|
92
|
+
type: "object";
|
|
93
|
+
}>;
|
|
94
|
+
risk: "mutate";
|
|
95
|
+
version: "1.0.0";
|
|
96
|
+
}>;
|
|
97
|
+
//#endregion
|
|
98
|
+
//#region src/domain/rivus-plugin.d.ts
|
|
99
|
+
declare const RIVUS_PLUGIN_API_VERSION = "1";
|
|
100
|
+
type RivusToolRisk = "observe" | "mutate" | "irreversible" | "host-control";
|
|
101
|
+
type RivusToolIdempotency = "none" | "supported" | "required";
|
|
102
|
+
declare function requiresToolApproval(risk: RivusToolRisk): boolean;
|
|
103
|
+
declare class RivusToolInputRejected extends Error {
|
|
104
|
+
readonly name: string;
|
|
105
|
+
}
|
|
106
|
+
interface RivusPluginManifest {
|
|
107
|
+
readonly apiVersion: string;
|
|
108
|
+
readonly id: string;
|
|
109
|
+
readonly version: string;
|
|
110
|
+
}
|
|
111
|
+
interface RivusToolExecutor {
|
|
112
|
+
execute(input: unknown, context: RivusToolExecutionContext): unknown;
|
|
113
|
+
}
|
|
114
|
+
interface RivusToolExecutionContext {
|
|
115
|
+
readonly agentId: string;
|
|
116
|
+
readonly instanceId: string;
|
|
117
|
+
readonly memory?: AgentMemoryAuthority;
|
|
118
|
+
readonly runId: string;
|
|
119
|
+
readonly callId: string;
|
|
120
|
+
readonly operationId?: string;
|
|
121
|
+
readonly policyEpoch: number;
|
|
122
|
+
readonly toolId: string;
|
|
123
|
+
readonly toolVersion: string;
|
|
124
|
+
readonly sessionKey: string;
|
|
125
|
+
}
|
|
126
|
+
interface RivusToolFactoryContext {
|
|
127
|
+
readonly toolId: string;
|
|
128
|
+
readonly toolVersion: string;
|
|
129
|
+
}
|
|
130
|
+
interface RivusToolDescriptor {
|
|
131
|
+
readonly id: string;
|
|
132
|
+
readonly version: string;
|
|
133
|
+
readonly digest: string;
|
|
134
|
+
readonly description: string;
|
|
135
|
+
readonly inputSchema: unknown;
|
|
136
|
+
readonly risk: RivusToolRisk;
|
|
137
|
+
readonly idempotency: RivusToolIdempotency;
|
|
138
|
+
readonly createExecutor: (context: RivusToolFactoryContext) => RivusToolExecutor;
|
|
139
|
+
}
|
|
140
|
+
interface RivusHostToolDescriptor extends RivusToolDescriptor {
|
|
141
|
+
readonly replayCompleted?: (input: unknown, completedResult: unknown, context: RivusToolExecutionContext) => unknown;
|
|
142
|
+
}
|
|
143
|
+
interface RivusSkillDescriptor {
|
|
144
|
+
readonly id: string;
|
|
145
|
+
readonly version: string;
|
|
146
|
+
readonly digest: string;
|
|
147
|
+
readonly title: string;
|
|
148
|
+
readonly content: string;
|
|
149
|
+
}
|
|
150
|
+
interface RivusAutomationTemplate {
|
|
151
|
+
readonly id: string;
|
|
152
|
+
readonly profileId: string;
|
|
153
|
+
readonly requestedSkillIds: ReadonlyArray<string>;
|
|
154
|
+
readonly requestedToolIds: ReadonlyArray<string>;
|
|
155
|
+
readonly createInput: (tick: RivusAutomationTickContext) => RivusAutomationInput;
|
|
156
|
+
}
|
|
157
|
+
interface RivusAutomationTickContext {
|
|
158
|
+
readonly occurrence: string;
|
|
159
|
+
}
|
|
160
|
+
interface RivusAutomationInput {
|
|
161
|
+
readonly text: string;
|
|
162
|
+
}
|
|
163
|
+
interface RivusAgentProfile {
|
|
164
|
+
readonly id: string;
|
|
165
|
+
readonly displayName: string;
|
|
166
|
+
readonly systemPrompt: string;
|
|
167
|
+
readonly model: Readonly<Record<string, unknown>>;
|
|
168
|
+
readonly tools: {
|
|
169
|
+
readonly allow: ReadonlyArray<string>;
|
|
170
|
+
};
|
|
171
|
+
readonly skills: {
|
|
172
|
+
readonly allow: ReadonlyArray<string>;
|
|
173
|
+
};
|
|
174
|
+
readonly memory: {
|
|
175
|
+
readonly scopes: ReadonlyArray<MemoryScope>;
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
interface RivusPluginRegistry {
|
|
179
|
+
registerAgentProfile(profile: RivusAgentProfile): void;
|
|
180
|
+
registerTool(tool: RivusToolDescriptor): void;
|
|
181
|
+
registerSkill(skill: RivusSkillDescriptor): void;
|
|
182
|
+
registerAutomation(template: RivusAutomationTemplate): void;
|
|
183
|
+
}
|
|
184
|
+
interface RivusPlugin {
|
|
185
|
+
readonly manifest: RivusPluginManifest;
|
|
186
|
+
register(registry: RivusPluginRegistry): void;
|
|
187
|
+
}
|
|
188
|
+
interface RegisteredRivusPlugin extends RivusPluginManifest {}
|
|
189
|
+
interface RegisteredRivusTool extends RivusToolDescriptor {
|
|
190
|
+
readonly pluginId: string;
|
|
191
|
+
}
|
|
192
|
+
interface RegisteredRivusSkill extends RivusSkillDescriptor {
|
|
193
|
+
readonly pluginId: string;
|
|
194
|
+
}
|
|
195
|
+
interface RegisteredRivusAutomation extends RivusAutomationTemplate {
|
|
196
|
+
readonly pluginId: string;
|
|
197
|
+
}
|
|
198
|
+
interface RegisteredRivusAgentProfile extends RivusAgentProfile {
|
|
199
|
+
readonly pluginId: string;
|
|
200
|
+
}
|
|
201
|
+
interface RivusPluginCatalogSnapshot {
|
|
202
|
+
readonly plugins: ReadonlyArray<RegisteredRivusPlugin>;
|
|
203
|
+
readonly profiles: ReadonlyArray<RegisteredRivusAgentProfile>;
|
|
204
|
+
readonly tools: ReadonlyArray<RegisteredRivusTool>;
|
|
205
|
+
readonly skills: ReadonlyArray<RegisteredRivusSkill>;
|
|
206
|
+
readonly automations: ReadonlyArray<RegisteredRivusAutomation>;
|
|
207
|
+
}
|
|
208
|
+
interface RivusPluginCatalog {
|
|
209
|
+
registerPlugin(plugin: RivusPlugin): void;
|
|
210
|
+
snapshot(): RivusPluginCatalogSnapshot;
|
|
211
|
+
}
|
|
212
|
+
interface RivusAgentDeployment {
|
|
213
|
+
readonly agentId: string;
|
|
214
|
+
readonly pluginId: string;
|
|
215
|
+
readonly profileId: string;
|
|
216
|
+
readonly endpointIds: ReadonlyArray<string>;
|
|
217
|
+
readonly memory?: {
|
|
218
|
+
readonly scopes: ReadonlyArray<MemoryScope>;
|
|
219
|
+
readonly tool: boolean;
|
|
220
|
+
};
|
|
221
|
+
readonly skills: {
|
|
222
|
+
readonly allow: ReadonlyArray<string>;
|
|
223
|
+
};
|
|
224
|
+
readonly tools: {
|
|
225
|
+
readonly allow: ReadonlyArray<string>;
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
interface RivusResolvedToolDescriptor {
|
|
229
|
+
readonly id: string;
|
|
230
|
+
readonly version: string;
|
|
231
|
+
readonly digest: string;
|
|
232
|
+
readonly description: string;
|
|
233
|
+
readonly inputSchema: unknown;
|
|
234
|
+
readonly risk: RivusToolRisk;
|
|
235
|
+
readonly idempotency: RivusToolIdempotency;
|
|
236
|
+
readonly pluginId: string;
|
|
237
|
+
}
|
|
238
|
+
interface RivusToolGrantSet {
|
|
239
|
+
readonly toolIds: ReadonlyArray<string>;
|
|
240
|
+
readonly revision: string;
|
|
241
|
+
}
|
|
242
|
+
interface RivusSkillGrantSet {
|
|
243
|
+
readonly skillIds: ReadonlyArray<string>;
|
|
244
|
+
readonly revision: string;
|
|
245
|
+
}
|
|
246
|
+
interface ResolvedRivusAgentDefinition {
|
|
247
|
+
readonly agentId: string;
|
|
248
|
+
readonly pluginId: string;
|
|
249
|
+
readonly profileId: string;
|
|
250
|
+
readonly endpointIds: ReadonlyArray<string>;
|
|
251
|
+
readonly profileRevision: string;
|
|
252
|
+
readonly systemPrompt: string;
|
|
253
|
+
readonly model: Readonly<Record<string, unknown>>;
|
|
254
|
+
readonly memory: {
|
|
255
|
+
readonly scopes: ReadonlyArray<MemoryScope>;
|
|
256
|
+
readonly tool: boolean;
|
|
257
|
+
};
|
|
258
|
+
readonly skillGrantSet: RivusSkillGrantSet;
|
|
259
|
+
readonly skills: ReadonlyArray<RegisteredRivusSkill>;
|
|
260
|
+
readonly tools: ReadonlyArray<RivusResolvedToolDescriptor>;
|
|
261
|
+
readonly toolGrantSet: RivusToolGrantSet;
|
|
262
|
+
}
|
|
263
|
+
declare class InvalidRivusPlugin extends Error {
|
|
264
|
+
readonly name = "InvalidRivusPlugin";
|
|
265
|
+
}
|
|
266
|
+
//#endregion
|
|
267
|
+
//#region src/testing/rivus-plugin-testkit.d.ts
|
|
268
|
+
interface RivusPluginLifecycleProbe {
|
|
269
|
+
activate(): Promise<{
|
|
270
|
+
readonly dispose: () => Promise<void> | void;
|
|
271
|
+
readonly activeResources: () => number;
|
|
272
|
+
}>;
|
|
273
|
+
}
|
|
274
|
+
interface RivusPluginConformanceInput {
|
|
275
|
+
readonly plugin: RivusPlugin;
|
|
276
|
+
readonly deployment: RivusAgentDeployment;
|
|
277
|
+
readonly lifecycle?: RivusPluginLifecycleProbe;
|
|
278
|
+
}
|
|
279
|
+
interface RivusPluginConformanceReport {
|
|
280
|
+
readonly pluginId: string;
|
|
281
|
+
readonly profileId: string;
|
|
282
|
+
readonly profileRevision: string;
|
|
283
|
+
readonly toolIds: ReadonlyArray<string>;
|
|
284
|
+
}
|
|
285
|
+
declare class RivusPluginConformanceError extends Error {
|
|
286
|
+
readonly name = "RivusPluginConformanceError";
|
|
287
|
+
}
|
|
288
|
+
declare function assertRivusPluginConforms(input: RivusPluginConformanceInput): Promise<RivusPluginConformanceReport>;
|
|
289
|
+
declare function createFakeRivusPlugin(): RivusPlugin;
|
|
290
|
+
//#endregion
|
|
291
|
+
export { RivusToolExecutionContext as A, AgentMemorySnapshot as B, RivusPluginCatalogSnapshot as C, RivusSkillDescriptor as D, RivusResolvedToolDescriptor as E, RivusToolInputRejected as F, MemoryScope as G, MemoryBinding as H, RivusToolRisk as I, RIVUS_MEMORY_TOOL_PLUGIN_ID as J, MemoryState as K, requiresToolApproval as L, RivusToolFactoryContext as M, RivusToolGrantSet as N, RivusSkillGrantSet as O, RivusToolIdempotency as P, restrictMemoryScopesForAudience as Q, AgentMemoryAuthority as R, RivusPluginCatalog as S, RivusPluginRegistry as T, MemoryInvocationAudience as U, MEMORY_SCOPES as V, MemoryRecord as W, createMemoryNamespace as X, RIVUS_MEMORY_TOOL_VERSION as Y, createRivusMemoryToolContract as Z, RivusAutomationInput as _, assertRivusPluginConforms as a, RivusHostToolDescriptor as b, RIVUS_PLUGIN_API_VERSION as c, RegisteredRivusPlugin as d, RegisteredRivusSkill as f, RivusAgentProfile as g, RivusAgentDeployment as h, RivusPluginLifecycleProbe as i, RivusToolExecutor as j, RivusToolDescriptor as k, RegisteredRivusAgentProfile as l, ResolvedRivusAgentDefinition as m, RivusPluginConformanceInput as n, createFakeRivusPlugin as o, RegisteredRivusTool as p, RIVUS_MEMORY_TOOL_ID as q, RivusPluginConformanceReport as r, InvalidRivusPlugin as s, RivusPluginConformanceError as t, RegisteredRivusAutomation as u, RivusAutomationTemplate as v, RivusPluginManifest as w, RivusPlugin as x, RivusAutomationTickContext as y, AgentMemoryIdentity as z };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { n as resolveRivusAgentDefinition, t as createRivusPluginCatalog } from "./rivus-plugin-registry.js";
|
|
2
|
+
//#region src/testing/rivus-plugin-testkit.ts
|
|
3
|
+
var RivusPluginConformanceError = class extends Error {
|
|
4
|
+
name = "RivusPluginConformanceError";
|
|
5
|
+
};
|
|
6
|
+
async function assertRivusPluginConforms(input) {
|
|
7
|
+
const catalog = createRivusPluginCatalog();
|
|
8
|
+
catalog.registerPlugin(input.plugin);
|
|
9
|
+
const resolved = resolveRivusAgentDefinition(catalog, input.deployment);
|
|
10
|
+
const requested = new Set(input.deployment.tools.allow);
|
|
11
|
+
if (resolved.toolGrantSet.toolIds.some((id) => !requested.has(id))) throw new RivusPluginConformanceError("resolved ToolGrantSet expanded beyond deployment request");
|
|
12
|
+
if (input.lifecycle) {
|
|
13
|
+
const lifecycle = await input.lifecycle.activate();
|
|
14
|
+
await lifecycle.dispose();
|
|
15
|
+
if (lifecycle.activeResources() !== 0) throw new RivusPluginConformanceError("plugin dispose leaked active resources");
|
|
16
|
+
}
|
|
17
|
+
return Object.freeze({
|
|
18
|
+
pluginId: input.plugin.manifest.id,
|
|
19
|
+
profileId: resolved.profileId,
|
|
20
|
+
profileRevision: resolved.profileRevision,
|
|
21
|
+
toolIds: resolved.toolGrantSet.toolIds
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
function createFakeRivusPlugin() {
|
|
25
|
+
return {
|
|
26
|
+
manifest: {
|
|
27
|
+
apiVersion: "1",
|
|
28
|
+
id: "fake-plugin",
|
|
29
|
+
version: "1.0.0"
|
|
30
|
+
},
|
|
31
|
+
register: (registry) => {
|
|
32
|
+
registry.registerTool({
|
|
33
|
+
createExecutor: () => ({ execute: async () => ({ ok: true }) }),
|
|
34
|
+
description: "Read fake data",
|
|
35
|
+
digest: "sha256:fake-read",
|
|
36
|
+
id: "fake-plugin/read",
|
|
37
|
+
idempotency: "supported",
|
|
38
|
+
inputSchema: { type: "object" },
|
|
39
|
+
risk: "observe",
|
|
40
|
+
version: "1.0.0"
|
|
41
|
+
});
|
|
42
|
+
registry.registerSkill({
|
|
43
|
+
content: "Use only fake data.",
|
|
44
|
+
digest: "sha256:fake-skill",
|
|
45
|
+
id: "fake-plugin/read-skill",
|
|
46
|
+
title: "Fake read",
|
|
47
|
+
version: "1.0.0"
|
|
48
|
+
});
|
|
49
|
+
registry.registerAgentProfile({
|
|
50
|
+
displayName: "Fake Profile",
|
|
51
|
+
id: "fake-profile",
|
|
52
|
+
memory: { scopes: ["agent-private"] },
|
|
53
|
+
model: { provider: "fake" },
|
|
54
|
+
skills: { allow: ["fake-plugin/read-skill"] },
|
|
55
|
+
systemPrompt: "Read fake data.",
|
|
56
|
+
tools: { allow: ["fake-plugin/read"] }
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
//#endregion
|
|
62
|
+
export { assertRivusPluginConforms as n, createFakeRivusPlugin as r, RivusPluginConformanceError as t };
|