@kynver-app/openclaw-agent-os 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +104 -0
- package/dist/index.js +981 -0
- package/dist/index.js.map +7 -0
- package/openclaw.plugin.json +91 -0
- package/package.json +47 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,981 @@
|
|
|
1
|
+
// src/config.ts
|
|
2
|
+
var pluginConfigSchema = {
|
|
3
|
+
type: "object",
|
|
4
|
+
additionalProperties: false,
|
|
5
|
+
properties: {
|
|
6
|
+
agentOsServer: {
|
|
7
|
+
type: "string",
|
|
8
|
+
default: "kynver-agent-os",
|
|
9
|
+
description: "mcporter server name for the Kynver AgentOS MCP server"
|
|
10
|
+
},
|
|
11
|
+
timeoutMs: {
|
|
12
|
+
type: "number",
|
|
13
|
+
default: 3e4,
|
|
14
|
+
description: "Timeout in milliseconds for mcporter calls"
|
|
15
|
+
},
|
|
16
|
+
mcporterConfigPath: {
|
|
17
|
+
type: "string",
|
|
18
|
+
description: "Explicit path to mcporter.json. Defaults to MCPORTER_CONFIG, OPENCLAW_MCPORTER_CONFIG, then ~/.openclaw/workspace/config/mcporter.json."
|
|
19
|
+
},
|
|
20
|
+
kynverApiUrl: {
|
|
21
|
+
type: "string",
|
|
22
|
+
description: "Kynver API origin for direct HTTP mode, for example https://www.kynver.com. Falls back to KYNVER_API_URL or mcporter env."
|
|
23
|
+
},
|
|
24
|
+
kynverApiKey: {
|
|
25
|
+
type: "string",
|
|
26
|
+
description: "Kynver API key for direct HTTP mode. Prefer OpenClaw secret references when available."
|
|
27
|
+
},
|
|
28
|
+
agentOsSlug: {
|
|
29
|
+
type: "string",
|
|
30
|
+
default: "ghost",
|
|
31
|
+
description: "Default AgentOS slug to use when a tool call does not pass slug."
|
|
32
|
+
},
|
|
33
|
+
enableDirectHttp: {
|
|
34
|
+
type: "boolean",
|
|
35
|
+
default: true,
|
|
36
|
+
description: "Use Kynver's AgentOS HTTP API directly when configured; mcporter remains the compatibility fallback."
|
|
37
|
+
},
|
|
38
|
+
enableSessionLifecycle: {
|
|
39
|
+
type: "boolean",
|
|
40
|
+
default: true,
|
|
41
|
+
description: "Automatically open and close AgentOS session records from OpenClaw session lifecycle hooks."
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
function resolvePluginConfig(raw) {
|
|
46
|
+
return {
|
|
47
|
+
agentOsServer: typeof raw?.agentOsServer === "string" && raw.agentOsServer.trim() ? raw.agentOsServer.trim() : "kynver-agent-os",
|
|
48
|
+
timeoutMs: typeof raw?.timeoutMs === "number" && Number.isFinite(raw.timeoutMs) && raw.timeoutMs > 0 ? raw.timeoutMs : 3e4,
|
|
49
|
+
mcporterConfigPath: typeof raw?.mcporterConfigPath === "string" && raw.mcporterConfigPath.trim() ? raw.mcporterConfigPath.trim() : void 0,
|
|
50
|
+
kynverApiUrl: typeof raw?.kynverApiUrl === "string" && raw.kynverApiUrl.trim() ? raw.kynverApiUrl.trim().replace(/\/$/, "") : void 0,
|
|
51
|
+
kynverApiKey: typeof raw?.kynverApiKey === "string" && raw.kynverApiKey.trim() ? raw.kynverApiKey.trim() : void 0,
|
|
52
|
+
agentOsSlug: typeof raw?.agentOsSlug === "string" && raw.agentOsSlug.trim() ? raw.agentOsSlug.trim() : "ghost",
|
|
53
|
+
enableDirectHttp: typeof raw?.enableDirectHttp === "boolean" ? raw.enableDirectHttp : true,
|
|
54
|
+
enableSessionLifecycle: typeof raw?.enableSessionLifecycle === "boolean" ? raw.enableSessionLifecycle : true
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// src/mcporter-client.ts
|
|
59
|
+
import { execFile } from "node:child_process";
|
|
60
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
61
|
+
import path from "node:path";
|
|
62
|
+
import { fileURLToPath } from "node:url";
|
|
63
|
+
import { promisify } from "node:util";
|
|
64
|
+
|
|
65
|
+
// src/result.ts
|
|
66
|
+
function toolJson(payload) {
|
|
67
|
+
return {
|
|
68
|
+
content: [{ type: "text", text: JSON.stringify(payload, null, 2) }],
|
|
69
|
+
details: payload
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function toolError(message, details) {
|
|
73
|
+
return {
|
|
74
|
+
content: [{ type: "text", text: message }],
|
|
75
|
+
details,
|
|
76
|
+
isError: true
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// src/mcporter-client.ts
|
|
81
|
+
var execFileAsync = promisify(execFile);
|
|
82
|
+
async function callAgentOsTool({
|
|
83
|
+
serverName,
|
|
84
|
+
toolName,
|
|
85
|
+
params,
|
|
86
|
+
timeoutMs,
|
|
87
|
+
mcporterConfigPath,
|
|
88
|
+
kynverApiUrl,
|
|
89
|
+
kynverApiKey,
|
|
90
|
+
agentOsSlug,
|
|
91
|
+
enableDirectHttp = true
|
|
92
|
+
}) {
|
|
93
|
+
const configPath = resolveMcporterConfigPath(mcporterConfigPath);
|
|
94
|
+
const directConfig = enableDirectHttp ? resolveDirectAgentOsConfig({ serverName, configPath, kynverApiUrl, kynverApiKey, agentOsSlug }) : void 0;
|
|
95
|
+
if (directConfig) {
|
|
96
|
+
try {
|
|
97
|
+
return toolJson(await callAgentOsApiDirect(toolName, params ?? {}, timeoutMs, directConfig));
|
|
98
|
+
} catch (error) {
|
|
99
|
+
if (!isDirectConfigError(error)) {
|
|
100
|
+
return toolError(`Kynver AgentOS direct call failed for ${toolName}.`, {
|
|
101
|
+
toolName,
|
|
102
|
+
serverName,
|
|
103
|
+
message: redactSecrets(String(error?.message || error))
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
const selector = `${serverName}.${toolName}`;
|
|
109
|
+
const args = ["--config", configPath, "call", selector];
|
|
110
|
+
const hasParams = params && Object.keys(params).length > 0;
|
|
111
|
+
if (hasParams) {
|
|
112
|
+
args.push("--args", JSON.stringify(params));
|
|
113
|
+
}
|
|
114
|
+
try {
|
|
115
|
+
const { stdout, stderr } = await execFileAsync("mcporter", args, {
|
|
116
|
+
timeout: timeoutMs,
|
|
117
|
+
maxBuffer: 1024 * 1024 * 4
|
|
118
|
+
});
|
|
119
|
+
const text = `${stdout || ""}${stderr || ""}`.trim();
|
|
120
|
+
const parsed = parseMcporterOutput(text);
|
|
121
|
+
return toolJson(parsed);
|
|
122
|
+
} catch (error) {
|
|
123
|
+
const msg = String(error?.message || error);
|
|
124
|
+
if (msg.includes("timed out")) {
|
|
125
|
+
return toolError(`Kynver AgentOS call timed out after ${timeoutMs}ms.`, { toolName, serverName });
|
|
126
|
+
}
|
|
127
|
+
return toolError(`Kynver AgentOS call failed for ${toolName}.`, {
|
|
128
|
+
toolName,
|
|
129
|
+
serverName,
|
|
130
|
+
message: msg,
|
|
131
|
+
stdout: error?.stdout,
|
|
132
|
+
stderr: error?.stderr
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
async function checkAgentOsHealth({
|
|
137
|
+
serverName,
|
|
138
|
+
slug,
|
|
139
|
+
timeoutMs,
|
|
140
|
+
mcporterConfigPath,
|
|
141
|
+
kynverApiUrl,
|
|
142
|
+
kynverApiKey,
|
|
143
|
+
agentOsSlug,
|
|
144
|
+
enableDirectHttp = true
|
|
145
|
+
}) {
|
|
146
|
+
const startedAt = Date.now();
|
|
147
|
+
const configPath = resolveMcporterConfigPath(mcporterConfigPath);
|
|
148
|
+
const directConfig = enableDirectHttp ? resolveDirectAgentOsConfig({ serverName, configPath, kynverApiUrl, kynverApiKey, agentOsSlug }) : void 0;
|
|
149
|
+
if (directConfig) {
|
|
150
|
+
try {
|
|
151
|
+
const parsed = await callAgentOsApiDirect("agent_os_get_context", slug ? { slug } : {}, timeoutMs, directConfig);
|
|
152
|
+
const summary = summarizeContextPayload(parsed);
|
|
153
|
+
return toolJson({
|
|
154
|
+
ok: true,
|
|
155
|
+
status: "available",
|
|
156
|
+
transport: "direct-http",
|
|
157
|
+
serverName,
|
|
158
|
+
probeTool: "agent_os_get_context",
|
|
159
|
+
latencyMs: Date.now() - startedAt,
|
|
160
|
+
checkedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
161
|
+
configPath,
|
|
162
|
+
...summary
|
|
163
|
+
});
|
|
164
|
+
} catch (error) {
|
|
165
|
+
return toolJson({
|
|
166
|
+
ok: false,
|
|
167
|
+
status: "unavailable",
|
|
168
|
+
transport: "direct-http",
|
|
169
|
+
serverName,
|
|
170
|
+
probeTool: "agent_os_get_context",
|
|
171
|
+
latencyMs: Date.now() - startedAt,
|
|
172
|
+
checkedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
173
|
+
configPath,
|
|
174
|
+
error: sanitizeHealthError(error)
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
const selector = `${serverName}.agent_os_get_context`;
|
|
179
|
+
const args = ["--config", configPath, "call", selector];
|
|
180
|
+
if (slug) {
|
|
181
|
+
args.push("--args", JSON.stringify({ slug }));
|
|
182
|
+
}
|
|
183
|
+
try {
|
|
184
|
+
const { stdout, stderr } = await execFileAsync("mcporter", args, {
|
|
185
|
+
timeout: timeoutMs,
|
|
186
|
+
maxBuffer: 1024 * 1024 * 4
|
|
187
|
+
});
|
|
188
|
+
const text = `${stdout || ""}${stderr || ""}`.trim();
|
|
189
|
+
const parsed = parseMcporterOutput(text);
|
|
190
|
+
const summary = summarizeContextPayload(parsed);
|
|
191
|
+
return toolJson({
|
|
192
|
+
ok: true,
|
|
193
|
+
status: "available",
|
|
194
|
+
serverName,
|
|
195
|
+
probeTool: "agent_os_get_context",
|
|
196
|
+
latencyMs: Date.now() - startedAt,
|
|
197
|
+
checkedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
198
|
+
configPath,
|
|
199
|
+
...summary
|
|
200
|
+
});
|
|
201
|
+
} catch (error) {
|
|
202
|
+
return toolJson({
|
|
203
|
+
ok: false,
|
|
204
|
+
status: "unavailable",
|
|
205
|
+
serverName,
|
|
206
|
+
probeTool: "agent_os_get_context",
|
|
207
|
+
latencyMs: Date.now() - startedAt,
|
|
208
|
+
checkedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
209
|
+
configPath,
|
|
210
|
+
error: sanitizeHealthError(error)
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
function resolveDirectAgentOsConfig({
|
|
215
|
+
serverName,
|
|
216
|
+
configPath,
|
|
217
|
+
kynverApiUrl,
|
|
218
|
+
kynverApiKey,
|
|
219
|
+
agentOsSlug
|
|
220
|
+
}) {
|
|
221
|
+
if (kynverApiUrl?.trim()) {
|
|
222
|
+
return {
|
|
223
|
+
apiUrl: kynverApiUrl.trim().replace(/\/$/, ""),
|
|
224
|
+
apiKey: kynverApiKey?.trim() || void 0,
|
|
225
|
+
defaultSlug: agentOsSlug?.trim() || "ghost"
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
const envConfig = directConfigFromEnv(agentOsSlug, kynverApiKey);
|
|
229
|
+
if (envConfig) return envConfig;
|
|
230
|
+
try {
|
|
231
|
+
const parsed = JSON.parse(readFileSync(configPath, "utf8"));
|
|
232
|
+
const server = parsed?.mcpServers?.[serverName];
|
|
233
|
+
const env = server?.env;
|
|
234
|
+
const apiUrl = typeof env?.KYNVER_API_URL === "string" ? env.KYNVER_API_URL.trim() : "";
|
|
235
|
+
if (!apiUrl) return void 0;
|
|
236
|
+
return {
|
|
237
|
+
apiUrl: apiUrl.replace(/\/$/, ""),
|
|
238
|
+
apiKey: typeof env?.KYNVER_API_KEY === "string" ? env.KYNVER_API_KEY.trim() : void 0,
|
|
239
|
+
defaultSlug: agentOsSlug?.trim() || (typeof env?.KYNVER_AGENT_OS_SLUG === "string" && env.KYNVER_AGENT_OS_SLUG.trim() ? env.KYNVER_AGENT_OS_SLUG.trim() : "ghost")
|
|
240
|
+
};
|
|
241
|
+
} catch {
|
|
242
|
+
return void 0;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
function directConfigFromEnv(agentOsSlug, kynverApiKey) {
|
|
246
|
+
const apiUrl = process.env.KYNVER_API_URL?.trim();
|
|
247
|
+
if (!apiUrl) return void 0;
|
|
248
|
+
return {
|
|
249
|
+
apiUrl: apiUrl.replace(/\/$/, ""),
|
|
250
|
+
apiKey: kynverApiKey?.trim() || process.env.KYNVER_API_KEY?.trim() || void 0,
|
|
251
|
+
defaultSlug: agentOsSlug?.trim() || process.env.KYNVER_AGENT_OS_SLUG?.trim() || "ghost"
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
function isDirectConfigError(error) {
|
|
255
|
+
return error?.code === "AGENT_OS_DIRECT_CONFIG";
|
|
256
|
+
}
|
|
257
|
+
async function callAgentOsApiDirect(toolName, params, timeoutMs, config) {
|
|
258
|
+
const { slug, path: path2, method, body } = directRequestForTool(toolName, params, config.defaultSlug);
|
|
259
|
+
if (!slug) {
|
|
260
|
+
const error = new Error("AgentOS slug could not be resolved.");
|
|
261
|
+
error.code = "AGENT_OS_DIRECT_CONFIG";
|
|
262
|
+
throw error;
|
|
263
|
+
}
|
|
264
|
+
const controller = new AbortController();
|
|
265
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
266
|
+
try {
|
|
267
|
+
const res = await fetch(`${config.apiUrl}/api/agent-os/${encodeURIComponent(slug)}${path2}`, {
|
|
268
|
+
method,
|
|
269
|
+
headers: {
|
|
270
|
+
"Content-Type": "application/json",
|
|
271
|
+
...config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}
|
|
272
|
+
},
|
|
273
|
+
...body === void 0 ? {} : { body: JSON.stringify(body) },
|
|
274
|
+
signal: controller.signal
|
|
275
|
+
});
|
|
276
|
+
const text = await res.text();
|
|
277
|
+
const payload = text ? safeJson(text) ?? text : {};
|
|
278
|
+
if (!res.ok) {
|
|
279
|
+
const message = payload && typeof payload === "object" && "error" in payload ? String(payload.error) : `HTTP ${res.status}`;
|
|
280
|
+
throw new Error(message);
|
|
281
|
+
}
|
|
282
|
+
return payload;
|
|
283
|
+
} finally {
|
|
284
|
+
clearTimeout(timer);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
function directRequestForTool(toolName, params, defaultSlug) {
|
|
288
|
+
const slug = stringParam(params.slug) || defaultSlug;
|
|
289
|
+
const withoutSlug = stripKeys(params, ["slug"]);
|
|
290
|
+
switch (toolName) {
|
|
291
|
+
case "agent_os_get_context":
|
|
292
|
+
return { slug, method: "GET", path: "/stats" };
|
|
293
|
+
case "agent_os_open_session":
|
|
294
|
+
return { slug, method: "POST", path: "/sessions", body: withoutSlug };
|
|
295
|
+
case "agent_os_close_session": {
|
|
296
|
+
const sessionId = requiredString(params.sessionId, "sessionId");
|
|
297
|
+
return { slug, method: "PATCH", path: `/sessions/${encodeURIComponent(sessionId)}`, body: stripKeys(params, ["slug", "sessionId"]) };
|
|
298
|
+
}
|
|
299
|
+
case "agent_os_log_session": {
|
|
300
|
+
const topics = arrayParam(params.topicsWorked);
|
|
301
|
+
const decisions = arrayParam(params.keyDecisions);
|
|
302
|
+
const lines = [requiredString(params.summary, "summary")];
|
|
303
|
+
if (topics.length) lines.push(`Topics: ${topics.join(", ")}`);
|
|
304
|
+
if (decisions.length) lines.push("Key decisions:", ...decisions.map((d) => `- ${d}`));
|
|
305
|
+
return { slug, method: "POST", path: "/daily-log", body: { entry: lines.join("\n"), ...stringParam(params.date) ? { date: stringParam(params.date) } : {} } };
|
|
306
|
+
}
|
|
307
|
+
case "agent_os_list_goals":
|
|
308
|
+
return { slug, method: "GET", path: `/goals${queryString(params, ["status", "projectId"])}` };
|
|
309
|
+
case "agent_os_update_goal": {
|
|
310
|
+
const goalId = stringParam(params.goalId);
|
|
311
|
+
if (goalId) return { slug, method: "PATCH", path: `/goals/${encodeURIComponent(goalId)}`, body: stripKeys(params, ["slug", "goalId"]) };
|
|
312
|
+
return { slug, method: "POST", path: "/goals", body: withoutSlug };
|
|
313
|
+
}
|
|
314
|
+
case "agent_os_get_projects":
|
|
315
|
+
return { slug, method: "GET", path: `/projects${queryString(params, ["status"])}` };
|
|
316
|
+
case "agent_os_create_project":
|
|
317
|
+
return { slug, method: "POST", path: "/projects", body: withoutSlug };
|
|
318
|
+
case "agent_os_update_project": {
|
|
319
|
+
const projectId = requiredString(params.projectId, "projectId");
|
|
320
|
+
return { slug, method: "PATCH", path: `/projects/${encodeURIComponent(projectId)}`, body: stripKeys(params, ["slug", "projectId"]) };
|
|
321
|
+
}
|
|
322
|
+
case "agent_os_search_memory": {
|
|
323
|
+
const q = requiredString(params.query, "query");
|
|
324
|
+
return { slug, method: "GET", path: `/memory?${queryStringFromEntries({ q, k: params.k })}` };
|
|
325
|
+
}
|
|
326
|
+
case "agent_os_write_memory": {
|
|
327
|
+
const categoryToSourceId = {
|
|
328
|
+
long_term: "agent:long-term",
|
|
329
|
+
project: "agent:project",
|
|
330
|
+
contact: "agent:long-term",
|
|
331
|
+
tool_config: "agent:long-term"
|
|
332
|
+
};
|
|
333
|
+
const sourceId = stringParam(params.sourceId) || categoryToSourceId[stringParam(params.category) || ""];
|
|
334
|
+
return {
|
|
335
|
+
slug,
|
|
336
|
+
method: "POST",
|
|
337
|
+
path: "/memory",
|
|
338
|
+
body: compact({
|
|
339
|
+
content: requiredString(params.content, "content"),
|
|
340
|
+
slug: stringParam(params.key),
|
|
341
|
+
sourceId,
|
|
342
|
+
metadata: params.metadata
|
|
343
|
+
})
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
case "agent_os_update_memory":
|
|
347
|
+
return {
|
|
348
|
+
slug,
|
|
349
|
+
method: "POST",
|
|
350
|
+
path: "/memory",
|
|
351
|
+
body: compact({
|
|
352
|
+
content: requiredString(params.content, "content"),
|
|
353
|
+
slug: requiredString(params.key, "key"),
|
|
354
|
+
sourceId: stringParam(params.sourceId),
|
|
355
|
+
metadata: params.metadata
|
|
356
|
+
})
|
|
357
|
+
};
|
|
358
|
+
case "agent_os_get_contacts":
|
|
359
|
+
return { slug, method: "GET", path: "/contacts" };
|
|
360
|
+
case "agent_os_create_contact":
|
|
361
|
+
return { slug, method: "POST", path: "/contacts", body: withoutSlug };
|
|
362
|
+
case "agent_os_update_contact": {
|
|
363
|
+
const contactId = requiredString(params.contactId, "contactId");
|
|
364
|
+
return { slug, method: "PATCH", path: `/contacts/${encodeURIComponent(contactId)}`, body: stripKeys(params, ["slug", "contactId"]) };
|
|
365
|
+
}
|
|
366
|
+
case "agent_os_consolidate_memory":
|
|
367
|
+
return { slug, method: "POST", path: "/consolidate", body: {} };
|
|
368
|
+
default:
|
|
369
|
+
throw new Error(`Unsupported AgentOS direct tool: ${toolName}`);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
function requiredString(value, name) {
|
|
373
|
+
const stringValue = stringParam(value);
|
|
374
|
+
if (!stringValue) throw new Error(`${name} is required`);
|
|
375
|
+
return stringValue;
|
|
376
|
+
}
|
|
377
|
+
function stringParam(value) {
|
|
378
|
+
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
379
|
+
}
|
|
380
|
+
function arrayParam(value) {
|
|
381
|
+
return Array.isArray(value) ? value.filter((item) => typeof item === "string" && !!item.trim()).map((item) => item.trim()) : [];
|
|
382
|
+
}
|
|
383
|
+
function stripKeys(source, keys) {
|
|
384
|
+
const out = {};
|
|
385
|
+
for (const [key, value] of Object.entries(source)) {
|
|
386
|
+
if (!keys.includes(key) && value !== void 0) out[key] = value;
|
|
387
|
+
}
|
|
388
|
+
return out;
|
|
389
|
+
}
|
|
390
|
+
function compact(source) {
|
|
391
|
+
const out = {};
|
|
392
|
+
for (const [key, value] of Object.entries(source)) {
|
|
393
|
+
if (value !== void 0) out[key] = value;
|
|
394
|
+
}
|
|
395
|
+
return out;
|
|
396
|
+
}
|
|
397
|
+
function queryString(params, keys) {
|
|
398
|
+
return queryStringFromEntries(Object.fromEntries(keys.map((key) => [key, params[key]])));
|
|
399
|
+
}
|
|
400
|
+
function queryStringFromEntries(entries) {
|
|
401
|
+
const params = new URLSearchParams();
|
|
402
|
+
for (const [key, value] of Object.entries(entries)) {
|
|
403
|
+
if (typeof value === "string" && value.trim()) params.set(key, value.trim());
|
|
404
|
+
else if (typeof value === "number" && Number.isFinite(value)) params.set(key, String(value));
|
|
405
|
+
}
|
|
406
|
+
const qs = params.toString();
|
|
407
|
+
return qs ? `?${qs}` : "";
|
|
408
|
+
}
|
|
409
|
+
function parseMcporterOutput(text) {
|
|
410
|
+
const trimmed = text.trim();
|
|
411
|
+
if (!trimmed) return { ok: true, empty: true };
|
|
412
|
+
const codeFenceMatch = trimmed.match(/```(?:json)?\s*([\s\S]*?)```/i);
|
|
413
|
+
if (codeFenceMatch) {
|
|
414
|
+
const inner = codeFenceMatch[1].trim();
|
|
415
|
+
return safeJson(inner) ?? { raw: trimmed };
|
|
416
|
+
}
|
|
417
|
+
const firstBrace = trimmed.indexOf("{");
|
|
418
|
+
const firstBracket = trimmed.indexOf("[");
|
|
419
|
+
let start = -1;
|
|
420
|
+
if (firstBrace >= 0 && firstBracket >= 0) start = Math.min(firstBrace, firstBracket);
|
|
421
|
+
else start = Math.max(firstBrace, firstBracket);
|
|
422
|
+
if (start >= 0) {
|
|
423
|
+
const candidate = trimmed.slice(start);
|
|
424
|
+
return safeJson(candidate) ?? { raw: trimmed };
|
|
425
|
+
}
|
|
426
|
+
return { raw: trimmed };
|
|
427
|
+
}
|
|
428
|
+
function safeJson(value) {
|
|
429
|
+
try {
|
|
430
|
+
return JSON.parse(value);
|
|
431
|
+
} catch {
|
|
432
|
+
return null;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
function resolveMcporterConfigPath(configuredPath) {
|
|
436
|
+
const here = fileURLToPath(new URL(".", import.meta.url));
|
|
437
|
+
const candidates = [
|
|
438
|
+
configuredPath,
|
|
439
|
+
process.env.MCPORTER_CONFIG,
|
|
440
|
+
process.env.OPENCLAW_MCPORTER_CONFIG,
|
|
441
|
+
process.env.HOME ? path.resolve(process.env.HOME, ".openclaw/workspace/config/mcporter.json") : void 0,
|
|
442
|
+
path.resolve(here, "../../config/mcporter.json"),
|
|
443
|
+
path.resolve(here, "../../../config/mcporter.json"),
|
|
444
|
+
path.resolve(process.cwd(), "config/mcporter.json")
|
|
445
|
+
].filter((candidate) => Boolean(candidate));
|
|
446
|
+
for (const candidate of candidates) {
|
|
447
|
+
if (existsSync(candidate)) return candidate;
|
|
448
|
+
}
|
|
449
|
+
return path.resolve(process.cwd(), "config/mcporter.json");
|
|
450
|
+
}
|
|
451
|
+
function summarizeContextPayload(payload) {
|
|
452
|
+
if (!payload || typeof payload !== "object") return {};
|
|
453
|
+
const record = payload;
|
|
454
|
+
const identity = record.identity && typeof record.identity === "object" ? record.identity : void 0;
|
|
455
|
+
return {
|
|
456
|
+
slug: typeof identity?.slug === "string" ? identity.slug : void 0,
|
|
457
|
+
openGoalCount: typeof record.openGoalCount === "number" ? record.openGoalCount : void 0,
|
|
458
|
+
projectCount: Array.isArray(record.projects) ? record.projects.length : void 0,
|
|
459
|
+
contactCount: Array.isArray(record.contacts) ? record.contacts.length : void 0,
|
|
460
|
+
memoryStats: record.memoryStats && typeof record.memoryStats === "object" ? record.memoryStats : void 0
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
function sanitizeHealthError(error) {
|
|
464
|
+
const message = String(error?.message || error).replace(/kynver_[A-Za-z0-9_]+/g, "kynver_[REDACTED]");
|
|
465
|
+
return {
|
|
466
|
+
message,
|
|
467
|
+
code: typeof error?.code === "string" ? error.code : void 0,
|
|
468
|
+
signal: typeof error?.signal === "string" ? error.signal : void 0,
|
|
469
|
+
stdout: typeof error?.stdout === "string" ? redactSecrets(error.stdout).slice(0, 2e3) : void 0,
|
|
470
|
+
stderr: typeof error?.stderr === "string" ? redactSecrets(error.stderr).slice(0, 2e3) : void 0
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
function redactSecrets(value) {
|
|
474
|
+
return value.replace(/kynver_[A-Za-z0-9_]+/g, "kynver_[REDACTED]");
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// src/schemas/common.ts
|
|
478
|
+
var stringArray = {
|
|
479
|
+
type: "array",
|
|
480
|
+
items: { type: "string" }
|
|
481
|
+
};
|
|
482
|
+
var looseObject = {
|
|
483
|
+
type: "object",
|
|
484
|
+
additionalProperties: {}
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
// src/schemas/contacts.ts
|
|
488
|
+
var getContactsSchema = {
|
|
489
|
+
type: "object",
|
|
490
|
+
properties: {
|
|
491
|
+
slug: { type: "string" }
|
|
492
|
+
},
|
|
493
|
+
additionalProperties: false,
|
|
494
|
+
$schema: "http://json-schema.org/draft-07/schema#"
|
|
495
|
+
};
|
|
496
|
+
var createContactSchema = {
|
|
497
|
+
type: "object",
|
|
498
|
+
properties: {
|
|
499
|
+
name: { type: "string" },
|
|
500
|
+
relationship: { type: "string" },
|
|
501
|
+
context: { type: "string" },
|
|
502
|
+
preferences: looseObject,
|
|
503
|
+
notes: { type: "string" },
|
|
504
|
+
slug: { type: "string" }
|
|
505
|
+
},
|
|
506
|
+
required: ["name"],
|
|
507
|
+
additionalProperties: false,
|
|
508
|
+
$schema: "http://json-schema.org/draft-07/schema#"
|
|
509
|
+
};
|
|
510
|
+
var updateContactSchema = {
|
|
511
|
+
type: "object",
|
|
512
|
+
properties: {
|
|
513
|
+
contactId: { type: "string" },
|
|
514
|
+
name: { type: "string" },
|
|
515
|
+
relationship: { type: "string" },
|
|
516
|
+
context: { type: "string" },
|
|
517
|
+
preferences: looseObject,
|
|
518
|
+
notes: { type: "string" },
|
|
519
|
+
slug: { type: "string" }
|
|
520
|
+
},
|
|
521
|
+
required: ["contactId"],
|
|
522
|
+
additionalProperties: false,
|
|
523
|
+
$schema: "http://json-schema.org/draft-07/schema#"
|
|
524
|
+
};
|
|
525
|
+
|
|
526
|
+
// src/tools/contacts.ts
|
|
527
|
+
function createContactTools(config) {
|
|
528
|
+
const mk = (name, description, parameters) => ({
|
|
529
|
+
name,
|
|
530
|
+
label: name,
|
|
531
|
+
description,
|
|
532
|
+
parameters,
|
|
533
|
+
execute: (_toolCallId, params) => callAgentOsTool({
|
|
534
|
+
serverName: config.agentOsServer,
|
|
535
|
+
toolName: name,
|
|
536
|
+
params,
|
|
537
|
+
timeoutMs: config.timeoutMs,
|
|
538
|
+
mcporterConfigPath: config.mcporterConfigPath,
|
|
539
|
+
kynverApiUrl: config.kynverApiUrl,
|
|
540
|
+
kynverApiKey: config.kynverApiKey,
|
|
541
|
+
agentOsSlug: config.agentOsSlug,
|
|
542
|
+
enableDirectHttp: config.enableDirectHttp
|
|
543
|
+
})
|
|
544
|
+
});
|
|
545
|
+
return [
|
|
546
|
+
mk("agent_os_get_contacts", "Get all AgentOS contacts.", getContactsSchema),
|
|
547
|
+
mk("agent_os_create_contact", "Create or upsert an AgentOS contact.", createContactSchema),
|
|
548
|
+
mk("agent_os_update_contact", "Update an existing AgentOS contact.", updateContactSchema)
|
|
549
|
+
];
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// src/schemas/context.ts
|
|
553
|
+
var getContextSchema = {
|
|
554
|
+
type: "object",
|
|
555
|
+
properties: {
|
|
556
|
+
slug: {
|
|
557
|
+
type: "string",
|
|
558
|
+
description: "AgentOS slug. Defaults to KYNVER_AGENT_OS_SLUG, then 'ghost'."
|
|
559
|
+
}
|
|
560
|
+
},
|
|
561
|
+
additionalProperties: false,
|
|
562
|
+
$schema: "http://json-schema.org/draft-07/schema#"
|
|
563
|
+
};
|
|
564
|
+
|
|
565
|
+
// src/tools/context.ts
|
|
566
|
+
function createContextTools(config) {
|
|
567
|
+
return [
|
|
568
|
+
{
|
|
569
|
+
name: "agent_os_get_context",
|
|
570
|
+
label: "AgentOS Get Context",
|
|
571
|
+
description: "Get the agent's full AgentOS state in one call: identity, goals, projects, contacts, sessions, and memory stats.",
|
|
572
|
+
parameters: getContextSchema,
|
|
573
|
+
execute: (_toolCallId, params) => callAgentOsTool({
|
|
574
|
+
serverName: config.agentOsServer,
|
|
575
|
+
toolName: "agent_os_get_context",
|
|
576
|
+
params,
|
|
577
|
+
timeoutMs: config.timeoutMs,
|
|
578
|
+
mcporterConfigPath: config.mcporterConfigPath,
|
|
579
|
+
kynverApiUrl: config.kynverApiUrl,
|
|
580
|
+
kynverApiKey: config.kynverApiKey,
|
|
581
|
+
agentOsSlug: config.agentOsSlug,
|
|
582
|
+
enableDirectHttp: config.enableDirectHttp
|
|
583
|
+
})
|
|
584
|
+
}
|
|
585
|
+
];
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
// src/schemas/goals.ts
|
|
589
|
+
var listGoalsSchema = {
|
|
590
|
+
type: "object",
|
|
591
|
+
properties: {
|
|
592
|
+
status: { type: "string", enum: ["open", "in_progress", "blocked", "complete", "cancelled"] },
|
|
593
|
+
projectId: { type: "string" },
|
|
594
|
+
slug: { type: "string" }
|
|
595
|
+
},
|
|
596
|
+
additionalProperties: false,
|
|
597
|
+
$schema: "http://json-schema.org/draft-07/schema#"
|
|
598
|
+
};
|
|
599
|
+
var updateGoalSchema = {
|
|
600
|
+
type: "object",
|
|
601
|
+
properties: {
|
|
602
|
+
title: { type: "string", description: "Goal title. Required when creating." },
|
|
603
|
+
description: { type: "string" },
|
|
604
|
+
status: { type: "string", enum: ["open", "in_progress", "blocked", "complete", "cancelled"] },
|
|
605
|
+
priority: { type: "string", enum: ["low", "normal", "high", "critical"] },
|
|
606
|
+
projectId: { type: "string" },
|
|
607
|
+
analystHypothesisId: { type: "string" },
|
|
608
|
+
outcome: { type: "string" },
|
|
609
|
+
goalId: { type: "string" },
|
|
610
|
+
slug: { type: "string" }
|
|
611
|
+
},
|
|
612
|
+
additionalProperties: false,
|
|
613
|
+
$schema: "http://json-schema.org/draft-07/schema#"
|
|
614
|
+
};
|
|
615
|
+
|
|
616
|
+
// src/tools/goals.ts
|
|
617
|
+
function createGoalTools(config) {
|
|
618
|
+
const mk = (name, description, parameters) => ({
|
|
619
|
+
name,
|
|
620
|
+
label: name,
|
|
621
|
+
description,
|
|
622
|
+
parameters,
|
|
623
|
+
execute: (_toolCallId, params) => callAgentOsTool({
|
|
624
|
+
serverName: config.agentOsServer,
|
|
625
|
+
toolName: name,
|
|
626
|
+
params,
|
|
627
|
+
timeoutMs: config.timeoutMs,
|
|
628
|
+
mcporterConfigPath: config.mcporterConfigPath,
|
|
629
|
+
kynverApiUrl: config.kynverApiUrl,
|
|
630
|
+
kynverApiKey: config.kynverApiKey,
|
|
631
|
+
agentOsSlug: config.agentOsSlug,
|
|
632
|
+
enableDirectHttp: config.enableDirectHttp
|
|
633
|
+
})
|
|
634
|
+
});
|
|
635
|
+
return [
|
|
636
|
+
mk("agent_os_list_goals", "List AgentOS goals, optionally filtered by status or project.", listGoalsSchema),
|
|
637
|
+
mk("agent_os_update_goal", "Create a goal or update an existing AgentOS goal.", updateGoalSchema)
|
|
638
|
+
];
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
// src/schemas/health.ts
|
|
642
|
+
var healthCheckSchema = {
|
|
643
|
+
type: "object",
|
|
644
|
+
properties: {
|
|
645
|
+
slug: {
|
|
646
|
+
type: "string",
|
|
647
|
+
description: "AgentOS slug to probe. Defaults to the AgentOS server default."
|
|
648
|
+
}
|
|
649
|
+
},
|
|
650
|
+
additionalProperties: false,
|
|
651
|
+
$schema: "http://json-schema.org/draft-07/schema#"
|
|
652
|
+
};
|
|
653
|
+
|
|
654
|
+
// src/tools/health.ts
|
|
655
|
+
function createHealthTools(config) {
|
|
656
|
+
return [
|
|
657
|
+
{
|
|
658
|
+
name: "agent_os_health_check",
|
|
659
|
+
label: "AgentOS Health Check",
|
|
660
|
+
description: "Check whether Kynver AgentOS is reachable through the configured first-class tool bridge.",
|
|
661
|
+
parameters: healthCheckSchema,
|
|
662
|
+
execute: (_toolCallId, params) => checkAgentOsHealth({
|
|
663
|
+
serverName: config.agentOsServer,
|
|
664
|
+
slug: typeof params.slug === "string" && params.slug.trim() ? params.slug.trim() : void 0,
|
|
665
|
+
timeoutMs: config.timeoutMs,
|
|
666
|
+
mcporterConfigPath: config.mcporterConfigPath,
|
|
667
|
+
kynverApiUrl: config.kynverApiUrl,
|
|
668
|
+
kynverApiKey: config.kynverApiKey,
|
|
669
|
+
agentOsSlug: config.agentOsSlug,
|
|
670
|
+
enableDirectHttp: config.enableDirectHttp
|
|
671
|
+
})
|
|
672
|
+
}
|
|
673
|
+
];
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
// src/schemas/memory.ts
|
|
677
|
+
var searchMemorySchema = {
|
|
678
|
+
type: "object",
|
|
679
|
+
properties: {
|
|
680
|
+
query: { type: "string" },
|
|
681
|
+
k: { type: "number" },
|
|
682
|
+
slug: { type: "string" }
|
|
683
|
+
},
|
|
684
|
+
required: ["query"],
|
|
685
|
+
additionalProperties: false,
|
|
686
|
+
$schema: "http://json-schema.org/draft-07/schema#"
|
|
687
|
+
};
|
|
688
|
+
var writeMemorySchema = {
|
|
689
|
+
type: "object",
|
|
690
|
+
properties: {
|
|
691
|
+
content: { type: "string" },
|
|
692
|
+
key: { type: "string" },
|
|
693
|
+
category: { type: "string", enum: ["long_term", "project", "contact", "tool_config"] },
|
|
694
|
+
sourceId: { type: "string" },
|
|
695
|
+
metadata: looseObject,
|
|
696
|
+
slug: { type: "string" }
|
|
697
|
+
},
|
|
698
|
+
required: ["content"],
|
|
699
|
+
additionalProperties: false,
|
|
700
|
+
$schema: "http://json-schema.org/draft-07/schema#"
|
|
701
|
+
};
|
|
702
|
+
var updateMemorySchema = {
|
|
703
|
+
type: "object",
|
|
704
|
+
properties: {
|
|
705
|
+
key: { type: "string" },
|
|
706
|
+
content: { type: "string" },
|
|
707
|
+
sourceId: { type: "string" },
|
|
708
|
+
metadata: looseObject,
|
|
709
|
+
slug: { type: "string" }
|
|
710
|
+
},
|
|
711
|
+
required: ["key", "content"],
|
|
712
|
+
additionalProperties: false,
|
|
713
|
+
$schema: "http://json-schema.org/draft-07/schema#"
|
|
714
|
+
};
|
|
715
|
+
var consolidateMemorySchema = {
|
|
716
|
+
type: "object",
|
|
717
|
+
properties: {
|
|
718
|
+
slug: { type: "string" }
|
|
719
|
+
},
|
|
720
|
+
additionalProperties: false,
|
|
721
|
+
$schema: "http://json-schema.org/draft-07/schema#"
|
|
722
|
+
};
|
|
723
|
+
|
|
724
|
+
// src/tools/memory.ts
|
|
725
|
+
function createMemoryTools(config) {
|
|
726
|
+
const mk = (name, description, parameters) => ({
|
|
727
|
+
name,
|
|
728
|
+
label: name,
|
|
729
|
+
description,
|
|
730
|
+
parameters,
|
|
731
|
+
execute: (_toolCallId, params) => callAgentOsTool({
|
|
732
|
+
serverName: config.agentOsServer,
|
|
733
|
+
toolName: name,
|
|
734
|
+
params,
|
|
735
|
+
timeoutMs: config.timeoutMs,
|
|
736
|
+
mcporterConfigPath: config.mcporterConfigPath,
|
|
737
|
+
kynverApiUrl: config.kynverApiUrl,
|
|
738
|
+
kynverApiKey: config.kynverApiKey,
|
|
739
|
+
agentOsSlug: config.agentOsSlug,
|
|
740
|
+
enableDirectHttp: config.enableDirectHttp
|
|
741
|
+
})
|
|
742
|
+
});
|
|
743
|
+
return [
|
|
744
|
+
mk("agent_os_search_memory", "Search AgentOS memory using semantic + keyword hybrid recall.", searchMemorySchema),
|
|
745
|
+
mk("agent_os_write_memory", "Write a durable memory entry to AgentOS.", writeMemorySchema),
|
|
746
|
+
mk("agent_os_update_memory", "Update an existing AgentOS memory entry by key.", updateMemorySchema),
|
|
747
|
+
mk("agent_os_consolidate_memory", "Trigger an AgentOS memory consolidation pass.", consolidateMemorySchema)
|
|
748
|
+
];
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
// src/schemas/projects.ts
|
|
752
|
+
var getProjectsSchema = {
|
|
753
|
+
type: "object",
|
|
754
|
+
properties: {
|
|
755
|
+
status: { type: "string", enum: ["active", "on_hold", "shipped", "archived"] },
|
|
756
|
+
slug: { type: "string" }
|
|
757
|
+
},
|
|
758
|
+
additionalProperties: false,
|
|
759
|
+
$schema: "http://json-schema.org/draft-07/schema#"
|
|
760
|
+
};
|
|
761
|
+
var createProjectSchema = {
|
|
762
|
+
type: "object",
|
|
763
|
+
properties: {
|
|
764
|
+
name: { type: "string" },
|
|
765
|
+
description: { type: "string" },
|
|
766
|
+
status: { type: "string", enum: ["active", "on_hold", "shipped", "archived"], default: "active" },
|
|
767
|
+
currentFocus: { type: "string" },
|
|
768
|
+
nextActions: stringArray,
|
|
769
|
+
blockers: stringArray,
|
|
770
|
+
repoUrl: { type: "string" },
|
|
771
|
+
deployUrl: { type: "string" },
|
|
772
|
+
slug: { type: "string" }
|
|
773
|
+
},
|
|
774
|
+
required: ["name"],
|
|
775
|
+
additionalProperties: false,
|
|
776
|
+
$schema: "http://json-schema.org/draft-07/schema#"
|
|
777
|
+
};
|
|
778
|
+
var updateProjectSchema = {
|
|
779
|
+
type: "object",
|
|
780
|
+
properties: {
|
|
781
|
+
projectId: { type: "string" },
|
|
782
|
+
name: { type: "string" },
|
|
783
|
+
description: { type: "string" },
|
|
784
|
+
status: { type: "string", enum: ["active", "on_hold", "shipped", "archived"] },
|
|
785
|
+
currentFocus: { type: "string" },
|
|
786
|
+
nextActions: stringArray,
|
|
787
|
+
blockers: stringArray,
|
|
788
|
+
repoUrl: { type: "string" },
|
|
789
|
+
deployUrl: { type: "string" },
|
|
790
|
+
slug: { type: "string" }
|
|
791
|
+
},
|
|
792
|
+
required: ["projectId"],
|
|
793
|
+
additionalProperties: false,
|
|
794
|
+
$schema: "http://json-schema.org/draft-07/schema#"
|
|
795
|
+
};
|
|
796
|
+
|
|
797
|
+
// src/tools/projects.ts
|
|
798
|
+
function createProjectTools(config) {
|
|
799
|
+
const mk = (name, description, parameters) => ({
|
|
800
|
+
name,
|
|
801
|
+
label: name,
|
|
802
|
+
description,
|
|
803
|
+
parameters,
|
|
804
|
+
execute: (_toolCallId, params) => callAgentOsTool({
|
|
805
|
+
serverName: config.agentOsServer,
|
|
806
|
+
toolName: name,
|
|
807
|
+
params,
|
|
808
|
+
timeoutMs: config.timeoutMs,
|
|
809
|
+
mcporterConfigPath: config.mcporterConfigPath,
|
|
810
|
+
kynverApiUrl: config.kynverApiUrl,
|
|
811
|
+
kynverApiKey: config.kynverApiKey,
|
|
812
|
+
agentOsSlug: config.agentOsSlug,
|
|
813
|
+
enableDirectHttp: config.enableDirectHttp
|
|
814
|
+
})
|
|
815
|
+
});
|
|
816
|
+
return [
|
|
817
|
+
mk("agent_os_get_projects", "Get all tracked AgentOS projects.", getProjectsSchema),
|
|
818
|
+
mk("agent_os_create_project", "Create a new AgentOS project.", createProjectSchema),
|
|
819
|
+
mk("agent_os_update_project", "Update an existing AgentOS project.", updateProjectSchema)
|
|
820
|
+
];
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
// src/schemas/sessions.ts
|
|
824
|
+
var openSessionSchema = {
|
|
825
|
+
type: "object",
|
|
826
|
+
properties: {
|
|
827
|
+
channel: { type: "string", description: "Runtime channel: 'webchat' | 'telegram' | 'discord' | \u2026" },
|
|
828
|
+
model: { type: "string", description: "Model used for the session." },
|
|
829
|
+
slug: { type: "string", description: "AgentOS slug. Defaults to KYNVER_AGENT_OS_SLUG, then 'ghost'." }
|
|
830
|
+
},
|
|
831
|
+
required: ["channel"],
|
|
832
|
+
additionalProperties: false,
|
|
833
|
+
$schema: "http://json-schema.org/draft-07/schema#"
|
|
834
|
+
};
|
|
835
|
+
var closeSessionSchema = {
|
|
836
|
+
type: "object",
|
|
837
|
+
properties: {
|
|
838
|
+
sessionId: { type: "string" },
|
|
839
|
+
summary: { type: "string" },
|
|
840
|
+
topicsWorked: stringArray,
|
|
841
|
+
decisionsLog: {},
|
|
842
|
+
goalIds: stringArray,
|
|
843
|
+
projectIds: stringArray,
|
|
844
|
+
slug: { type: "string" }
|
|
845
|
+
},
|
|
846
|
+
required: ["sessionId", "summary"],
|
|
847
|
+
additionalProperties: false,
|
|
848
|
+
$schema: "http://json-schema.org/draft-07/schema#"
|
|
849
|
+
};
|
|
850
|
+
var logSessionSchema = {
|
|
851
|
+
type: "object",
|
|
852
|
+
properties: {
|
|
853
|
+
summary: { type: "string", description: "2-4 sentence summary of what was worked on." },
|
|
854
|
+
topicsWorked: stringArray,
|
|
855
|
+
keyDecisions: stringArray,
|
|
856
|
+
date: { type: "string", description: "Date to log against (YYYY-MM-DD, defaults to today UTC)." },
|
|
857
|
+
slug: { type: "string" }
|
|
858
|
+
},
|
|
859
|
+
required: ["summary"],
|
|
860
|
+
additionalProperties: false,
|
|
861
|
+
$schema: "http://json-schema.org/draft-07/schema#"
|
|
862
|
+
};
|
|
863
|
+
|
|
864
|
+
// src/tools/sessions.ts
|
|
865
|
+
function createSessionTools(config) {
|
|
866
|
+
const mk = (name, description, parameters) => ({
|
|
867
|
+
name,
|
|
868
|
+
label: name,
|
|
869
|
+
description,
|
|
870
|
+
parameters,
|
|
871
|
+
execute: (_toolCallId, params) => callAgentOsTool({
|
|
872
|
+
serverName: config.agentOsServer,
|
|
873
|
+
toolName: name,
|
|
874
|
+
params,
|
|
875
|
+
timeoutMs: config.timeoutMs,
|
|
876
|
+
mcporterConfigPath: config.mcporterConfigPath,
|
|
877
|
+
kynverApiUrl: config.kynverApiUrl,
|
|
878
|
+
kynverApiKey: config.kynverApiKey,
|
|
879
|
+
agentOsSlug: config.agentOsSlug,
|
|
880
|
+
enableDirectHttp: config.enableDirectHttp
|
|
881
|
+
})
|
|
882
|
+
});
|
|
883
|
+
return [
|
|
884
|
+
mk("agent_os_open_session", "Open an AgentOS session record at the start of a session.", openSessionSchema),
|
|
885
|
+
mk("agent_os_close_session", "Close an AgentOS session record with summary, decisions, and linked goals/projects.", closeSessionSchema),
|
|
886
|
+
mk("agent_os_log_session", "Append a structured session log entry to AgentOS daily notes.", logSessionSchema)
|
|
887
|
+
];
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
// src/tools/index.ts
|
|
891
|
+
function createAllTools(config) {
|
|
892
|
+
return [
|
|
893
|
+
...createHealthTools(config),
|
|
894
|
+
...createContextTools(config),
|
|
895
|
+
...createSessionTools(config),
|
|
896
|
+
...createGoalTools(config),
|
|
897
|
+
...createProjectTools(config),
|
|
898
|
+
...createMemoryTools(config),
|
|
899
|
+
...createContactTools(config)
|
|
900
|
+
];
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
// index.ts
|
|
904
|
+
var plugin = {
|
|
905
|
+
id: "kynver-agent-os-tools",
|
|
906
|
+
name: "Kynver AgentOS Tools",
|
|
907
|
+
description: "First-class OpenClaw tools for Kynver AgentOS, using direct Kynver HTTP with mcporter fallback.",
|
|
908
|
+
configSchema: pluginConfigSchema,
|
|
909
|
+
register(api) {
|
|
910
|
+
const config = resolvePluginConfig(api?.config);
|
|
911
|
+
const tools = createAllTools(config);
|
|
912
|
+
for (const tool of tools) {
|
|
913
|
+
api.registerTool(tool);
|
|
914
|
+
}
|
|
915
|
+
if (config.enableSessionLifecycle && typeof api.on === "function") {
|
|
916
|
+
const sessionIds = /* @__PURE__ */ new Map();
|
|
917
|
+
const keyFor = (event, ctx) => String(event?.sessionKey || ctx?.sessionKey || event?.sessionId || ctx?.sessionId || "");
|
|
918
|
+
const shouldTrack = (key) => key && !key.includes("subagent") && !key.includes("acp") && !key.includes("isolated");
|
|
919
|
+
const channelFor = (key) => {
|
|
920
|
+
if (key.includes("telegram")) return "telegram";
|
|
921
|
+
if (key.includes("discord")) return "discord";
|
|
922
|
+
if (key.includes("webchat")) return "webchat";
|
|
923
|
+
return "openclaw";
|
|
924
|
+
};
|
|
925
|
+
api.on(
|
|
926
|
+
"session_start",
|
|
927
|
+
async (event, ctx) => {
|
|
928
|
+
const key = keyFor(event, ctx);
|
|
929
|
+
if (!shouldTrack(key) || sessionIds.has(key)) return;
|
|
930
|
+
const result = await callAgentOsTool({
|
|
931
|
+
serverName: config.agentOsServer,
|
|
932
|
+
toolName: "agent_os_open_session",
|
|
933
|
+
params: { channel: channelFor(key), model: "openclaw" },
|
|
934
|
+
timeoutMs: Math.min(config.timeoutMs, 1e4),
|
|
935
|
+
mcporterConfigPath: config.mcporterConfigPath,
|
|
936
|
+
kynverApiUrl: config.kynverApiUrl,
|
|
937
|
+
kynverApiKey: config.kynverApiKey,
|
|
938
|
+
agentOsSlug: config.agentOsSlug,
|
|
939
|
+
enableDirectHttp: config.enableDirectHttp
|
|
940
|
+
});
|
|
941
|
+
const id = result?.details?.id;
|
|
942
|
+
if (typeof id === "string") sessionIds.set(key, id);
|
|
943
|
+
},
|
|
944
|
+
{ priority: 10, timeoutMs: 12e3 }
|
|
945
|
+
);
|
|
946
|
+
api.on(
|
|
947
|
+
"session_end",
|
|
948
|
+
async (event, ctx) => {
|
|
949
|
+
const key = keyFor(event, ctx);
|
|
950
|
+
const sessionId = sessionIds.get(key);
|
|
951
|
+
if (!sessionId) return;
|
|
952
|
+
sessionIds.delete(key);
|
|
953
|
+
const reason = typeof event?.reason === "string" ? event.reason : "unknown";
|
|
954
|
+
const messageCount = typeof event?.messageCount === "number" ? event.messageCount : void 0;
|
|
955
|
+
const durationMs = typeof event?.durationMs === "number" ? event.durationMs : void 0;
|
|
956
|
+
await callAgentOsTool({
|
|
957
|
+
serverName: config.agentOsServer,
|
|
958
|
+
toolName: "agent_os_close_session",
|
|
959
|
+
params: {
|
|
960
|
+
sessionId,
|
|
961
|
+
summary: `OpenClaw session ended automatically (reason: ${reason}; messages: ${messageCount ?? "unknown"}; durationMs: ${durationMs ?? "unknown"}).`,
|
|
962
|
+
topicsWorked: ["OpenClaw session lifecycle"]
|
|
963
|
+
},
|
|
964
|
+
timeoutMs: Math.min(config.timeoutMs, 1e4),
|
|
965
|
+
mcporterConfigPath: config.mcporterConfigPath,
|
|
966
|
+
kynverApiUrl: config.kynverApiUrl,
|
|
967
|
+
kynverApiKey: config.kynverApiKey,
|
|
968
|
+
agentOsSlug: config.agentOsSlug,
|
|
969
|
+
enableDirectHttp: config.enableDirectHttp
|
|
970
|
+
});
|
|
971
|
+
},
|
|
972
|
+
{ priority: 10, timeoutMs: 12e3 }
|
|
973
|
+
);
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
};
|
|
977
|
+
var index_default = plugin;
|
|
978
|
+
export {
|
|
979
|
+
index_default as default
|
|
980
|
+
};
|
|
981
|
+
//# sourceMappingURL=index.js.map
|