@rivus/agent 0.14.3 → 0.15.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.
Files changed (40) hide show
  1. package/README.md +1 -1
  2. package/dist/acp.js +1 -2
  3. package/dist/bootstrap/pi-feishu.d.ts +2 -2
  4. package/dist/bootstrap/pi-feishu.js +4119 -389
  5. package/dist/chunks/agent-loop.d.ts +55 -300
  6. package/dist/chunks/agent-loop.js +3 -1123
  7. package/dist/chunks/background-session-authority.js +230 -0
  8. package/dist/chunks/background-session-control-input.js +51 -0
  9. package/dist/chunks/background-session-service.d.ts +382 -0
  10. package/dist/chunks/index.d.ts +1294 -515
  11. package/dist/chunks/pi-tool-proxy.d.ts +22 -90
  12. package/dist/chunks/pi.js +60 -20
  13. package/dist/chunks/rivus-agent-definition-resolver.js +508 -0
  14. package/dist/chunks/rivus-daemon-cli.js +3004 -3164
  15. package/dist/chunks/rivus-model-management-wire.js +344 -0
  16. package/dist/chunks/rivus-plugin-testkit.d.ts +175 -2
  17. package/dist/chunks/rivus-plugin-testkit.js +11 -4
  18. package/dist/chunks/rivus-skill.d.ts +95 -0
  19. package/dist/chunks/rivus-tool.js +158 -0
  20. package/dist/chunks/sha256-digest.js +2 -7
  21. package/dist/chunks/src.js +13402 -8264
  22. package/dist/cli.js +901 -698
  23. package/dist/index.d.ts +7 -8
  24. package/dist/index.js +8 -9
  25. package/dist/mcp.d.ts +46 -7
  26. package/dist/mcp.js +145 -19
  27. package/dist/pi.d.ts +5 -4
  28. package/dist/pi.js +1 -1
  29. package/examples/pi-feishu-deployment.bootstrap.ts +557 -462
  30. package/package.json +9 -7
  31. package/skills/runtime-management/SKILL.md +61 -0
  32. package/dist/chunks/api.d.ts +0 -70
  33. package/dist/chunks/api.js +0 -471
  34. package/dist/chunks/api2.d.ts +0 -387
  35. package/dist/chunks/api2.js +0 -1331
  36. package/dist/chunks/api3.d.ts +0 -402
  37. package/dist/chunks/module.js +0 -267
  38. package/dist/chunks/pi-skill-tool.js +0 -460
  39. package/dist/chunks/spi.d.ts +0 -1
  40. package/dist/chunks/spi.js +0 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rivus/agent",
3
- "version": "0.14.3",
3
+ "version": "0.15.0",
4
4
  "description": "A local agent daemon core built around a usable agent harness and domain events.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -50,7 +50,8 @@
50
50
  "types": "./dist/bootstrap/pi-feishu.d.ts",
51
51
  "import": "./dist/bootstrap/pi-feishu.js"
52
52
  },
53
- "./plugin/starter": "./examples/rivus-starter.plugin.mjs"
53
+ "./plugin/starter": "./examples/rivus-starter.plugin.mjs",
54
+ "./skills/runtime-management/SKILL.md": "./skills/runtime-management/SKILL.md"
54
55
  },
55
56
  "files": [
56
57
  "dist",
@@ -58,7 +59,8 @@
58
59
  "examples/*.bootstrap.ts",
59
60
  "examples/*.json",
60
61
  "README.md",
61
- "LICENSE"
62
+ "LICENSE",
63
+ "skills/runtime-management/SKILL.md"
62
64
  ],
63
65
  "publishConfig": {
64
66
  "access": "public"
@@ -75,23 +77,23 @@
75
77
  "lint:fix": "vp lint --fix",
76
78
  "package-api:update": "vp pack && node scripts/package-api-report.mjs --write",
77
79
  "package:check": "node scripts/check-npm-package.mjs",
78
- "prepublishOnly": "npm run check",
80
+ "prepublishOnly": "npm run check && npm run audit",
79
81
  "release:check": "node scripts/check-npm-release.mjs",
80
82
  "test": "vp test",
81
83
  "test:feishu:offline": "node scripts/run-feishu-offline-tests.mjs",
82
84
  "test:coverage": "vp test --coverage",
83
85
  "test:watch": "vp test watch",
84
86
  "typecheck": "vp check --no-fmt --no-lint",
85
- "check": "vp check && vp test --coverage && vp run duplicates && vp pack && vp run package:check && vp run audit && ./scripts/check-repository.sh",
87
+ "check": "vp check && vp test --coverage && vp run duplicates && vp pack && vp run package:check && ./scripts/check-repository.sh",
86
88
  "duplicates": "jscpd src examples --min-lines 6 --min-tokens 40 --threshold 0 --reporters console --ignore '**/*.test.ts,**/*.test.mjs' --format 'typescript,javascript,json'",
87
89
  "version-packages": "changeset version && npm install --package-lock-only --ignore-scripts",
88
- "version-packages:ci": "npm run version-packages && npm run check"
90
+ "version-packages:ci": "npm run version-packages && npm run check && npm run audit"
89
91
  },
90
92
  "dependencies": {
91
93
  "@earendil-works/pi-coding-agent": "0.84.4",
92
94
  "@larksuiteoapi/node-sdk": "1.71.1",
93
95
  "@opentelemetry/api": "^1.9.1",
94
- "@opentelemetry/exporter-trace-otlp-proto": "^0.220.0",
96
+ "@opentelemetry/exporter-trace-otlp-proto": "^0.221.0",
95
97
  "@opentelemetry/resources": "^2.9.0",
96
98
  "@opentelemetry/sdk-trace-base": "^2.9.0",
97
99
  "@opentelemetry/sdk-trace-node": "^2.9.0",
@@ -0,0 +1,61 @@
1
+ ---
2
+ name: runtime-management
3
+ description: Use when the user asks what model is active, requests a persistent model change, or asks to restore the previous model; invoke the installed Rivus CLI and report the returned status.
4
+ ---
5
+
6
+ # Runtime management
7
+
8
+ Use the installed `rivus` executable for the personal Home's model management. The CLI is the source of truth for the
9
+ current revision and the durable request status. It validates an exact `provider/model` submitted by the Host; it does
10
+ not enumerate the supported model catalog. Use a model identifier already confirmed by the Home configuration,
11
+ deployment, the provider's official documentation, or a trusted Host response. Do not guess aliases or infer an
12
+ identifier from a model family name. When the identifier remains ambiguous, ask the user for the exact value; the Host
13
+ performs the final validation before accepting it.
14
+
15
+ ## Query
16
+
17
+ Run:
18
+
19
+ ```bash
20
+ rivus model status --json
21
+ ```
22
+
23
+ Read `current`, `source`, `revision`, and `pending` from the JSON response. If a request is in progress, keep its
24
+ `requestId` and `reason` visible to the user. Query a known request with:
25
+
26
+ ```bash
27
+ rivus model status --request <request-id> --json
28
+ ```
29
+
30
+ ## Set a default model
31
+
32
+ Use the exact `provider/model` value confirmed by the Host. First obtain the current `revision`, then submit one request
33
+ with a fresh request id:
34
+
35
+ ```bash
36
+ rivus model set --model <provider/model> --expected-revision <revision> --request <request-id> --json
37
+ ```
38
+
39
+ The first response confirms receipt. When the response is `pending`, report its `requestId` and finish the current Run.
40
+ The Host completes validation and activation across the safe boundary and sends the final notification. A later Run can
41
+ query the request to determine whether the final state is `applied`, `failed`, `restored`, or `recovery-required`.
42
+ Keep the same request id after a disconnect instead of submitting the change again with a new id.
43
+
44
+ ## Restore the previous model
45
+
46
+ Use the same revision and request rules:
47
+
48
+ ```bash
49
+ rivus model rollback --expected-revision <revision> --request <request-id> --json
50
+ ```
51
+
52
+ If there is no previous selection, or the provider no longer supports it, report the returned limitation. Restoring a
53
+ model does not undo messages, memory, or completed business effects.
54
+
55
+ ## Trust and scope
56
+
57
+ Only a trusted Host Run can authorize `set` and `rollback`. A local client without that context can read diagnostics but
58
+ cannot grant itself permission. Do not add identity, owner, Home, credential, or authorization fields to a command.
59
+
60
+ When a command reports `failed` or `recovery-required`, preserve the returned error code and request id. Do not infer
61
+ success from process exit code `0`; inspect the JSON business status.
@@ -1,70 +0,0 @@
1
- import { Effect } from "effect";
2
-
3
- //#region src/modules/memory/application/compaction/compaction-service.d.ts
4
- interface CompactionInput {
5
- readonly tenantId: string;
6
- readonly agentId: string;
7
- readonly instanceId: string;
8
- readonly conversationId: string;
9
- readonly profileRevision: string;
10
- readonly watermark: number;
11
- readonly transcript: ReadonlyArray<string>;
12
- }
13
- interface CompactionSnapshot extends Omit<CompactionInput, "transcript"> {
14
- readonly id: string;
15
- readonly summary: string;
16
- }
17
- declare class CompactionError extends Error {
18
- readonly name = "CompactionError";
19
- }
20
- //#endregion
21
- //#region src/modules/memory/domain/scope/memory-scope.d.ts
22
- declare const MEMORY_SCOPES: readonly ["conversation", "agent-private", "project", "shared-user-profile"];
23
- type MemoryScope = (typeof MEMORY_SCOPES)[number];
24
- type MemoryInvocationAudience = "group" | "private";
25
- interface AgentMemoryIdentity {
26
- readonly audience: MemoryInvocationAudience;
27
- readonly conversationId?: string;
28
- readonly projectId?: string;
29
- readonly subjectId: string;
30
- readonly tenantId: string;
31
- }
32
- interface AgentMemoryAuthority extends AgentMemoryIdentity {
33
- readonly scopes: ReadonlyArray<MemoryScope>;
34
- }
35
- interface MemoryBinding {
36
- readonly agentId: string;
37
- readonly conversationId?: string;
38
- readonly projectId?: string;
39
- readonly scope: MemoryScope;
40
- readonly subjectId: string;
41
- readonly tenantId: string;
42
- }
43
- declare function createMemoryNamespace(binding: MemoryBinding): string;
44
- declare function restrictMemoryScopesForAudience(scopes: ReadonlyArray<MemoryScope>, audience: MemoryInvocationAudience): ReadonlyArray<MemoryScope>;
45
- //#endregion
46
- //#region src/modules/memory/domain/record/memory-record.d.ts
47
- type MemoryState = "proposed" | "confirmed" | "superseded" | "tombstoned";
48
- interface MemoryRecord {
49
- readonly content: string;
50
- readonly conversationSafe: boolean;
51
- readonly id: string;
52
- readonly revision: number;
53
- readonly scope: MemoryScope;
54
- readonly state: MemoryState;
55
- readonly tombstoneReason?: string;
56
- }
57
- interface AgentMemorySnapshot {
58
- readonly binding: MemoryBinding;
59
- readonly record: MemoryRecord;
60
- }
61
- //#endregion
62
- //#region src/modules/memory/application/storage/agent-memory-service.d.ts
63
- interface MemorySearchQuery {
64
- readonly query: string;
65
- }
66
- declare class AgentMemoryError extends Error {
67
- readonly name = "AgentMemoryError";
68
- }
69
- //#endregion
70
- export { MemoryState as a, MEMORY_SCOPES as c, MemoryScope as d, createMemoryNamespace as f, CompactionSnapshot as g, CompactionInput as h, MemoryRecord as i, MemoryBinding as l, CompactionError as m, MemorySearchQuery as n, AgentMemoryAuthority as o, restrictMemoryScopesForAudience as p, AgentMemorySnapshot as r, AgentMemoryIdentity as s, AgentMemoryError as t, MemoryInvocationAudience as u };
@@ -1,471 +0,0 @@
1
- import { t as createSha256Digest } from "./sha256-digest.js";
2
- import { Effect } from "effect";
3
- //#region src/modules/memory/application/compaction/compaction-service.ts
4
- var CompactionError = class extends Error {
5
- name = "CompactionError";
6
- };
7
- function createEffectCompactionService(options) {
8
- const candidates = /* @__PURE__ */ new Map();
9
- const committed = /* @__PURE__ */ new Map();
10
- const serial = Effect.unsafeMakeSemaphore(1);
11
- return {
12
- createCandidate: (input) => {
13
- const safeInput = Object.freeze({
14
- agentId: input.agentId,
15
- conversationId: input.conversationId,
16
- instanceId: input.instanceId,
17
- profileRevision: input.profileRevision,
18
- tenantId: input.tenantId,
19
- transcript: Object.freeze([...input.transcript]),
20
- watermark: input.watermark
21
- });
22
- return options.compactor.compact(safeInput).pipe(Effect.map((summary) => Object.freeze({
23
- agentId: input.agentId,
24
- conversationId: input.conversationId,
25
- id: `compaction:${options.identity.next()}`,
26
- instanceId: input.instanceId,
27
- profileRevision: input.profileRevision,
28
- summary,
29
- tenantId: input.tenantId,
30
- watermark: input.watermark
31
- })), Effect.tap((candidate) => Effect.sync(() => candidates.set(candidate.id, candidate))));
32
- },
33
- commit: (candidateId) => serial.withPermits(1)(Effect.suspend(() => {
34
- const candidate = candidates.get(candidateId);
35
- if (!candidate) return Effect.fail(new CompactionError(`unknown compaction candidate: ${candidateId}`));
36
- const key = `${candidate.instanceId}/${candidate.conversationId}`;
37
- const current = committed.get(key);
38
- if (current && current.watermark >= candidate.watermark) return Effect.fail(new CompactionError("compaction watermark conflict"));
39
- return Effect.sync(() => {
40
- committed.set(key, candidate);
41
- candidates.delete(candidateId);
42
- return candidate;
43
- });
44
- })),
45
- current: (instanceId, conversationId) => committed.get(`${instanceId}/${conversationId}`)
46
- };
47
- }
48
- //#endregion
49
- //#region src/modules/memory/domain/record/memory-record.ts
50
- var MemoryRecordError = class extends Error {
51
- name = "MemoryRecordError";
52
- };
53
- function proposeMemory(scope, contentInput, id) {
54
- const content = contentInput.trim();
55
- if (!content) throw new MemoryRecordError("memory content must not be empty");
56
- if (!id.trim()) throw new MemoryRecordError("memory id must not be empty");
57
- return Object.freeze({
58
- content,
59
- conversationSafe: false,
60
- id,
61
- revision: 1,
62
- scope,
63
- state: "proposed"
64
- });
65
- }
66
- function confirmMemory(current, input) {
67
- requireRevision(current, input.expectedRevision);
68
- if (current.state !== "proposed") throw new MemoryRecordError("only proposed memory can be confirmed");
69
- return Object.freeze({
70
- ...current,
71
- conversationSafe: input.conversationSafe ?? false,
72
- revision: current.revision + 1,
73
- state: "confirmed"
74
- });
75
- }
76
- function forgetMemory(current, input) {
77
- requireRevision(current, input.expectedRevision);
78
- if (current.state === "tombstoned") throw new MemoryRecordError(`memory is already forgotten: ${current.id}`);
79
- const reason = input.reason?.trim();
80
- return Object.freeze({
81
- ...current,
82
- revision: current.revision + 1,
83
- state: "tombstoned",
84
- ...reason ? { tombstoneReason: reason } : {}
85
- });
86
- }
87
- function isVisibleMemory(record) {
88
- if (record.state === "tombstoned" || record.state === "superseded") return false;
89
- return record.scope !== "shared-user-profile" && record.scope !== "project" || record.state === "confirmed";
90
- }
91
- function isValidMemoryTransition(previous, next) {
92
- if (!sameBinding(previous.binding, next.binding) || previous.record.id !== next.record.id || previous.record.content !== next.record.content || previous.record.scope !== next.record.scope || next.record.revision !== previous.record.revision + 1) return false;
93
- switch (previous.record.state) {
94
- case "proposed": return (next.record.state === "confirmed" || next.record.state === "tombstoned") && (!next.record.conversationSafe || next.record.state === "confirmed");
95
- case "confirmed":
96
- case "superseded": return next.record.state === "tombstoned" && next.record.conversationSafe === previous.record.conversationSafe;
97
- case "tombstoned": return false;
98
- }
99
- }
100
- function sameBinding(left, right) {
101
- return left.agentId === right.agentId && left.conversationId === right.conversationId && left.projectId === right.projectId && left.scope === right.scope && left.subjectId === right.subjectId && left.tenantId === right.tenantId;
102
- }
103
- function requireRevision(current, expectedRevision) {
104
- if (current.revision !== expectedRevision) throw new MemoryRecordError("memory revision conflict");
105
- }
106
- //#endregion
107
- //#region src/modules/memory/domain/scope/memory-scope.ts
108
- const MEMORY_SCOPES = [
109
- "conversation",
110
- "agent-private",
111
- "project",
112
- "shared-user-profile"
113
- ];
114
- var MemoryScopeError = class extends Error {
115
- name = "MemoryScopeError";
116
- };
117
- function normalizeMemoryBinding(binding) {
118
- const tenantId = binding.tenantId.trim();
119
- const agentId = binding.agentId.trim();
120
- const subjectId = binding.subjectId.trim();
121
- if (!tenantId || !agentId || !subjectId || !MEMORY_SCOPES.includes(binding.scope)) throw new MemoryScopeError("Memory binding requires trusted tenant, Agent, subject, and scope");
122
- const conversationId = binding.conversationId?.trim();
123
- const projectId = binding.projectId?.trim();
124
- if (binding.scope === "conversation" && !conversationId) throw new MemoryScopeError("Conversation Memory requires a trusted conversation identity");
125
- if (binding.scope !== "conversation" && conversationId) throw new MemoryScopeError("Only Conversation Memory accepts a conversation identity");
126
- if (binding.scope === "project" && !projectId) throw new MemoryScopeError("Project Memory requires a trusted Project Space identity");
127
- if (binding.scope !== "project" && projectId) throw new MemoryScopeError("Only Project Memory accepts a Project Space identity");
128
- return Object.freeze({
129
- agentId,
130
- ...conversationId ? { conversationId } : {},
131
- ...projectId ? { projectId } : {},
132
- scope: binding.scope,
133
- subjectId,
134
- tenantId
135
- });
136
- }
137
- function createMemoryNamespace(binding) {
138
- const encode = (value) => encodeURIComponent(value);
139
- switch (binding.scope) {
140
- case "conversation": return [
141
- binding.tenantId,
142
- binding.agentId,
143
- binding.subjectId,
144
- binding.conversationId ?? "",
145
- binding.scope
146
- ].map(encode).join("/");
147
- case "agent-private": return [
148
- binding.tenantId,
149
- binding.agentId,
150
- binding.subjectId,
151
- binding.scope
152
- ].map(encode).join("/");
153
- case "project": return [
154
- binding.tenantId,
155
- binding.agentId,
156
- binding.projectId ?? "",
157
- binding.scope
158
- ].map(encode).join("/");
159
- case "shared-user-profile": return [
160
- binding.tenantId,
161
- binding.subjectId,
162
- binding.scope
163
- ].map(encode).join("/");
164
- }
165
- }
166
- function restrictMemoryScopesForAudience(scopes, audience) {
167
- return audience === "group" ? scopes.filter((scope) => scope === "conversation" || scope === "project") : [...scopes];
168
- }
169
- //#endregion
170
- //#region src/modules/memory/application/storage/agent-memory-repository.ts
171
- var AgentMemoryRepositoryConflict = class extends Error {
172
- name = "AgentMemoryRepositoryConflict";
173
- };
174
- //#endregion
175
- //#region src/modules/memory/application/storage/agent-memory-service.ts
176
- var AgentMemoryError = class extends Error {
177
- name = "AgentMemoryError";
178
- };
179
- function createMemoryService(options) {
180
- return { bind: (bindingInput) => {
181
- let binding;
182
- try {
183
- binding = normalizeMemoryBinding(bindingInput);
184
- } catch (error) {
185
- throw asAgentMemoryError(error);
186
- }
187
- const update = (id, transition) => Effect.gen(function* () {
188
- const current = yield* options.repository.get(binding, id);
189
- if (!current) return yield* Effect.fail(new AgentMemoryError(`memory not found: ${id}`));
190
- const record = yield* Effect.try({
191
- catch: asAgentMemoryError,
192
- try: () => transition(current)
193
- });
194
- return yield* options.repository.save({
195
- binding,
196
- record
197
- }).pipe(Effect.mapError(mapRepositoryConflict));
198
- });
199
- const handle = {
200
- namespace: createMemoryNamespace(binding),
201
- scope: binding.scope,
202
- confirm: (input) => update(input.id, (current) => confirmMemory(current, {
203
- expectedRevision: input.expectedRevision,
204
- ...input.conversationSafe === void 0 ? {} : { conversationSafe: input.conversationSafe }
205
- })),
206
- forgetRequest: (input) => update(input.id, (current) => forgetMemory(current, {
207
- expectedRevision: input.expectedRevision,
208
- ...input.reason === void 0 ? {} : { reason: input.reason }
209
- })),
210
- inspect: (id) => options.repository.get(binding, id),
211
- propose: (input) => Effect.gen(function* () {
212
- const id = yield* Effect.try({
213
- catch: (error) => error,
214
- try: () => options.identity.next()
215
- });
216
- const record = yield* Effect.try({
217
- catch: asAgentMemoryError,
218
- try: () => proposeMemory(binding.scope, input.content, `memory:${id}`)
219
- });
220
- return yield* options.repository.save({
221
- binding,
222
- record
223
- }).pipe(Effect.mapError(mapRepositoryConflict));
224
- }),
225
- read: (id) => options.repository.get(binding, id).pipe(Effect.map((record) => record && isVisibleMemory(record) ? record : void 0)),
226
- search: ({ query }) => options.repository.list(binding).pipe(Effect.map((records) => {
227
- const normalized = query.trim().toLowerCase();
228
- return records.filter((record) => isVisibleMemory(record) && record.content.toLowerCase().includes(normalized));
229
- }))
230
- };
231
- return Object.freeze(handle);
232
- } };
233
- }
234
- function mapRepositoryConflict(error) {
235
- return error instanceof AgentMemoryRepositoryConflict ? new AgentMemoryError("memory revision conflict") : error;
236
- }
237
- function asAgentMemoryError(error) {
238
- if (error instanceof AgentMemoryError) return error;
239
- if (error instanceof MemoryRecordError || error instanceof MemoryScopeError) return new AgentMemoryError(error.message);
240
- return new AgentMemoryError(error instanceof Error ? error.message : String(error));
241
- }
242
- //#endregion
243
- //#region src/modules/agent-catalog/domain/plugin/rivus-plugin.ts
244
- const RIVUS_PLUGIN_API_VERSION = "1";
245
- var InvalidRivusPlugin = class extends Error {
246
- name = "InvalidRivusPlugin";
247
- };
248
- //#endregion
249
- //#region src/modules/agent-catalog/domain/runtime-tool/rivus-runtime-tool.ts
250
- const RIVUS_RUNTIME_TOOL_IDS = Object.freeze([
251
- "read",
252
- "bash",
253
- "edit",
254
- "write",
255
- "grep",
256
- "find",
257
- "ls"
258
- ]);
259
- function isRivusRuntimeToolId(value) {
260
- return RIVUS_RUNTIME_TOOL_IDS.includes(value);
261
- }
262
- //#endregion
263
- //#region src/modules/agent-catalog/domain/tool/rivus-tool.ts
264
- var RivusToolInputRejected = class extends Error {
265
- name = "RivusToolInputRejected";
266
- };
267
- //#endregion
268
- //#region src/modules/agent-catalog/domain/policy/rivus-catalog-policy.ts
269
- function validateRivusPluginManifest(manifest) {
270
- validateRivusCatalogIdentifier(manifest.id, "plugin");
271
- if (manifest.apiVersion !== "1") throw new InvalidRivusPlugin(`unsupported plugin API version ${manifest.apiVersion}; expected 1`);
272
- if (manifest.version.trim() === "") throw new InvalidRivusPlugin("plugin version must not be empty");
273
- }
274
- function validateRivusCatalogIdentifier(id, kind) {
275
- if (!/^[a-z0-9][a-z0-9._/-]*$/.test(id) || id.includes("*") || id.includes("//")) throw new InvalidRivusPlugin(`invalid ${kind} id: ${id}`);
276
- }
277
- function uniqueRivusCatalogIds(ids, label) {
278
- const result = /* @__PURE__ */ new Set();
279
- for (const id of ids) {
280
- if (id.includes("*")) throw new InvalidRivusPlugin(`${label} does not support wildcard id: ${id}`);
281
- validateRivusCatalogIdentifier(id, label);
282
- if (result.has(id)) throw new InvalidRivusPlugin(`duplicate id in ${label}: ${id}`);
283
- result.add(id);
284
- }
285
- return [...result];
286
- }
287
- function validateRivusCatalogReferences(ids, available, owner, kind) {
288
- for (const id of uniqueRivusCatalogIds(ids, `${owner} ${kind} references`)) if (!available.has(id)) throw new InvalidRivusPlugin(`${owner} references unknown ${kind}: ${id}`);
289
- }
290
- function validateRivusMemoryScopes(scopes, owner) {
291
- const result = /* @__PURE__ */ new Set();
292
- for (const scope of scopes) {
293
- if (!MEMORY_SCOPES.includes(scope)) throw new InvalidRivusPlugin(`${owner} references unsupported Memory scope: ${String(scope)}`);
294
- if (result.has(scope)) throw new InvalidRivusPlugin(`${owner} contains duplicate Memory scope: ${scope}`);
295
- result.add(scope);
296
- }
297
- return [...result];
298
- }
299
- function uniqueRivusRuntimeToolIds(ids, owner) {
300
- const result = /* @__PURE__ */ new Set();
301
- for (const id of ids) {
302
- if (typeof id === "string" && id.includes("*")) throw new InvalidRivusPlugin(`${owner} does not support wildcard Runtime Tool: ${id}`);
303
- if (typeof id !== "string" || !isRivusRuntimeToolId(id)) throw new InvalidRivusPlugin(`${owner} references unknown Runtime Tool: ${String(id)}`);
304
- if (result.has(id)) throw new InvalidRivusPlugin(`${owner} contains duplicate Runtime Tool: ${id}`);
305
- result.add(id);
306
- }
307
- return [...result];
308
- }
309
- //#endregion
310
- //#region src/platform/values/deep-freeze.ts
311
- function deepFreeze(value) {
312
- if (value !== null && typeof value === "object" && !Object.isFrozen(value)) {
313
- Object.freeze(value);
314
- for (const child of Object.values(value)) deepFreeze(child);
315
- }
316
- return value;
317
- }
318
- //#endregion
319
- //#region src/modules/agent-catalog/application/catalog/rivus-plugin-catalog.ts
320
- function createRivusPluginCatalog() {
321
- const plugins = /* @__PURE__ */ new Map();
322
- const profiles = /* @__PURE__ */ new Map();
323
- const tools = /* @__PURE__ */ new Map();
324
- const skills = /* @__PURE__ */ new Map();
325
- const automations = /* @__PURE__ */ new Map();
326
- return {
327
- registerPlugin: (plugin) => {
328
- validateRivusPluginManifest(plugin.manifest);
329
- rejectDuplicate(plugins, plugin.manifest.id, "plugin");
330
- const pendingProfiles = [];
331
- const pendingTools = [];
332
- const pendingSkills = [];
333
- const pendingAutomations = [];
334
- const pendingIds = /* @__PURE__ */ new Set();
335
- const register = (kind, definition, catalog, destination, namespaced) => {
336
- validateRivusCatalogIdentifier(definition.id, kind);
337
- if (namespaced && !definition.id.startsWith(`${plugin.manifest.id}/`)) throw new InvalidRivusPlugin(`${kind} id ${definition.id} must use plugin namespace ${plugin.manifest.id}/`);
338
- const key = `${kind}:${definition.id}`;
339
- if (pendingIds.has(key) || catalog.has(definition.id)) throw new InvalidRivusPlugin(`duplicate ${kind} id: ${definition.id}`);
340
- pendingIds.add(key);
341
- destination.push(deepFreeze({
342
- ...definition,
343
- pluginId: plugin.manifest.id
344
- }));
345
- };
346
- plugin.register({
347
- registerAgentProfile: (profile) => register("profile", profile, profiles, pendingProfiles, false),
348
- registerAutomation: (automation) => register("automation", automation, automations, pendingAutomations, true),
349
- registerSkill: (skill) => register("skill", skill, skills, pendingSkills, true),
350
- registerTool: (tool) => register("tool", tool, tools, pendingTools, true)
351
- });
352
- const availableToolIds = /* @__PURE__ */ new Set([...tools.keys(), ...pendingTools.map(({ id }) => id)]);
353
- const availableSkillIds = /* @__PURE__ */ new Set([...skills.keys(), ...pendingSkills.map(({ id }) => id)]);
354
- const availableProfileIds = /* @__PURE__ */ new Set([...profiles.keys(), ...pendingProfiles.map(({ id }) => id)]);
355
- for (const profile of pendingProfiles) {
356
- validateRivusMemoryScopes(profile.memory.scopes, `profile ${profile.id}`);
357
- uniqueRivusRuntimeToolIds(profile.runtimeTools?.allow ?? [], `profile ${profile.id}`);
358
- validateRivusCatalogReferences(profile.tools.allow, availableToolIds, `profile ${profile.id}`, "tool");
359
- validateRivusCatalogReferences(profile.skills.allow, availableSkillIds, `profile ${profile.id}`, "skill");
360
- }
361
- for (const automation of pendingAutomations) {
362
- if (!availableProfileIds.has(automation.profileId)) throw new InvalidRivusPlugin(`automation ${automation.id} references unknown profile: ${automation.profileId}`);
363
- validateRivusCatalogReferences(automation.requestedToolIds, availableToolIds, `automation ${automation.id}`, "tool");
364
- validateRivusCatalogReferences(automation.requestedSkillIds, availableSkillIds, `automation ${automation.id}`, "skill");
365
- }
366
- plugins.set(plugin.manifest.id, deepFreeze({ ...plugin.manifest }));
367
- for (const profile of pendingProfiles) profiles.set(profile.id, profile);
368
- for (const tool of pendingTools) tools.set(tool.id, tool);
369
- for (const skill of pendingSkills) skills.set(skill.id, skill);
370
- for (const automation of pendingAutomations) automations.set(automation.id, automation);
371
- },
372
- snapshot: () => deepFreeze({
373
- automations: [...automations.values()],
374
- plugins: [...plugins.values()],
375
- profiles: [...profiles.values()],
376
- skills: [...skills.values()],
377
- tools: [...tools.values()]
378
- })
379
- };
380
- }
381
- function rejectDuplicate(map, id, kind) {
382
- if (map.has(id)) throw new InvalidRivusPlugin(`duplicate ${kind} id: ${id}`);
383
- }
384
- //#endregion
385
- //#region src/modules/agent-catalog/application/resolution/rivus-tool-grant-set.ts
386
- function narrowRivusToolGrantSet(parent, restrictions) {
387
- const toolIds = intersectToolIds([parent.toolIds, ...restrictions]);
388
- return deepFreeze({
389
- revision: createSha256Digest(JSON.stringify({
390
- parentRevision: parent.revision,
391
- toolIds
392
- })),
393
- toolIds
394
- });
395
- }
396
- function intersectRivusToolIds(sets) {
397
- const toolIds = intersectToolIds(sets);
398
- return deepFreeze({
399
- revision: createSha256Digest(JSON.stringify(toolIds)),
400
- toolIds
401
- });
402
- }
403
- function intersectToolIds(sets) {
404
- const [first = [], ...rest] = sets;
405
- return [...new Set(first)].filter((id) => rest.every((set) => set.includes(id))).sort();
406
- }
407
- //#endregion
408
- //#region src/modules/agent-catalog/application/resolution/rivus-agent-grant-restriction.ts
409
- function restrictRivusAgentDefinitionGrants(definition, restriction) {
410
- const toolIds = uniqueIds(restriction.toolIds);
411
- const skillIds = uniqueIds(restriction.skillIds);
412
- const runtimeToolIds = uniqueRuntimeToolIds(restriction.runtimeToolIds);
413
- const memoryScopes = uniqueScopes(restriction.memory.scopes);
414
- const toolsById = new Map(definition.tools.map((tool) => [tool.id, tool]));
415
- const skillsById = new Map(definition.skills.map((skill) => [skill.id, skill]));
416
- const tools = toolIds.map((toolId) => {
417
- const tool = toolsById.get(toolId);
418
- if (!tool) throw new Error(`Agent grant restriction requests ungranted Tool: ${toolId}`);
419
- return tool;
420
- });
421
- const skills = skillIds.map((skillId) => {
422
- const skill = skillsById.get(skillId);
423
- if (!skill) throw new Error(`Agent grant restriction requests ungranted Skill: ${skillId}`);
424
- return skill;
425
- });
426
- for (const scope of memoryScopes) if (!definition.memory.scopes.includes(scope)) throw new Error(`Agent grant restriction requests ungranted Memory scope: ${scope}`);
427
- for (const runtimeToolId of runtimeToolIds) if (!definition.runtimeToolGrantSet.toolIds.includes(runtimeToolId)) throw new Error(`Agent grant restriction requests ungranted Runtime Tool: ${runtimeToolId}`);
428
- if (restriction.memory.tool && !definition.memory.tool) throw new Error("Agent grant restriction cannot enable an ungranted Memory Tool");
429
- const skillGrantSet = deepFreeze({
430
- revision: createSha256Digest(JSON.stringify({
431
- parentRevision: definition.skillGrantSet.revision,
432
- skillIds
433
- })),
434
- skillIds
435
- });
436
- const runtimeToolGrantSet = deepFreeze({
437
- revision: createSha256Digest(JSON.stringify({
438
- parentRevision: definition.runtimeToolGrantSet.revision,
439
- toolIds: runtimeToolIds
440
- })),
441
- toolIds: runtimeToolIds
442
- });
443
- return deepFreeze({
444
- ...definition,
445
- memory: {
446
- scopes: memoryScopes,
447
- tool: restriction.memory.tool
448
- },
449
- runtimeToolGrantSet,
450
- skillGrantSet,
451
- skills,
452
- toolGrantSet: narrowRivusToolGrantSet(definition.toolGrantSet, [toolIds]),
453
- tools
454
- });
455
- }
456
- function uniqueRuntimeToolIds(ids) {
457
- const requested = /* @__PURE__ */ new Set();
458
- for (const id of ids) {
459
- if (!isRivusRuntimeToolId(id)) throw new Error(`Agent grant restriction requests unknown Runtime Tool: ${id}`);
460
- requested.add(id);
461
- }
462
- return RIVUS_RUNTIME_TOOL_IDS.filter((id) => requested.has(id));
463
- }
464
- function uniqueIds(ids) {
465
- return [...new Set(ids)].sort();
466
- }
467
- function uniqueScopes(scopes) {
468
- return [...new Set(scopes)].sort();
469
- }
470
- //#endregion
471
- export { createEffectCompactionService as C, CompactionError as S, AgentMemoryRepositoryConflict as _, deepFreeze as a, restrictMemoryScopesForAudience as b, validateRivusCatalogIdentifier as c, RIVUS_RUNTIME_TOOL_IDS as d, isRivusRuntimeToolId as f, createMemoryService as g, AgentMemoryError as h, createRivusPluginCatalog as i, validateRivusMemoryScopes as l, RIVUS_PLUGIN_API_VERSION as m, intersectRivusToolIds as n, uniqueRivusCatalogIds as o, InvalidRivusPlugin as p, narrowRivusToolGrantSet as r, uniqueRivusRuntimeToolIds as s, restrictRivusAgentDefinitionGrants as t, RivusToolInputRejected as u, MEMORY_SCOPES as v, isValidMemoryTransition as x, createMemoryNamespace as y };