@rivus/agent 0.6.2 → 0.8.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/dist/mcp.d.ts ADDED
@@ -0,0 +1,86 @@
1
+ import { k as BackgroundSessionAuthority, r as BackgroundSessionService } from "./background-session-service.js";
2
+ import { Readable, Writable } from "node:stream";
3
+
4
+ //#region src/application/background-session/background-session-control.d.ts
5
+ type BackgroundSessionControlCommand = "start" | "wait" | "list" | "status" | "send" | "stop";
6
+ interface BackgroundSessionControlOrigin {
7
+ readonly allowedActorOpenIds: ReadonlyArray<string>;
8
+ readonly conversationId?: string;
9
+ readonly endpointId: string;
10
+ readonly tenantKey: string;
11
+ }
12
+ interface BackgroundSessionControlContext {
13
+ readonly agentId: string;
14
+ readonly authority: BackgroundSessionAuthority;
15
+ readonly origin: BackgroundSessionControlOrigin;
16
+ readonly policyEpoch: number;
17
+ readonly runId: string;
18
+ readonly sessionKey: string;
19
+ readonly sourceMessageId: string;
20
+ }
21
+ interface BackgroundSessionControl {
22
+ handle(command: BackgroundSessionControlCommand, context: BackgroundSessionControlContext, input: unknown): Promise<unknown>;
23
+ }
24
+ declare function createBackgroundSessionControl(options: {
25
+ readonly service: BackgroundSessionService;
26
+ }): BackgroundSessionControl;
27
+ declare class BackgroundSessionControlError extends Error {
28
+ readonly name = "BackgroundSessionControlError";
29
+ }
30
+ declare function toControlContext(input: {
31
+ readonly agentId: string;
32
+ readonly authority: BackgroundSessionAuthority;
33
+ readonly origin: BackgroundSessionControlOrigin;
34
+ readonly policyEpoch: number;
35
+ readonly sessionKey: string;
36
+ readonly sourceMessageId?: string;
37
+ }): BackgroundSessionControlContext;
38
+ //#endregion
39
+ //#region src/infrastructure/mcp/background-session-mcp-server.d.ts
40
+ declare const BACKGROUND_SESSION_MCP_SERVER_NAME = "rivus-background-sessions";
41
+ declare const BACKGROUND_SESSION_MCP_SERVER_VERSION = "1.0.0";
42
+ interface BackgroundSessionMcpServerOptions {
43
+ readonly controlContext: BackgroundSessionControlContext;
44
+ readonly controlUrl: string;
45
+ readonly controlToken: string;
46
+ readonly enabledTools?: ReadonlyArray<BackgroundSessionControlCommand>;
47
+ readonly fetch?: typeof fetch;
48
+ readonly input?: Readable;
49
+ readonly output?: Writable;
50
+ readonly serverName?: string;
51
+ readonly serverVersion?: string;
52
+ }
53
+ interface BackgroundSessionMcpServer {
54
+ run(): Promise<void>;
55
+ }
56
+ declare class BackgroundSessionMcpError extends Error {
57
+ readonly name = "BackgroundSessionMcpError";
58
+ }
59
+ declare function createBackgroundSessionMcpServer(options: BackgroundSessionMcpServerOptions): BackgroundSessionMcpServer;
60
+ interface RunBackgroundSessionMcpServerEnv {
61
+ readonly fetch?: typeof fetch;
62
+ readonly input?: Readable;
63
+ readonly output?: Writable;
64
+ }
65
+ declare function runBackgroundSessionMcpServer(options?: RunBackgroundSessionMcpServerEnv): Promise<void>;
66
+ //#endregion
67
+ //#region src/infrastructure/http/background-session-control-http-server.d.ts
68
+ interface BackgroundSessionControlHttpServerOptions {
69
+ readonly control: BackgroundSessionControl;
70
+ readonly host?: string;
71
+ readonly port: number;
72
+ readonly token: string;
73
+ }
74
+ interface BackgroundSessionControlHttpServer {
75
+ port(): number;
76
+ close(): Promise<void>;
77
+ start(): Promise<void>;
78
+ }
79
+ declare class BackgroundSessionControlHttpError extends Error {
80
+ readonly statusCode: number;
81
+ readonly name = "BackgroundSessionControlHttpError";
82
+ constructor(statusCode: number, message: string);
83
+ }
84
+ declare function createBackgroundSessionControlHttpServer(options: BackgroundSessionControlHttpServerOptions): BackgroundSessionControlHttpServer;
85
+ //#endregion
86
+ export { BACKGROUND_SESSION_MCP_SERVER_NAME, BACKGROUND_SESSION_MCP_SERVER_VERSION, type BackgroundSessionControl, type BackgroundSessionControlCommand, type BackgroundSessionControlContext, BackgroundSessionControlError, BackgroundSessionControlHttpError, type BackgroundSessionControlHttpServer, type BackgroundSessionControlHttpServerOptions, type BackgroundSessionControlOrigin, BackgroundSessionMcpError, type BackgroundSessionMcpServer, type BackgroundSessionMcpServerOptions, createBackgroundSessionControl, createBackgroundSessionControlHttpServer, createBackgroundSessionMcpServer, runBackgroundSessionMcpServer, toControlContext };
package/dist/mcp.js ADDED
@@ -0,0 +1,416 @@
1
+ import { l as createBackgroundSessionToolContracts, s as createBackgroundSessionKey } from "./background-session-authority.js";
2
+ import { a as readBackgroundSessionWaitInput, i as readBackgroundSessionString, n as readBackgroundSessionObject, r as readBackgroundSessionPhase, t as readBackgroundSessionInteger } from "./background-session-input.js";
3
+ import { randomUUID } from "node:crypto";
4
+ import { pathToFileURL } from "node:url";
5
+ import { createServer } from "node:http";
6
+ //#region src/infrastructure/mcp/background-session-mcp-server.ts
7
+ const BACKGROUND_SESSION_MCP_SERVER_NAME = "rivus-background-sessions";
8
+ const BACKGROUND_SESSION_MCP_SERVER_VERSION = "1.0.0";
9
+ var BackgroundSessionMcpError = class extends Error {
10
+ name = "BackgroundSessionMcpError";
11
+ };
12
+ function createBackgroundSessionMcpServer(options) {
13
+ const input = options.input ?? process.stdin;
14
+ const output = options.output ?? process.stdout;
15
+ const fetchImplementation = options.fetch ?? fetch;
16
+ const enabledTools = new Set(options.enabledTools ?? [
17
+ "start",
18
+ "wait",
19
+ "list",
20
+ "status",
21
+ "send",
22
+ "stop"
23
+ ]);
24
+ const tools = createBackgroundSessionToolContracts().filter(({ id }) => enabledTools.has(id.slice(11))).map((contract) => ({
25
+ description: contract.description,
26
+ inputSchema: contract.inputSchema,
27
+ name: contract.id,
28
+ outputSchema: { type: "object" }
29
+ }));
30
+ const serverInfo = {
31
+ name: options.serverName ?? "rivus-background-sessions",
32
+ version: options.serverVersion ?? "1.0.0"
33
+ };
34
+ return { run: () => runMcpServer({
35
+ controlContext: options.controlContext,
36
+ controlToken: options.controlToken,
37
+ controlUrl: options.controlUrl,
38
+ fetchImplementation,
39
+ input,
40
+ output,
41
+ serverInfo,
42
+ tools
43
+ }) };
44
+ }
45
+ async function runBackgroundSessionMcpServer(options = {}) {
46
+ const controlUrl = requireEnv("RIVUS_MCP_CONTROL_URL");
47
+ const controlToken = requireEnv("RIVUS_MCP_CONTROL_TOKEN");
48
+ const context = parseContext(requireEnv("RIVUS_MCP_CONTEXT"));
49
+ const enabledTools = optionalEnv("RIVUS_MCP_TOOLS")?.split(",").map((tool) => tool.trim()).filter(Boolean);
50
+ await createBackgroundSessionMcpServer({
51
+ controlContext: context,
52
+ controlToken,
53
+ controlUrl,
54
+ ...enabledTools ? { enabledTools } : {},
55
+ ...options.fetch ? { fetch: options.fetch } : {},
56
+ ...options.input ? { input: options.input } : {},
57
+ ...options.output ? { output: options.output } : {}
58
+ }).run();
59
+ }
60
+ async function runMcpServer(options) {
61
+ const send = (message) => {
62
+ const body = JSON.stringify(message);
63
+ options.output.write(`Content-Length: ${Buffer.byteLength(body)}\r\n\r\n${body}`);
64
+ };
65
+ for await (const message of readMcpMessages(options.input)) {
66
+ if (!isRecord(message) || typeof message.id !== "number") continue;
67
+ const method = typeof message.method === "string" ? message.method : void 0;
68
+ if (!method) continue;
69
+ try {
70
+ switch (method) {
71
+ case "initialize":
72
+ send({
73
+ id: message.id,
74
+ result: {
75
+ capabilities: { tools: { listChanged: false } },
76
+ protocolVersion: "2025-03-26",
77
+ serverInfo: options.serverInfo
78
+ }
79
+ });
80
+ break;
81
+ case "ping":
82
+ send({
83
+ id: message.id,
84
+ result: {}
85
+ });
86
+ break;
87
+ case "tools/list":
88
+ send({
89
+ id: message.id,
90
+ result: { tools: options.tools }
91
+ });
92
+ break;
93
+ case "tools/call": {
94
+ const params = isRecord(message.params) ? message.params : {};
95
+ const name = typeof params.name === "string" ? params.name : "";
96
+ const command = name.startsWith("background.") ? name.slice(11) : void 0;
97
+ if (!command || !options.tools.some((tool) => tool.name === name)) {
98
+ send({
99
+ id: message.id,
100
+ error: {
101
+ code: -32602,
102
+ message: `unknown tool: ${name}`
103
+ }
104
+ });
105
+ break;
106
+ }
107
+ const response = await options.fetchImplementation(options.controlUrl, {
108
+ body: JSON.stringify({
109
+ command,
110
+ context: options.controlContext,
111
+ input: params.arguments ?? {}
112
+ }),
113
+ headers: {
114
+ authorization: `Bearer ${options.controlToken}`,
115
+ "content-type": "application/json"
116
+ },
117
+ method: "POST"
118
+ });
119
+ const envelope = await response.json();
120
+ if (!response.ok || envelope.error) {
121
+ const messageText = envelope.error?.message ?? `background session control failed with ${response.status}`;
122
+ send({
123
+ id: message.id,
124
+ error: {
125
+ code: -32e3,
126
+ message: messageText
127
+ }
128
+ });
129
+ break;
130
+ }
131
+ send({
132
+ id: message.id,
133
+ result: {
134
+ content: [{
135
+ text: JSON.stringify(envelope.result ?? null),
136
+ type: "text"
137
+ }],
138
+ isError: false
139
+ }
140
+ });
141
+ break;
142
+ }
143
+ default: send({
144
+ id: message.id,
145
+ error: {
146
+ code: -32601,
147
+ message: `method not found: ${method}`
148
+ }
149
+ });
150
+ }
151
+ } catch (error) {
152
+ send({
153
+ id: message.id,
154
+ error: {
155
+ code: -32e3,
156
+ message: error instanceof Error ? error.message : String(error)
157
+ }
158
+ });
159
+ }
160
+ }
161
+ }
162
+ async function* readMcpMessages(input) {
163
+ let buffer = "";
164
+ for await (const chunk of input) {
165
+ buffer += chunk.toString("utf8");
166
+ let parsed = parseNextMessage(buffer);
167
+ while (parsed) {
168
+ yield parsed.message;
169
+ buffer = Buffer.from(buffer).subarray(parsed.byteLength).toString("utf8");
170
+ parsed = parseNextMessage(buffer);
171
+ }
172
+ }
173
+ }
174
+ function parseNextMessage(buffer) {
175
+ const headerEnd = buffer.indexOf("\r\n\r\n");
176
+ if (headerEnd < 0) return void 0;
177
+ const contentLength = buffer.slice(0, headerEnd).split("\r\n").find((header) => /^Content-Length:\s*\d+$/i.test(header));
178
+ if (!contentLength) throw new BackgroundSessionMcpError("MCP message is missing a Content-Length header");
179
+ const byteLength = Number(contentLength.slice(15).trim());
180
+ const headerBytes = Buffer.byteLength(buffer.slice(0, headerEnd + 4));
181
+ if (Buffer.byteLength(buffer) < headerBytes + byteLength) return void 0;
182
+ const payload = Buffer.from(buffer).subarray(headerBytes, headerBytes + byteLength).toString("utf8");
183
+ try {
184
+ return {
185
+ byteLength: headerBytes + byteLength,
186
+ message: JSON.parse(payload)
187
+ };
188
+ } catch {
189
+ throw new BackgroundSessionMcpError("invalid MCP JSON payload");
190
+ }
191
+ }
192
+ function parseContext(value) {
193
+ const parsed = JSON.parse(value);
194
+ if (!isRecord(parsed)) throw new BackgroundSessionMcpError("RIVUS_MCP_CONTEXT must be a JSON object");
195
+ return parsed;
196
+ }
197
+ function requireEnv(name) {
198
+ const value = process.env[name]?.trim();
199
+ if (!value) throw new BackgroundSessionMcpError(`${name} is required`);
200
+ return value;
201
+ }
202
+ function optionalEnv(name) {
203
+ return process.env[name]?.trim() || void 0;
204
+ }
205
+ function isRecord(value) {
206
+ return value !== null && typeof value === "object" && !Array.isArray(value);
207
+ }
208
+ //#endregion
209
+ //#region src/application/background-session/background-session-control.ts
210
+ function createBackgroundSessionControl(options) {
211
+ return { handle: async (command, context, input) => {
212
+ const executionContext = {
213
+ agentId: context.agentId,
214
+ callId: `mcp-call:${randomUUID()}`,
215
+ instanceId: `mcp:${context.agentId}`,
216
+ policyEpoch: context.policyEpoch,
217
+ runId: context.runId,
218
+ sessionKey: context.sessionKey,
219
+ sourceMessageId: context.sourceMessageId,
220
+ toolId: `background.${command}`,
221
+ toolVersion: "1.0.0",
222
+ origin: toToolOrigin(context.origin)
223
+ };
224
+ switch (command) {
225
+ case "start": {
226
+ const { displayName, prompt } = readObject(input, ["displayName", "prompt"]);
227
+ if (typeof prompt !== "string" || prompt.trim() === "") throw new BackgroundSessionControlError("background.start requires a non-empty prompt");
228
+ const sessionId = `bg-${randomUUID()}`;
229
+ return options.service.start({
230
+ authority: {
231
+ ...context.authority,
232
+ sessionKey: createBackgroundSessionKey(sessionId)
233
+ },
234
+ context: executionContext,
235
+ ...displayName === void 0 ? {} : { displayName: readString(displayName, "displayName") },
236
+ prompt,
237
+ sessionId
238
+ });
239
+ }
240
+ case "wait": return options.service.wait({
241
+ context: executionContext,
242
+ ...readBackgroundSessionWaitInput(input, (message) => new BackgroundSessionControlError(message))
243
+ });
244
+ case "list": {
245
+ const { limit, phase } = readObject(input, ["limit", "phase"]);
246
+ return options.service.list({
247
+ context: executionContext,
248
+ ...limit === void 0 ? {} : { limit: readInteger(limit, "limit") },
249
+ ...phase === void 0 ? {} : { phase: readPhase(phase) }
250
+ });
251
+ }
252
+ case "status": {
253
+ const { sessionId } = readObject(input, ["sessionId"]);
254
+ return options.service.status({
255
+ context: executionContext,
256
+ sessionId: readString(sessionId, "sessionId")
257
+ });
258
+ }
259
+ case "send": {
260
+ const { message, sessionId } = readObject(input, ["message", "sessionId"]);
261
+ return options.service.send({
262
+ context: executionContext,
263
+ message: readString(message, "message"),
264
+ sessionId: readString(sessionId, "sessionId")
265
+ });
266
+ }
267
+ case "stop": {
268
+ const { reason, sessionId } = readObject(input, ["reason", "sessionId"]);
269
+ return options.service.stop({
270
+ context: executionContext,
271
+ ...reason === void 0 ? {} : { reason: readString(reason, "reason") },
272
+ sessionId: readString(sessionId, "sessionId")
273
+ });
274
+ }
275
+ }
276
+ } };
277
+ }
278
+ var BackgroundSessionControlError = class extends Error {
279
+ name = "BackgroundSessionControlError";
280
+ };
281
+ function toControlContext(input) {
282
+ return {
283
+ agentId: input.agentId,
284
+ authority: input.authority,
285
+ origin: {
286
+ allowedActorOpenIds: input.origin.allowedActorOpenIds,
287
+ ...input.origin.conversationId === void 0 ? {} : { conversationId: input.origin.conversationId },
288
+ endpointId: input.origin.endpointId,
289
+ tenantKey: input.origin.tenantKey
290
+ },
291
+ policyEpoch: input.policyEpoch,
292
+ runId: `mcp:${randomUUID()}`,
293
+ sessionKey: input.sessionKey,
294
+ sourceMessageId: input.sourceMessageId ?? `mcp:${randomUUID()}`
295
+ };
296
+ }
297
+ function toToolOrigin(origin) {
298
+ return {
299
+ allowedActorOpenIds: origin.allowedActorOpenIds,
300
+ endpointId: origin.endpointId,
301
+ tenantKey: origin.tenantKey,
302
+ ...origin.conversationId === void 0 ? {} : { conversationId: origin.conversationId }
303
+ };
304
+ }
305
+ function readObject(input, allowed) {
306
+ return readBackgroundSessionObject(input, allowed, (message) => new BackgroundSessionControlError(message));
307
+ }
308
+ function readString(value, name) {
309
+ return readBackgroundSessionString(value, name, (message) => new BackgroundSessionControlError(message));
310
+ }
311
+ function readInteger(value, name) {
312
+ return readBackgroundSessionInteger(value, name, (message) => new BackgroundSessionControlError(message));
313
+ }
314
+ function readPhase(value) {
315
+ return readBackgroundSessionPhase(value, (message) => new BackgroundSessionControlError(message));
316
+ }
317
+ //#endregion
318
+ //#region src/infrastructure/http/background-session-control-http-server.ts
319
+ var BackgroundSessionControlHttpError = class extends Error {
320
+ statusCode;
321
+ name = "BackgroundSessionControlHttpError";
322
+ constructor(statusCode, message) {
323
+ super(message);
324
+ this.statusCode = statusCode;
325
+ }
326
+ };
327
+ const COMMANDS = [
328
+ "start",
329
+ "wait",
330
+ "list",
331
+ "status",
332
+ "send",
333
+ "stop"
334
+ ];
335
+ function createBackgroundSessionControlHttpServer(options) {
336
+ let server;
337
+ let boundPort = options.port;
338
+ const serverHandle = createServer((request, response) => {
339
+ (async () => {
340
+ try {
341
+ if (request.method !== "POST" || request.url !== "/background-sessions") throw new BackgroundSessionControlHttpError(404, "not found");
342
+ if (request.headers.authorization !== `Bearer ${options.token}`) throw new BackgroundSessionControlHttpError(401, "unauthorized");
343
+ const envelope = parseEnvelope(await readBody(request, 64 * 1024));
344
+ const command = envelope.command;
345
+ if (!COMMANDS.includes(command)) throw new BackgroundSessionControlHttpError(400, `unsupported background session command: ${String(command)}`);
346
+ respond(response, 200, {
347
+ ok: true,
348
+ result: await options.control.handle(command, envelope.context, envelope.input)
349
+ });
350
+ } catch (error) {
351
+ respond(response, error instanceof BackgroundSessionControlHttpError ? error.statusCode : 500, {
352
+ error: {
353
+ message: error instanceof Error ? error.message : String(error),
354
+ name: error instanceof Error ? error.name : "Error"
355
+ },
356
+ ok: false
357
+ });
358
+ }
359
+ })();
360
+ });
361
+ serverHandle.on("error", () => void 0);
362
+ return {
363
+ port: () => boundPort,
364
+ close: async () => {
365
+ const active = server;
366
+ server = void 0;
367
+ if (active) await new Promise((resolve) => active.close(() => resolve()));
368
+ },
369
+ start: async () => {
370
+ if (server) return;
371
+ await new Promise((resolve) => {
372
+ server = serverHandle;
373
+ serverHandle.listen(options.port, options.host ?? "127.0.0.1", () => {
374
+ const address = serverHandle.address();
375
+ if (address !== null && typeof address === "object") boundPort = address.port;
376
+ resolve();
377
+ });
378
+ });
379
+ }
380
+ };
381
+ }
382
+ function respond(response, statusCode, body) {
383
+ response.writeHead(statusCode, { "content-type": "application/json" });
384
+ response.end(JSON.stringify(body));
385
+ }
386
+ function parseEnvelope(body) {
387
+ const parsed = JSON.parse(body);
388
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) throw new BackgroundSessionControlHttpError(400, "invalid background session control envelope");
389
+ const record = parsed;
390
+ if (typeof record.command !== "string" || record.context === void 0) throw new BackgroundSessionControlHttpError(400, "background session control envelope requires command and context");
391
+ return {
392
+ command: record.command,
393
+ context: record.context,
394
+ input: record.input
395
+ };
396
+ }
397
+ function readBody(request, maxBytes) {
398
+ return new Promise((resolve, reject) => {
399
+ const chunks = [];
400
+ let total = 0;
401
+ request.on("data", (chunk) => {
402
+ total += chunk.length;
403
+ if (total > maxBytes) {
404
+ reject(new BackgroundSessionControlHttpError(413, "background session control request too large"));
405
+ return;
406
+ }
407
+ chunks.push(chunk);
408
+ });
409
+ request.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
410
+ });
411
+ }
412
+ //#endregion
413
+ //#region src/mcp.ts
414
+ if (pathToFileURL(process.argv[1] ?? "").href === import.meta.url) await runBackgroundSessionMcpServer();
415
+ //#endregion
416
+ export { BACKGROUND_SESSION_MCP_SERVER_NAME, BACKGROUND_SESSION_MCP_SERVER_VERSION, BackgroundSessionControlError, BackgroundSessionControlHttpError, BackgroundSessionMcpError, createBackgroundSessionControl, createBackgroundSessionControlHttpServer, createBackgroundSessionMcpServer, runBackgroundSessionMcpServer, toControlContext };
@@ -94,6 +94,9 @@ interface InvocationAuthorityRef {
94
94
  }
95
95
  interface InvocationAuthority {
96
96
  readonly agentId: string;
97
+ readonly allowedActorOpenIds?: ReadonlyArray<string>;
98
+ readonly conversationId?: string;
99
+ readonly endpointId?: string;
97
100
  readonly instanceId: string;
98
101
  readonly memory?: AgentMemoryAuthority;
99
102
  readonly runId: string;
package/dist/pi.js CHANGED
@@ -88,6 +88,9 @@ function createPiToolProxyDefinitions(options) {
88
88
  const result = await options.broker.execute({
89
89
  authority: createInvocationAuthority({
90
90
  agentId: options.agentId,
91
+ allowedActorOpenIds: invocation.allowedActorOpenIds,
92
+ ...invocation.memory?.conversationId ? { conversationId: invocation.memory.conversationId } : {},
93
+ endpointId: invocation.endpointId,
91
94
  instanceId: options.instanceId,
92
95
  ...invocation.memory ? { memory: {
93
96
  ...invocation.memory,