@rivus/agent 0.13.2 → 0.14.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.
Files changed (46) hide show
  1. package/README.md +17 -18
  2. package/dist/acp.d.ts +40 -40
  3. package/dist/acp.js +71 -31
  4. package/dist/bootstrap/pi-feishu.d.ts +20 -0
  5. package/dist/bootstrap/pi-feishu.js +596 -0
  6. package/dist/{agent-loop.d.ts → chunks/agent-loop.d.ts} +293 -44
  7. package/dist/chunks/agent-loop.js +1272 -0
  8. package/dist/chunks/api.d.ts +70 -0
  9. package/dist/chunks/api.js +471 -0
  10. package/dist/{rivus-plugin.d.ts → chunks/api2.d.ts} +271 -120
  11. package/dist/chunks/api2.js +1331 -0
  12. package/dist/chunks/api3.d.ts +402 -0
  13. package/dist/chunks/index.d.ts +3662 -0
  14. package/dist/chunks/module.js +267 -0
  15. package/dist/chunks/pi-skill-tool.js +460 -0
  16. package/dist/chunks/pi-tool-proxy.d.ts +188 -0
  17. package/dist/chunks/pi.js +329 -0
  18. package/dist/{rivus-daemon-cli.js → chunks/rivus-daemon-cli.js} +2197 -1526
  19. package/dist/{rivus-plugin-testkit.d.ts → chunks/rivus-plugin-testkit.d.ts} +1 -1
  20. package/dist/{rivus-plugin-testkit.js → chunks/rivus-plugin-testkit.js} +11 -3
  21. package/dist/chunks/sha256-digest.js +12 -0
  22. package/dist/chunks/spi.d.ts +1 -0
  23. package/dist/chunks/spi.js +2 -0
  24. package/dist/chunks/src.js +9897 -0
  25. package/dist/cli.js +604 -95
  26. package/dist/index.d.ts +8 -3645
  27. package/dist/index.js +9 -10483
  28. package/dist/mcp.d.ts +3 -38
  29. package/dist/mcp.js +4 -114
  30. package/dist/pi.d.ts +95 -9
  31. package/dist/pi.js +3 -146
  32. package/dist/testing/index.d.ts +1 -1
  33. package/dist/testing/index.js +1 -1
  34. package/examples/pi-feishu-deployment.bootstrap.ts +45 -54
  35. package/examples/pi-feishu.bootstrap.ts +53 -37
  36. package/examples/rivus-starter.plugin.mjs +3 -1
  37. package/package.json +12 -14
  38. package/dist/agent-loop.js +0 -121
  39. package/dist/agent-memory.d.ts +0 -100
  40. package/dist/agent-memory.js +0 -114
  41. package/dist/background-session-authority.js +0 -224
  42. package/dist/background-session-input.js +0 -45
  43. package/dist/background-session-service.d.ts +0 -291
  44. package/dist/pi-tool-proxy.d.ts +0 -197
  45. package/dist/rivus-plugin-registry.js +0 -215
  46. package/dist/tool-input-digest.js +0 -128
@@ -0,0 +1,329 @@
1
+ import { l as toEffectAgentLoopInput } from "./agent-loop.js";
2
+ import "./api.js";
3
+ import { h as requiresToolApproval, o as createToolInputDigest, p as createInvocationAuthority } from "./pi-skill-tool.js";
4
+ import { createHash } from "node:crypto";
5
+ import { readFile, realpath, stat } from "node:fs/promises";
6
+ import { isAbsolute, join, relative } from "node:path";
7
+ import { DefaultResourceLoader, SettingsManager, createReadToolDefinition } from "@earendil-works/pi-coding-agent";
8
+ import { realpathSync, statSync } from "node:fs";
9
+ import { Unsafe } from "typebox";
10
+ //#region src/adapters/pi/skills/pi-skill-read-tool.ts
11
+ var ProjectSkillReadDenied = class extends Error {
12
+ name = "ProjectSkillReadDenied";
13
+ };
14
+ function createPiSkillReadTool(options) {
15
+ if (options.skillPaths.length === 0) throw new ProjectSkillReadDenied("Pi Skill read requires a trusted Skill source");
16
+ const allowedSources = options.skillPaths.map((source) => {
17
+ const path = realpathSync(source);
18
+ return Object.freeze({
19
+ directory: statSync(path).isDirectory(),
20
+ path
21
+ });
22
+ });
23
+ return createReadToolDefinition(options.cwd, { operations: {
24
+ access: async (absolutePath) => {
25
+ await stat(await authorize(absolutePath, allowedSources));
26
+ },
27
+ readFile: async (absolutePath) => readFile(await authorize(absolutePath, allowedSources))
28
+ } });
29
+ }
30
+ const createPiProjectSkillReadTool = createPiSkillReadTool;
31
+ function createPiSkillReadTools(options) {
32
+ if (options.skillPaths.length === 0 || options.runtimeToolIds.includes("read")) return [];
33
+ return [createPiSkillReadTool(options)];
34
+ }
35
+ async function authorize(path, sources) {
36
+ const candidate = await realpath(path);
37
+ for (const source of sources) {
38
+ if (!source.directory) {
39
+ if (candidate === source.path) return candidate;
40
+ continue;
41
+ }
42
+ const relation = relative(source.path, candidate);
43
+ if (relation === "" || !relation.startsWith("..") && !isAbsolute(relation)) return candidate;
44
+ }
45
+ throw new ProjectSkillReadDenied("read is restricted to the bound Pi Skill sources");
46
+ }
47
+ //#endregion
48
+ //#region src/adapters/pi/skills/pi-skill-catalog.ts
49
+ var InvalidPiSkillCatalog = class extends Error {
50
+ name = "InvalidPiSkillCatalog";
51
+ };
52
+ function validatePiSkillCatalog(input) {
53
+ const fatal = input.diagnostics.find(({ type }) => type === "error" || type === "collision");
54
+ if (fatal) throw new InvalidPiSkillCatalog(`Pi Skill discovery failed: ${fatal.message}${fatal.path ? ` (${fatal.path})` : ""}`);
55
+ const names = /* @__PURE__ */ new Set();
56
+ for (const { name } of input.skills) {
57
+ validateSkillName(name);
58
+ if (names.has(name)) throw new InvalidPiSkillCatalog(`Pi Skill discovery contains duplicate name: ${name}`);
59
+ names.add(name);
60
+ }
61
+ return names;
62
+ }
63
+ function validateSkillName(name) {
64
+ if (typeof name !== "string" || name.length === 0 || name.length > 64 || !/^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$/.test(name) || name.includes("--")) throw new InvalidPiSkillCatalog(`Pi Skill discovery contains unsafe name: ${String(name)}`);
65
+ }
66
+ function validatePiSkillCommand(text, skillNames) {
67
+ if (!text.startsWith("/skill:")) return;
68
+ const name = text.slice(7).split(/\s/, 1)[0];
69
+ if (!skillNames.has(name)) throw new InvalidPiSkillCatalog(`Unknown Pi Skill: ${name}`);
70
+ }
71
+ //#endregion
72
+ //#region src/adapters/pi/skills/pi-skill-sources.ts
73
+ var InvalidPiSkillSource = class extends Error {
74
+ name = "InvalidPiSkillSource";
75
+ };
76
+ async function resolvePiSkillSources(options) {
77
+ const roots = [];
78
+ const seen = /* @__PURE__ */ new Set();
79
+ for (const path of [join(options.agentDir, "skills"), join(options.homeDirectory, ".agents", "skills")]) {
80
+ const canonical = await optionalDirectory(path);
81
+ if (canonical) appendUnique(roots, seen, canonical);
82
+ }
83
+ for (const path of options.projectSkillPaths ?? []) appendUnique(roots, seen, await requiredSkillSource(path));
84
+ return Object.freeze(roots);
85
+ }
86
+ async function optionalDirectory(path) {
87
+ let canonical;
88
+ try {
89
+ canonical = await realpath(path);
90
+ } catch (error) {
91
+ if (isMissingPath(error)) return void 0;
92
+ throw new InvalidPiSkillSource(`failed to resolve optional user Skill directory: ${path}`, { cause: error });
93
+ }
94
+ if (!(await stat(canonical)).isDirectory()) throw new InvalidPiSkillSource(`user Skill source must be a directory: ${path}`);
95
+ return canonical;
96
+ }
97
+ async function requiredSkillSource(path) {
98
+ try {
99
+ const canonical = await realpath(path);
100
+ const metadata = await stat(canonical);
101
+ if (!metadata.isDirectory() && !metadata.isFile()) throw new InvalidPiSkillSource(`Project Space Skill source must be a file or directory: ${path}`);
102
+ return canonical;
103
+ } catch (error) {
104
+ if (error instanceof InvalidPiSkillSource) throw error;
105
+ throw new InvalidPiSkillSource(`required Project Space Skill source is unavailable: ${path}`, { cause: error });
106
+ }
107
+ }
108
+ function appendUnique(roots, seen, path) {
109
+ if (seen.has(path)) return;
110
+ seen.add(path);
111
+ roots.push(path);
112
+ }
113
+ function isMissingPath(error) {
114
+ return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
115
+ }
116
+ //#endregion
117
+ //#region src/adapters/pi/tool-execution/pi-session-tools.ts
118
+ function resolvePiSessionToolNames(runtimeToolIds, customTools) {
119
+ const names = [];
120
+ const seen = /* @__PURE__ */ new Set();
121
+ for (const name of [...runtimeToolIds, ...customTools.map(({ name }) => name)]) {
122
+ if (seen.has(name)) throw new Error(`Pi Session Tool name collision: ${name}`);
123
+ seen.add(name);
124
+ names.push(name);
125
+ }
126
+ return Object.freeze(names);
127
+ }
128
+ //#endregion
129
+ //#region src/adapters/pi/runtime/pi-session-resources.ts
130
+ const PI_BEHAVIOR_SETTING_KEYS = Object.freeze([
131
+ "lastChangelogVersion",
132
+ "defaultProvider",
133
+ "defaultModel",
134
+ "defaultThinkingLevel",
135
+ "transport",
136
+ "steeringMode",
137
+ "followUpMode",
138
+ "theme",
139
+ "compaction",
140
+ "branchSummary",
141
+ "retry",
142
+ "hideThinkingBlock",
143
+ "showCacheMissNotices",
144
+ "externalEditor",
145
+ "shellPath",
146
+ "quietStartup",
147
+ "shellCommandPrefix",
148
+ "collapseChangelog",
149
+ "enableSkillCommands",
150
+ "terminal",
151
+ "images",
152
+ "enabledModels",
153
+ "doubleEscapeAction",
154
+ "treeFilterMode",
155
+ "thinkingBudgets",
156
+ "editorPaddingX",
157
+ "outputPad",
158
+ "autocompleteMaxVisible",
159
+ "showHardwareCursor",
160
+ "markdown",
161
+ "warnings",
162
+ "httpProxy",
163
+ "httpIdleTimeoutMs",
164
+ "websocketConnectTimeoutMs"
165
+ ]);
166
+ async function createPiSessionResources(options) {
167
+ const settingsManager = createSanitizedSettingsManager(options.cwd, options.agentDir);
168
+ const skillPaths = await resolvePiSkillSources({
169
+ agentDir: options.agentDir,
170
+ homeDirectory: options.homeDirectory,
171
+ ...options.projectSkillPaths ? { projectSkillPaths: options.projectSkillPaths } : {}
172
+ });
173
+ const resourceLoader = new DefaultResourceLoader({
174
+ agentDir: options.agentDir,
175
+ additionalSkillPaths: [...skillPaths],
176
+ ...options.appendSystemPromptOverride ? { appendSystemPromptOverride: options.appendSystemPromptOverride } : {},
177
+ cwd: options.cwd,
178
+ noContextFiles: true,
179
+ noExtensions: true,
180
+ noPromptTemplates: true,
181
+ noSkills: true,
182
+ noThemes: true,
183
+ settingsManager,
184
+ ...options.systemPromptOverride ? { systemPromptOverride: options.systemPromptOverride } : {}
185
+ });
186
+ await resourceLoader.reload();
187
+ const skillNames = validatePiSkillCatalog(resourceLoader.getSkills());
188
+ return Object.freeze({
189
+ skillNames,
190
+ skillPaths,
191
+ withSessionOptions: (sessionOptions) => Object.freeze({
192
+ ...sessionOptions,
193
+ agentDir: options.agentDir,
194
+ cwd: options.cwd,
195
+ resourceLoader,
196
+ settingsManager
197
+ })
198
+ });
199
+ }
200
+ function createSanitizedSettingsManager(cwd, agentDir) {
201
+ const fileSettings = SettingsManager.create(cwd, agentDir, { projectTrusted: false }).getGlobalSettings();
202
+ const behaviorSettings = Object.fromEntries(PI_BEHAVIOR_SETTING_KEYS.flatMap((key) => fileSettings[key] === void 0 ? [] : [[key, fileSettings[key]]]));
203
+ return SettingsManager.inMemory(behaviorSettings, { projectTrusted: false });
204
+ }
205
+ //#endregion
206
+ //#region src/adapters/pi/tool-execution/pi-tool-proxy.ts
207
+ function createPiToolProxyDefinitions$1(options) {
208
+ const names = /* @__PURE__ */ new Set();
209
+ return options.tools.map((tool) => {
210
+ const name = toPiToolName(tool.id);
211
+ if (names.has(name)) throw new Error(`Pi tool name collision: ${name}`);
212
+ names.add(name);
213
+ return {
214
+ description: tool.description,
215
+ execute: async (callId, input, signal) => {
216
+ const activeInput = options.getActiveInput();
217
+ const invocation = activeInput?.invocation;
218
+ if (!activeInput || !invocation) throw new Error(`tool ${tool.id} requires an active agent run with a trusted invocation`);
219
+ if (!invocation.tenantKey) throw new Error(`tool ${tool.id} requires a trusted tenant identity`);
220
+ throwIfAborted(signal ?? activeInput.abortSignal);
221
+ const inputDigest = createToolInputDigest(input);
222
+ const operationId = createBoundId("operation", {
223
+ agentId: options.agentId,
224
+ inputDigest,
225
+ instanceId: options.instanceId,
226
+ sourceMessageId: invocation.sourceMessageId,
227
+ toolId: tool.id,
228
+ toolVersion: tool.version
229
+ });
230
+ const approvalId = createBoundId("approval", {
231
+ callId,
232
+ operationId,
233
+ runId: activeInput.runId
234
+ });
235
+ if (requiresToolApproval(tool.risk)) {
236
+ if (invocation.allowedActorOpenIds.length === 0) throw new Error(`tool ${tool.id} requires at least one trusted approval actor`);
237
+ await options.approvals.requestApproval({
238
+ agentId: options.agentId,
239
+ allowedActorOpenIds: invocation.allowedActorOpenIds,
240
+ approvalId,
241
+ callId,
242
+ endpointId: invocation.endpointId,
243
+ inputDigest,
244
+ instanceId: options.instanceId,
245
+ operationId,
246
+ risk: tool.risk,
247
+ runId: activeInput.runId,
248
+ sessionKey: activeInput.sessionKey,
249
+ signal: signal ?? activeInput.abortSignal,
250
+ sourceMessageId: invocation.sourceMessageId,
251
+ tenantKey: invocation.tenantKey,
252
+ toolId: tool.id,
253
+ toolVersion: tool.version
254
+ });
255
+ throwIfAborted(signal ?? activeInput.abortSignal);
256
+ }
257
+ const result = await options.broker.execute({
258
+ authority: createInvocationAuthority({
259
+ agentId: options.agentId,
260
+ allowedActorOpenIds: invocation.allowedActorOpenIds,
261
+ ...invocation.kind === "background-session" ? invocation.conversationId ? { conversationId: invocation.conversationId } : {} : invocation.memory?.conversationId ? { conversationId: invocation.memory.conversationId } : {},
262
+ endpointId: invocation.endpointId,
263
+ instanceId: options.instanceId,
264
+ ...invocation.memory ? { memory: {
265
+ ...invocation.memory,
266
+ scopes: options.memoryScopes ?? []
267
+ } } : {},
268
+ runId: activeInput.runId,
269
+ sessionKey: activeInput.sessionKey,
270
+ sourceMessageId: invocation.sourceMessageId,
271
+ tenantKey: invocation.tenantKey,
272
+ toolGrantSet: options.toolGrantSet
273
+ }),
274
+ callId,
275
+ input,
276
+ operationId,
277
+ ...requiresToolApproval(tool.risk) ? { approvalId } : {},
278
+ toolId: tool.id,
279
+ version: tool.version
280
+ });
281
+ return {
282
+ content: [{
283
+ text: stringifyToolResult(result),
284
+ type: "text"
285
+ }],
286
+ details: result
287
+ };
288
+ },
289
+ executionMode: "sequential",
290
+ label: tool.id,
291
+ name,
292
+ parameters: Unsafe(tool.inputSchema),
293
+ promptSnippet: `${name}: ${tool.description}`
294
+ };
295
+ });
296
+ }
297
+ function createPiToolNameResolver$1(tools) {
298
+ const toolIdsByPiName = new Map(tools.map((tool) => [toPiToolName(tool.id), tool.id]));
299
+ return (toolName) => toolIdsByPiName.get(toolName) ?? toolName;
300
+ }
301
+ function toPiToolName(toolId) {
302
+ return `rivus_${toolId.replace(/[^a-zA-Z0-9_-]/g, "_")}`;
303
+ }
304
+ function createBoundId(kind, binding) {
305
+ return `${kind}:${createHash("sha256").update(JSON.stringify(binding)).digest("hex")}`;
306
+ }
307
+ function throwIfAborted(signal) {
308
+ if (signal.aborted) throw signal.reason ?? /* @__PURE__ */ new Error("tool execution was aborted");
309
+ }
310
+ function stringifyToolResult(result) {
311
+ if (typeof result === "string") return result;
312
+ return JSON.stringify(result ?? null);
313
+ }
314
+ //#endregion
315
+ //#region src/adapters/compatibility/agent-execution/pi/pi-tool-proxy.ts
316
+ function createPiToolProxyDefinitions(options) {
317
+ return createPiToolProxyDefinitions$1({
318
+ ...options,
319
+ getActiveInput: () => {
320
+ const input = options.getActiveInput();
321
+ return input ? toEffectAgentLoopInput(input) : void 0;
322
+ }
323
+ });
324
+ }
325
+ function createPiToolNameResolver(tools) {
326
+ return createPiToolNameResolver$1(tools);
327
+ }
328
+ //#endregion
329
+ export { InvalidPiSkillSource as a, validatePiSkillCatalog as c, createPiProjectSkillReadTool as d, createPiSkillReadTool as f, resolvePiSessionToolNames as i, validatePiSkillCommand as l, createPiToolProxyDefinitions as n, resolvePiSkillSources as o, createPiSkillReadTools as p, createPiSessionResources as r, InvalidPiSkillCatalog as s, createPiToolNameResolver as t, ProjectSkillReadDenied as u };