@rivus/gateway 0.16.2
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 +21 -0
- package/README.md +6 -0
- package/dist/bootstrap/pi-feishu.d.ts +20 -0
- package/dist/bootstrap/pi-feishu.js +671 -0
- package/dist/chunks/background-session-authority.js +230 -0
- package/dist/chunks/background-session-control-input.js +45 -0
- package/dist/chunks/background-session-service.d.ts +390 -0
- package/dist/chunks/index.d.ts +4703 -0
- package/dist/chunks/node-rivus-deployment-manifest.js +1650 -0
- package/dist/chunks/rivus-node-entrypoint.js +4464 -0
- package/dist/chunks/service.js +12112 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +16 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1215 -0
- package/dist/mcp.d.ts +92 -0
- package/dist/mcp.js +455 -0
- package/package.json +64 -0
- package/skills/runtime-management/SKILL.md +65 -0
- package/templates/a-share-briefing-analysis.mjs +93 -0
- package/templates/a-share-briefing-renderer.mjs +257 -0
- package/templates/a-share-index-evidence.mjs +99 -0
- package/templates/a-share-market-briefing.mjs +83 -0
- package/templates/a-share-market-date.mjs +10 -0
- package/templates/a-share-overseas-evidence.mjs +86 -0
- package/templates/a-share-policy-evidence.mjs +145 -0
- package/templates/a-share-provider-response.mjs +21 -0
- package/templates/a-share-sector-evidence.mjs +70 -0
- package/templates/acp-stdio-proxy.mjs +58 -0
- package/templates/current-weather.mjs +117 -0
- package/templates/html-drive-tools.mjs +262 -0
- package/templates/https-response-reader.mjs +36 -0
- package/templates/langfuse-drive-e2e.mjs +175 -0
- package/templates/pi-feishu-deployment.bootstrap.ts +3 -0
- package/templates/pi-feishu.bootstrap.ts +242 -0
- package/templates/rivus-agents.plugin.mjs +290 -0
- package/templates/rivus-langfuse-demo.config.json +37 -0
- package/templates/rivus-starter.plugin.mjs +47 -0
- package/templates/rivus.config.json +114 -0
package/dist/mcp.d.ts
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { M as BackgroundSessionAuthority, r as BackgroundSessionService } from "./chunks/background-session-service.js";
|
|
2
|
+
import { Readable, Writable } from "node:stream";
|
|
3
|
+
|
|
4
|
+
//#region src/bootstrap/mcp/rivus-mcp-entrypoint.d.ts
|
|
5
|
+
interface RunBackgroundSessionMcpServerEnv {
|
|
6
|
+
readonly fetch?: typeof fetch;
|
|
7
|
+
readonly input?: Readable;
|
|
8
|
+
readonly output?: Writable;
|
|
9
|
+
}
|
|
10
|
+
declare function runBackgroundSessionMcpServer(options?: RunBackgroundSessionMcpServerEnv): Promise<void>;
|
|
11
|
+
//#endregion
|
|
12
|
+
//#region src/core/application/background-session/control/background-session-control.d.ts
|
|
13
|
+
type BackgroundSessionControlCommand = "start" | "wait" | "list" | "status" | "send" | "stop";
|
|
14
|
+
interface BackgroundSessionControlOrigin {
|
|
15
|
+
readonly allowedActorOpenIds: ReadonlyArray<string>;
|
|
16
|
+
readonly conversationId?: string;
|
|
17
|
+
readonly endpointId: string;
|
|
18
|
+
readonly tenantKey: string;
|
|
19
|
+
}
|
|
20
|
+
interface BackgroundSessionControlContext {
|
|
21
|
+
readonly agentId: string;
|
|
22
|
+
readonly authority: BackgroundSessionAuthority;
|
|
23
|
+
readonly origin: BackgroundSessionControlOrigin;
|
|
24
|
+
readonly policyEpoch: number;
|
|
25
|
+
readonly runId: string;
|
|
26
|
+
readonly sessionKey: string;
|
|
27
|
+
readonly sourceMessageId: string;
|
|
28
|
+
}
|
|
29
|
+
interface BackgroundSessionControl {
|
|
30
|
+
handle(command: BackgroundSessionControlCommand, context: BackgroundSessionControlContext, input: unknown): Promise<unknown>;
|
|
31
|
+
}
|
|
32
|
+
declare class BackgroundSessionControlError extends Error {
|
|
33
|
+
readonly name = "BackgroundSessionControlError";
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
//#region src/adapters/mcp/background-session/background-session-mcp-server.d.ts
|
|
37
|
+
declare const BACKGROUND_SESSION_MCP_SERVER_NAME = "rivus-background-sessions";
|
|
38
|
+
declare const BACKGROUND_SESSION_MCP_SERVER_VERSION = "1.0.0";
|
|
39
|
+
interface BackgroundSessionMcpServerOptions {
|
|
40
|
+
readonly capability: string;
|
|
41
|
+
readonly controlUrl: string;
|
|
42
|
+
readonly controlToken: string;
|
|
43
|
+
readonly enabledTools?: ReadonlyArray<BackgroundSessionControlCommand>;
|
|
44
|
+
readonly fetch?: typeof fetch;
|
|
45
|
+
readonly input?: Readable;
|
|
46
|
+
readonly output?: Writable;
|
|
47
|
+
readonly serverName?: string;
|
|
48
|
+
readonly serverVersion?: string;
|
|
49
|
+
}
|
|
50
|
+
interface BackgroundSessionMcpServer {
|
|
51
|
+
run(): Promise<void>;
|
|
52
|
+
}
|
|
53
|
+
declare class BackgroundSessionMcpError extends Error {
|
|
54
|
+
readonly name = "BackgroundSessionMcpError";
|
|
55
|
+
}
|
|
56
|
+
declare function createBackgroundSessionMcpServer(options: BackgroundSessionMcpServerOptions): BackgroundSessionMcpServer;
|
|
57
|
+
//#endregion
|
|
58
|
+
//#region src/adapters/compatibility/background-session/control.d.ts
|
|
59
|
+
declare function createBackgroundSessionControl(options: {
|
|
60
|
+
readonly service: BackgroundSessionService;
|
|
61
|
+
}): BackgroundSessionControl;
|
|
62
|
+
declare function toControlContext(input: {
|
|
63
|
+
readonly agentId: string;
|
|
64
|
+
readonly authority: BackgroundSessionAuthority;
|
|
65
|
+
readonly origin: BackgroundSessionControlOrigin;
|
|
66
|
+
readonly policyEpoch: number;
|
|
67
|
+
readonly sessionKey: string;
|
|
68
|
+
readonly sourceMessageId?: string;
|
|
69
|
+
}): BackgroundSessionControlContext;
|
|
70
|
+
//#endregion
|
|
71
|
+
//#region src/adapters/http/background-session/background-session-control-http-server.d.ts
|
|
72
|
+
interface BackgroundSessionControlHttpServerOptions {
|
|
73
|
+
readonly control: BackgroundSessionControl;
|
|
74
|
+
readonly host?: string;
|
|
75
|
+
readonly port: number;
|
|
76
|
+
readonly status?: () => unknown;
|
|
77
|
+
readonly token: string;
|
|
78
|
+
}
|
|
79
|
+
interface BackgroundSessionControlHttpServer {
|
|
80
|
+
port(): number;
|
|
81
|
+
issueCapability(context: BackgroundSessionControlContext): string;
|
|
82
|
+
close(): Promise<void>;
|
|
83
|
+
start(): Promise<void>;
|
|
84
|
+
}
|
|
85
|
+
declare class BackgroundSessionControlHttpError extends Error {
|
|
86
|
+
readonly statusCode: number;
|
|
87
|
+
readonly name = "BackgroundSessionControlHttpError";
|
|
88
|
+
constructor(statusCode: number, message: string);
|
|
89
|
+
}
|
|
90
|
+
declare function createBackgroundSessionControlHttpServer(options: BackgroundSessionControlHttpServerOptions): BackgroundSessionControlHttpServer;
|
|
91
|
+
//#endregion
|
|
92
|
+
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,455 @@
|
|
|
1
|
+
import { d as createBackgroundSessionKey, o as createBackgroundSessionToolContracts } from "./chunks/background-session-authority.js";
|
|
2
|
+
import { a as readBackgroundSessionWaitInput, i as readBackgroundSessionString, n as readBackgroundSessionObject, r as readBackgroundSessionPhase, t as readBackgroundSessionInteger } from "./chunks/background-session-control-input.js";
|
|
3
|
+
import { createRandomId } from "@rivus/platform/identity";
|
|
4
|
+
import { randomUUID } from "node:crypto";
|
|
5
|
+
import { pathToFileURL } from "node:url";
|
|
6
|
+
import { createServer } from "node:http";
|
|
7
|
+
//#region src/adapters/mcp/background-session/background-session-mcp-server.ts
|
|
8
|
+
const BACKGROUND_SESSION_MCP_SERVER_NAME = "rivus-background-sessions";
|
|
9
|
+
const BACKGROUND_SESSION_MCP_SERVER_VERSION = "1.0.0";
|
|
10
|
+
var BackgroundSessionMcpError = class extends Error {
|
|
11
|
+
name = "BackgroundSessionMcpError";
|
|
12
|
+
};
|
|
13
|
+
function createBackgroundSessionMcpServer(options) {
|
|
14
|
+
const input = options.input ?? process.stdin;
|
|
15
|
+
const output = options.output ?? process.stdout;
|
|
16
|
+
const fetchImplementation = options.fetch ?? fetch;
|
|
17
|
+
const enabledTools = new Set(options.enabledTools ?? [
|
|
18
|
+
"start",
|
|
19
|
+
"wait",
|
|
20
|
+
"list",
|
|
21
|
+
"status",
|
|
22
|
+
"send",
|
|
23
|
+
"stop"
|
|
24
|
+
]);
|
|
25
|
+
const tools = createBackgroundSessionToolContracts().filter(({ id }) => enabledTools.has(id.slice(11))).map((contract) => ({
|
|
26
|
+
description: contract.description,
|
|
27
|
+
inputSchema: contract.inputSchema,
|
|
28
|
+
name: contract.id
|
|
29
|
+
}));
|
|
30
|
+
const serverInfo = {
|
|
31
|
+
name: options.serverName ?? "rivus-background-sessions",
|
|
32
|
+
version: options.serverVersion ?? "1.0.0"
|
|
33
|
+
};
|
|
34
|
+
return { run: () => runMcpServer({
|
|
35
|
+
capability: options.capability,
|
|
36
|
+
controlToken: options.controlToken,
|
|
37
|
+
controlUrl: options.controlUrl,
|
|
38
|
+
fetchImplementation,
|
|
39
|
+
input,
|
|
40
|
+
output,
|
|
41
|
+
serverInfo,
|
|
42
|
+
tools
|
|
43
|
+
}) };
|
|
44
|
+
}
|
|
45
|
+
async function runMcpServer(options) {
|
|
46
|
+
const send = (message) => {
|
|
47
|
+
const body = JSON.stringify(message);
|
|
48
|
+
options.output.write(`${body}\n`);
|
|
49
|
+
};
|
|
50
|
+
for await (const message of readMcpMessages(options.input)) {
|
|
51
|
+
if (!isRecord(message) || !isJsonRpcRequestId(message.id)) continue;
|
|
52
|
+
const method = typeof message.method === "string" ? message.method : void 0;
|
|
53
|
+
if (!method) continue;
|
|
54
|
+
try {
|
|
55
|
+
switch (method) {
|
|
56
|
+
case "initialize":
|
|
57
|
+
send({
|
|
58
|
+
jsonrpc: "2.0",
|
|
59
|
+
id: message.id,
|
|
60
|
+
result: {
|
|
61
|
+
capabilities: { tools: { listChanged: false } },
|
|
62
|
+
protocolVersion: "2025-03-26",
|
|
63
|
+
serverInfo: options.serverInfo
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
break;
|
|
67
|
+
case "ping":
|
|
68
|
+
send({
|
|
69
|
+
jsonrpc: "2.0",
|
|
70
|
+
id: message.id,
|
|
71
|
+
result: {}
|
|
72
|
+
});
|
|
73
|
+
break;
|
|
74
|
+
case "tools/list":
|
|
75
|
+
send({
|
|
76
|
+
jsonrpc: "2.0",
|
|
77
|
+
id: message.id,
|
|
78
|
+
result: { tools: options.tools }
|
|
79
|
+
});
|
|
80
|
+
break;
|
|
81
|
+
case "tools/call": {
|
|
82
|
+
const params = isRecord(message.params) ? message.params : {};
|
|
83
|
+
const name = typeof params.name === "string" ? params.name : "";
|
|
84
|
+
const command = name.startsWith("background.") ? name.slice(11) : void 0;
|
|
85
|
+
if (!command || !options.tools.some((tool) => tool.name === name)) {
|
|
86
|
+
send({
|
|
87
|
+
jsonrpc: "2.0",
|
|
88
|
+
id: message.id,
|
|
89
|
+
error: {
|
|
90
|
+
code: -32602,
|
|
91
|
+
message: `unknown tool: ${name}`
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
const response = await options.fetchImplementation(options.controlUrl, {
|
|
97
|
+
body: JSON.stringify({
|
|
98
|
+
capability: options.capability,
|
|
99
|
+
command,
|
|
100
|
+
input: params.arguments ?? {}
|
|
101
|
+
}),
|
|
102
|
+
headers: {
|
|
103
|
+
authorization: `Bearer ${options.controlToken}`,
|
|
104
|
+
"content-type": "application/json"
|
|
105
|
+
},
|
|
106
|
+
method: "POST"
|
|
107
|
+
});
|
|
108
|
+
const envelope = await response.json();
|
|
109
|
+
if (!response.ok || envelope.error) {
|
|
110
|
+
const messageText = envelope.error?.message ?? `background session control failed with ${response.status}`;
|
|
111
|
+
send({
|
|
112
|
+
jsonrpc: "2.0",
|
|
113
|
+
id: message.id,
|
|
114
|
+
error: {
|
|
115
|
+
code: -32e3,
|
|
116
|
+
message: messageText
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
send({
|
|
122
|
+
jsonrpc: "2.0",
|
|
123
|
+
id: message.id,
|
|
124
|
+
result: {
|
|
125
|
+
content: [{
|
|
126
|
+
text: JSON.stringify(envelope.result ?? null),
|
|
127
|
+
type: "text"
|
|
128
|
+
}],
|
|
129
|
+
isError: false
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
default: send({
|
|
135
|
+
jsonrpc: "2.0",
|
|
136
|
+
id: message.id,
|
|
137
|
+
error: {
|
|
138
|
+
code: -32601,
|
|
139
|
+
message: `method not found: ${method}`
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
} catch (error) {
|
|
144
|
+
send({
|
|
145
|
+
jsonrpc: "2.0",
|
|
146
|
+
id: message.id,
|
|
147
|
+
error: {
|
|
148
|
+
code: -32e3,
|
|
149
|
+
message: error instanceof Error ? error.message : String(error)
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
async function* readMcpMessages(input) {
|
|
156
|
+
let buffer = "";
|
|
157
|
+
for await (const chunk of input) {
|
|
158
|
+
buffer += chunk.toString("utf8");
|
|
159
|
+
let newlineIndex = buffer.indexOf("\n");
|
|
160
|
+
while (newlineIndex >= 0) {
|
|
161
|
+
const line = buffer.slice(0, newlineIndex).replace(/\r$/, "");
|
|
162
|
+
buffer = buffer.slice(newlineIndex + 1);
|
|
163
|
+
if (line.trim() !== "") yield parseMcpMessage(line);
|
|
164
|
+
newlineIndex = buffer.indexOf("\n");
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
if (buffer.trim() !== "") yield parseMcpMessage(buffer.trim());
|
|
168
|
+
}
|
|
169
|
+
function parseMcpMessage(payload) {
|
|
170
|
+
try {
|
|
171
|
+
return JSON.parse(payload);
|
|
172
|
+
} catch {
|
|
173
|
+
throw new BackgroundSessionMcpError("invalid MCP JSON payload");
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
function isJsonRpcRequestId(value) {
|
|
177
|
+
return value === null || typeof value === "string" || typeof value === "number";
|
|
178
|
+
}
|
|
179
|
+
function isRecord(value) {
|
|
180
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
181
|
+
}
|
|
182
|
+
//#endregion
|
|
183
|
+
//#region src/bootstrap/mcp/rivus-mcp-entrypoint.ts
|
|
184
|
+
async function runBackgroundSessionMcpServer(options = {}) {
|
|
185
|
+
const controlUrl = requireEnv("RIVUS_MCP_CONTROL_URL");
|
|
186
|
+
const controlToken = requireEnv("RIVUS_MCP_CONTROL_TOKEN");
|
|
187
|
+
const capability = requireEnv("RIVUS_MCP_CAPABILITY");
|
|
188
|
+
const enabledTools = optionalEnv("RIVUS_MCP_TOOLS")?.split(",").map((tool) => tool.trim()).filter(Boolean);
|
|
189
|
+
await createBackgroundSessionMcpServer({
|
|
190
|
+
capability,
|
|
191
|
+
controlToken,
|
|
192
|
+
controlUrl,
|
|
193
|
+
...enabledTools ? { enabledTools } : {},
|
|
194
|
+
...options.fetch ? { fetch: options.fetch } : {},
|
|
195
|
+
...options.input ? { input: options.input } : {},
|
|
196
|
+
...options.output ? { output: options.output } : {}
|
|
197
|
+
}).run();
|
|
198
|
+
}
|
|
199
|
+
function requireEnv(name) {
|
|
200
|
+
const value = process.env[name]?.trim();
|
|
201
|
+
if (!value) throw new BackgroundSessionMcpError(`${name} is required`);
|
|
202
|
+
return value;
|
|
203
|
+
}
|
|
204
|
+
function optionalEnv(name) {
|
|
205
|
+
return process.env[name]?.trim() || void 0;
|
|
206
|
+
}
|
|
207
|
+
//#endregion
|
|
208
|
+
//#region src/core/application/background-session/control/background-session-control.ts
|
|
209
|
+
function createBackgroundSessionControl$1(options) {
|
|
210
|
+
return { handle: async (command, context, input) => {
|
|
211
|
+
const executionContext = {
|
|
212
|
+
agentId: context.agentId,
|
|
213
|
+
callId: `mcp-call:${options.createId()}`,
|
|
214
|
+
instanceId: `mcp:${context.agentId}`,
|
|
215
|
+
policyEpoch: context.policyEpoch,
|
|
216
|
+
runId: context.runId,
|
|
217
|
+
sessionKey: context.sessionKey,
|
|
218
|
+
sourceMessageId: context.sourceMessageId,
|
|
219
|
+
toolId: `background.${command}`,
|
|
220
|
+
toolVersion: "1.0.0",
|
|
221
|
+
origin: toToolOrigin(context.origin)
|
|
222
|
+
};
|
|
223
|
+
switch (command) {
|
|
224
|
+
case "start": {
|
|
225
|
+
const { displayName, prompt } = readObject(input, ["displayName", "prompt"]);
|
|
226
|
+
if (typeof prompt !== "string" || prompt.trim() === "") throw new BackgroundSessionControlError("background.start requires a non-empty prompt");
|
|
227
|
+
const sessionId = `bg-${options.createId()}`;
|
|
228
|
+
return options.service.start({
|
|
229
|
+
authority: {
|
|
230
|
+
...context.authority,
|
|
231
|
+
sessionKey: createBackgroundSessionKey(sessionId)
|
|
232
|
+
},
|
|
233
|
+
context: executionContext,
|
|
234
|
+
...displayName === void 0 ? {} : { displayName: readString(displayName, "displayName") },
|
|
235
|
+
prompt,
|
|
236
|
+
sessionId
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
case "wait": return options.service.wait({
|
|
240
|
+
context: executionContext,
|
|
241
|
+
...readBackgroundSessionWaitInput(input, (message) => new BackgroundSessionControlError(message))
|
|
242
|
+
});
|
|
243
|
+
case "list": {
|
|
244
|
+
const { limit, phase } = readObject(input, ["limit", "phase"]);
|
|
245
|
+
return options.service.list({
|
|
246
|
+
context: executionContext,
|
|
247
|
+
...limit === void 0 ? {} : { limit: readInteger(limit, "limit") },
|
|
248
|
+
...phase === void 0 ? {} : { phase: readPhase(phase) }
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
case "status": {
|
|
252
|
+
const { sessionId } = readObject(input, ["sessionId"]);
|
|
253
|
+
return options.service.status({
|
|
254
|
+
context: executionContext,
|
|
255
|
+
sessionId: readString(sessionId, "sessionId")
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
case "send": {
|
|
259
|
+
const { message, sessionId } = readObject(input, ["message", "sessionId"]);
|
|
260
|
+
return options.service.send({
|
|
261
|
+
context: executionContext,
|
|
262
|
+
message: readString(message, "message"),
|
|
263
|
+
sessionId: readString(sessionId, "sessionId")
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
case "stop": {
|
|
267
|
+
const { reason, sessionId } = readObject(input, ["reason", "sessionId"]);
|
|
268
|
+
return options.service.stop({
|
|
269
|
+
context: executionContext,
|
|
270
|
+
...reason === void 0 ? {} : { reason: readString(reason, "reason") },
|
|
271
|
+
sessionId: readString(sessionId, "sessionId")
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
} };
|
|
276
|
+
}
|
|
277
|
+
var BackgroundSessionControlError = class extends Error {
|
|
278
|
+
name = "BackgroundSessionControlError";
|
|
279
|
+
};
|
|
280
|
+
function toControlContext$1(input) {
|
|
281
|
+
return {
|
|
282
|
+
agentId: input.agentId,
|
|
283
|
+
authority: input.authority,
|
|
284
|
+
origin: {
|
|
285
|
+
allowedActorOpenIds: input.origin.allowedActorOpenIds,
|
|
286
|
+
...input.origin.conversationId === void 0 ? {} : { conversationId: input.origin.conversationId },
|
|
287
|
+
endpointId: input.origin.endpointId,
|
|
288
|
+
tenantKey: input.origin.tenantKey
|
|
289
|
+
},
|
|
290
|
+
policyEpoch: input.policyEpoch,
|
|
291
|
+
runId: `mcp:${input.createId()}`,
|
|
292
|
+
sessionKey: input.sessionKey,
|
|
293
|
+
sourceMessageId: input.sourceMessageId ?? `mcp:${input.createId()}`
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
function toToolOrigin(origin) {
|
|
297
|
+
return {
|
|
298
|
+
allowedActorOpenIds: origin.allowedActorOpenIds,
|
|
299
|
+
endpointId: origin.endpointId,
|
|
300
|
+
tenantKey: origin.tenantKey,
|
|
301
|
+
...origin.conversationId === void 0 ? {} : { conversationId: origin.conversationId }
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
function readObject(input, allowed) {
|
|
305
|
+
return readBackgroundSessionObject(input, allowed, (message) => new BackgroundSessionControlError(message));
|
|
306
|
+
}
|
|
307
|
+
function readString(value, name) {
|
|
308
|
+
return readBackgroundSessionString(value, name, (message) => new BackgroundSessionControlError(message));
|
|
309
|
+
}
|
|
310
|
+
function readInteger(value, name) {
|
|
311
|
+
return readBackgroundSessionInteger(value, name, (message) => new BackgroundSessionControlError(message));
|
|
312
|
+
}
|
|
313
|
+
function readPhase(value) {
|
|
314
|
+
return readBackgroundSessionPhase(value, (message) => new BackgroundSessionControlError(message));
|
|
315
|
+
}
|
|
316
|
+
//#endregion
|
|
317
|
+
//#region src/adapters/compatibility/background-session/control.ts
|
|
318
|
+
function createBackgroundSessionControl(options) {
|
|
319
|
+
return createBackgroundSessionControl$1({
|
|
320
|
+
createId: createRandomId,
|
|
321
|
+
service: options.service
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
function toControlContext(input) {
|
|
325
|
+
return toControlContext$1({
|
|
326
|
+
...input,
|
|
327
|
+
createId: createRandomId
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
//#endregion
|
|
331
|
+
//#region src/adapters/http/background-session/background-session-control-http-server.ts
|
|
332
|
+
var BackgroundSessionControlHttpError = class extends Error {
|
|
333
|
+
statusCode;
|
|
334
|
+
name = "BackgroundSessionControlHttpError";
|
|
335
|
+
constructor(statusCode, message) {
|
|
336
|
+
super(message);
|
|
337
|
+
this.statusCode = statusCode;
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
const COMMANDS = [
|
|
341
|
+
"start",
|
|
342
|
+
"wait",
|
|
343
|
+
"list",
|
|
344
|
+
"status",
|
|
345
|
+
"send",
|
|
346
|
+
"stop"
|
|
347
|
+
];
|
|
348
|
+
function createBackgroundSessionControlHttpServer(options) {
|
|
349
|
+
let server;
|
|
350
|
+
let boundPort = options.port;
|
|
351
|
+
const capabilities = /* @__PURE__ */ new Map();
|
|
352
|
+
const capabilitiesBySessionKey = /* @__PURE__ */ new Map();
|
|
353
|
+
const serverHandle = createServer((request, response) => {
|
|
354
|
+
(async () => {
|
|
355
|
+
try {
|
|
356
|
+
if (request.method === "GET" && request.url === "/background-sessions/status") {
|
|
357
|
+
if (request.headers.authorization !== `Bearer ${options.token}`) throw new BackgroundSessionControlHttpError(401, "unauthorized");
|
|
358
|
+
respond(response, 200, {
|
|
359
|
+
ok: true,
|
|
360
|
+
result: options.status?.() ?? null
|
|
361
|
+
});
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
if (request.method !== "POST" || request.url !== "/background-sessions") throw new BackgroundSessionControlHttpError(404, "not found");
|
|
365
|
+
if (request.headers.authorization !== `Bearer ${options.token}`) throw new BackgroundSessionControlHttpError(401, "unauthorized");
|
|
366
|
+
const envelope = parseEnvelope(await readBody(request, 64 * 1024));
|
|
367
|
+
const context = capabilities.get(envelope.capability);
|
|
368
|
+
if (!context) throw new BackgroundSessionControlHttpError(401, "unknown or expired capability");
|
|
369
|
+
const command = envelope.command;
|
|
370
|
+
if (!COMMANDS.includes(command)) throw new BackgroundSessionControlHttpError(400, `unsupported background session command: ${String(command)}`);
|
|
371
|
+
respond(response, 200, {
|
|
372
|
+
ok: true,
|
|
373
|
+
result: await options.control.handle(command, context, envelope.input)
|
|
374
|
+
});
|
|
375
|
+
} catch (error) {
|
|
376
|
+
respond(response, error instanceof BackgroundSessionControlHttpError ? error.statusCode : 500, {
|
|
377
|
+
error: {
|
|
378
|
+
message: error instanceof Error ? error.message : String(error),
|
|
379
|
+
name: error instanceof Error ? error.name : "Error"
|
|
380
|
+
},
|
|
381
|
+
ok: false
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
})();
|
|
385
|
+
});
|
|
386
|
+
serverHandle.on("error", () => void 0);
|
|
387
|
+
return {
|
|
388
|
+
port: () => boundPort,
|
|
389
|
+
close: async () => {
|
|
390
|
+
const active = server;
|
|
391
|
+
server = void 0;
|
|
392
|
+
capabilities.clear();
|
|
393
|
+
capabilitiesBySessionKey.clear();
|
|
394
|
+
if (active) await new Promise((resolve) => active.close(() => resolve()));
|
|
395
|
+
},
|
|
396
|
+
issueCapability: (context) => {
|
|
397
|
+
const existing = capabilitiesBySessionKey.get(context.sessionKey);
|
|
398
|
+
if (existing) return existing;
|
|
399
|
+
const capability = randomUUID();
|
|
400
|
+
capabilities.set(capability, context);
|
|
401
|
+
capabilitiesBySessionKey.set(context.sessionKey, capability);
|
|
402
|
+
return capability;
|
|
403
|
+
},
|
|
404
|
+
start: async () => {
|
|
405
|
+
if (server) return;
|
|
406
|
+
await new Promise((resolve, reject) => {
|
|
407
|
+
server = serverHandle;
|
|
408
|
+
serverHandle.listen(options.port, options.host ?? "127.0.0.1", () => {
|
|
409
|
+
const address = serverHandle.address();
|
|
410
|
+
if (address !== null && typeof address === "object") boundPort = address.port;
|
|
411
|
+
resolve();
|
|
412
|
+
});
|
|
413
|
+
serverHandle.once("error", (error) => {
|
|
414
|
+
server = void 0;
|
|
415
|
+
reject(error);
|
|
416
|
+
});
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
function respond(response, statusCode, body) {
|
|
422
|
+
response.writeHead(statusCode, { "content-type": "application/json" });
|
|
423
|
+
response.end(JSON.stringify(body));
|
|
424
|
+
}
|
|
425
|
+
function parseEnvelope(body) {
|
|
426
|
+
const parsed = JSON.parse(body);
|
|
427
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) throw new BackgroundSessionControlHttpError(400, "invalid background session control envelope");
|
|
428
|
+
const record = parsed;
|
|
429
|
+
if (typeof record.command !== "string" || typeof record.capability !== "string") throw new BackgroundSessionControlHttpError(400, "background session control envelope requires command and capability");
|
|
430
|
+
return {
|
|
431
|
+
capability: record.capability,
|
|
432
|
+
command: record.command,
|
|
433
|
+
input: record.input
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
function readBody(request, maxBytes) {
|
|
437
|
+
return new Promise((resolve, reject) => {
|
|
438
|
+
const chunks = [];
|
|
439
|
+
let total = 0;
|
|
440
|
+
request.on("data", (chunk) => {
|
|
441
|
+
total += chunk.length;
|
|
442
|
+
if (total > maxBytes) {
|
|
443
|
+
reject(new BackgroundSessionControlHttpError(413, "background session control request too large"));
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
chunks.push(chunk);
|
|
447
|
+
});
|
|
448
|
+
request.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
//#endregion
|
|
452
|
+
//#region src/mcp.ts
|
|
453
|
+
if (pathToFileURL(process.argv[1] ?? "").href === import.meta.url) await runBackgroundSessionMcpServer();
|
|
454
|
+
//#endregion
|
|
455
|
+
export { BACKGROUND_SESSION_MCP_SERVER_NAME, BACKGROUND_SESSION_MCP_SERVER_VERSION, BackgroundSessionControlError, BackgroundSessionControlHttpError, BackgroundSessionMcpError, createBackgroundSessionControl, createBackgroundSessionControlHttpServer, createBackgroundSessionMcpServer, runBackgroundSessionMcpServer, toControlContext };
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rivus/gateway",
|
|
3
|
+
"version": "0.16.2",
|
|
4
|
+
"description": "Message gateway, channels, host binding, automation, and daemon assembly for Rivus.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": "^24.11.0"
|
|
9
|
+
},
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/PerfectPan/rivus-agent.git",
|
|
13
|
+
"directory": "packages/gateway"
|
|
14
|
+
},
|
|
15
|
+
"homepage": "https://github.com/PerfectPan/rivus-agent#readme",
|
|
16
|
+
"bugs": {
|
|
17
|
+
"url": "https://github.com/PerfectPan/rivus-agent/issues"
|
|
18
|
+
},
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"import": "./dist/index.js",
|
|
23
|
+
"default": "./dist/index.js"
|
|
24
|
+
},
|
|
25
|
+
"./mcp": {
|
|
26
|
+
"types": "./dist/mcp.d.ts",
|
|
27
|
+
"import": "./dist/mcp.js",
|
|
28
|
+
"default": "./dist/mcp.js"
|
|
29
|
+
},
|
|
30
|
+
"./bootstrap/pi-feishu": {
|
|
31
|
+
"types": "./dist/bootstrap/pi-feishu.d.ts",
|
|
32
|
+
"import": "./dist/bootstrap/pi-feishu.js",
|
|
33
|
+
"default": "./dist/bootstrap/pi-feishu.js"
|
|
34
|
+
},
|
|
35
|
+
"./cli": "./dist/cli.js",
|
|
36
|
+
"./plugin/starter": "./templates/rivus-starter.plugin.mjs",
|
|
37
|
+
"./skills/runtime-management/SKILL.md": "./skills/runtime-management/SKILL.md",
|
|
38
|
+
"./package.json": "./package.json"
|
|
39
|
+
},
|
|
40
|
+
"files": [
|
|
41
|
+
"dist",
|
|
42
|
+
"templates/*.mjs",
|
|
43
|
+
"templates/*.bootstrap.ts",
|
|
44
|
+
"templates/*.json",
|
|
45
|
+
"skills",
|
|
46
|
+
"README.md",
|
|
47
|
+
"LICENSE"
|
|
48
|
+
],
|
|
49
|
+
"scripts": {
|
|
50
|
+
"build": "node ../../scripts/generate-gateway-release-descriptor.mjs && vp pack",
|
|
51
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
52
|
+
"test": "vp test --run"
|
|
53
|
+
},
|
|
54
|
+
"dependencies": {
|
|
55
|
+
"@rivus/platform": "0.16.2",
|
|
56
|
+
"@rivus/runtime": "0.16.2",
|
|
57
|
+
"@larksuiteoapi/node-sdk": "1.71.1",
|
|
58
|
+
"axios": "1.18.0",
|
|
59
|
+
"effect": "^3.21.4"
|
|
60
|
+
},
|
|
61
|
+
"publishConfig": {
|
|
62
|
+
"access": "public"
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
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
|
+
The default is shared by every Agent in the current Home, including their background Sessions. Describe that scope when
|
|
33
|
+
submitting a change. If the user asks to change only one Agent, explain that per-Agent overrides are unsupported and
|
|
34
|
+
resolve the requested scope before submitting a Home-wide change.
|
|
35
|
+
|
|
36
|
+
Use the exact `provider/model` value confirmed by the Host. First obtain the current `revision`, then submit one request
|
|
37
|
+
with a fresh request id:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
rivus model set --model <provider/model> --expected-revision <revision> --request <request-id> --json
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The first response confirms receipt. When the response is `pending`, report its `requestId` and finish the current Run.
|
|
44
|
+
The Host completes validation and activation across the safe boundary and sends the final notification. A later Run can
|
|
45
|
+
query the request to determine whether the final state is `applied`, `failed`, `restored`, or `recovery-required`.
|
|
46
|
+
Keep the same request id after a disconnect instead of submitting the change again with a new id.
|
|
47
|
+
|
|
48
|
+
## Restore the previous model
|
|
49
|
+
|
|
50
|
+
Use the same revision and request rules:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
rivus model rollback --expected-revision <revision> --request <request-id> --json
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
If there is no previous selection, or the provider no longer supports it, report the returned limitation. Restoring a
|
|
57
|
+
model does not undo messages, memory, or completed business effects.
|
|
58
|
+
|
|
59
|
+
## Trust and scope
|
|
60
|
+
|
|
61
|
+
Only a trusted Host Run can authorize `set` and `rollback`. A local client without that context can read diagnostics but
|
|
62
|
+
cannot grant itself permission. Do not add identity, owner, Home, credential, or authorization fields to a command.
|
|
63
|
+
|
|
64
|
+
When a command reports `failed` or `recovery-required`, preserve the returned error code and request id. Do not infer
|
|
65
|
+
success from process exit code `0`; inspect the JSON business status.
|