@feynmanzhang/open-party 0.1.6 → 0.1.7
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 +138 -0
- package/dist/claude-code/{open-party-0.1.6 → open-party-0.1.7}/.claude-plugin/plugin.json +1 -1
- package/dist/claude-code/open-party-0.1.7/BUILD_INFO.json +6 -0
- package/dist/claude-code/open-party-0.1.7/dist/dispatcher.js +187 -0
- package/dist/claude-code/{open-party-0.1.6 → open-party-0.1.7}/dist/hook-handler.js +58 -73
- package/dist/claude-code/{open-party-0.1.6 → open-party-0.1.7}/dist/mcp-server.js +552 -364
- package/dist/claude-code/{open-party-0.1.6 → open-party-0.1.7}/dist/party-server.js +426 -1657
- package/dist/claude-code/{open-party-0.1.6 → open-party-0.1.7}/hooks/hooks.json +39 -50
- package/dist/claude-code/{open-party-0.1.6 → open-party-0.1.7}/package.json +1 -1
- package/dist/claude-code/{open-party-0.1.6 → open-party-0.1.7}/skills/open-party/SKILL.md +39 -21
- package/dist/cli/index.js +1528 -2647
- package/dist/cli/index.js.map +1 -1
- package/dist/party-server.js +426 -1657
- package/dist/party-server.js.map +1 -1
- package/package.json +10 -13
- package/dist/claude-code/open-party-0.1.6/BUILD_INFO.json +0 -6
- package/dist/openclaw/open-party-0.1.5/BUILD_INFO.json +0 -6
- package/dist/openclaw/open-party-0.1.5/SKILL.md +0 -127
- package/dist/openclaw/open-party-0.1.5/dist/index.js +0 -550
- package/dist/openclaw/open-party-0.1.5/dist/party-server.js +0 -5502
- package/dist/openclaw/open-party-0.1.5/openclaw.plugin.json +0 -28
- package/dist/openclaw/open-party-0.1.5/package.json +0 -12
- package/dist/openclaw/open-party-0.1.5/skills/open-party/SKILL.md +0 -90
- package/dist/openclaw/open-party-0.1.6/BUILD_INFO.json +0 -6
- package/dist/openclaw/open-party-0.1.6/SKILL.md +0 -127
- package/dist/openclaw/open-party-0.1.6/dist/index.js +0 -550
- package/dist/openclaw/open-party-0.1.6/dist/party-server.js +0 -5502
- package/dist/openclaw/open-party-0.1.6/openclaw.plugin.json +0 -28
- package/dist/openclaw/open-party-0.1.6/package.json +0 -12
- package/dist/openclaw/open-party-0.1.6/skills/open-party/SKILL.md +0 -90
- /package/dist/claude-code/{open-party-0.1.6 → open-party-0.1.7}/.mcp.json +0 -0
|
@@ -1,550 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
// src/client/shared/client.ts
|
|
5
|
-
var PartyHttpClient = class {
|
|
6
|
-
baseUrl;
|
|
7
|
-
timeout;
|
|
8
|
-
constructor(baseUrl = "http://127.0.0.1:8000", timeout = 5e3) {
|
|
9
|
-
this.baseUrl = baseUrl.replace(/\/$/, "");
|
|
10
|
-
this.timeout = timeout;
|
|
11
|
-
}
|
|
12
|
-
async request(path, options = {}) {
|
|
13
|
-
const controller = new AbortController();
|
|
14
|
-
const timer = setTimeout(() => controller.abort(), this.timeout);
|
|
15
|
-
try {
|
|
16
|
-
const resp = await fetch(`${this.baseUrl}${path}`, {
|
|
17
|
-
...options,
|
|
18
|
-
signal: controller.signal,
|
|
19
|
-
headers: {
|
|
20
|
-
"Content-Type": "application/json",
|
|
21
|
-
...options.headers
|
|
22
|
-
}
|
|
23
|
-
});
|
|
24
|
-
if (!resp.ok) throw new Error(`HTTP ${resp.status}: ${resp.statusText}`);
|
|
25
|
-
return resp.json();
|
|
26
|
-
} finally {
|
|
27
|
-
clearTimeout(timer);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
// -- Agent lifecycle --
|
|
31
|
-
async register(agentId, displayName, metadata) {
|
|
32
|
-
return this.request("/agent/register", {
|
|
33
|
-
method: "POST",
|
|
34
|
-
body: JSON.stringify({ agent_id: agentId, display_name: displayName, metadata: metadata ?? {} })
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
async remove(agentId) {
|
|
38
|
-
const result = await this.request("/agent/remove", {
|
|
39
|
-
method: "POST",
|
|
40
|
-
body: JSON.stringify({ agent_id: agentId })
|
|
41
|
-
});
|
|
42
|
-
return result.status === "removed";
|
|
43
|
-
}
|
|
44
|
-
async heartbeat(agentId) {
|
|
45
|
-
return this.request("/agent/heartbeat", {
|
|
46
|
-
method: "POST",
|
|
47
|
-
body: JSON.stringify({ agent_id: agentId })
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
async listAgents() {
|
|
51
|
-
const result = await this.request("/agent/list");
|
|
52
|
-
return result.agents ?? [];
|
|
53
|
-
}
|
|
54
|
-
// -- Messaging --
|
|
55
|
-
async sendMessage(senderId, recipientId, content, summary) {
|
|
56
|
-
return this.request("/agent/send", {
|
|
57
|
-
method: "POST",
|
|
58
|
-
body: JSON.stringify({ sender_id: senderId, recipient_id: recipientId, content, summary })
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
async checkMessages(agentId) {
|
|
62
|
-
const result = await this.request(`/agent/messages/${agentId}`);
|
|
63
|
-
return result.messages ?? [];
|
|
64
|
-
}
|
|
65
|
-
/** Get message history for an agent. */
|
|
66
|
-
async getMessageHistory(agentId, limit = 20) {
|
|
67
|
-
const result = await this.request(`/agent/history/${agentId}?limit=${limit}`);
|
|
68
|
-
return result.history ?? [];
|
|
69
|
-
}
|
|
70
|
-
// -- Proxy --
|
|
71
|
-
async health() {
|
|
72
|
-
return this.request("/proxy/health");
|
|
73
|
-
}
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
// src/client/shared/server-manager.ts
|
|
77
|
-
import { spawn, execSync } from "child_process";
|
|
78
|
-
import {
|
|
79
|
-
existsSync,
|
|
80
|
-
readFileSync,
|
|
81
|
-
writeFileSync,
|
|
82
|
-
unlinkSync,
|
|
83
|
-
mkdirSync,
|
|
84
|
-
openSync,
|
|
85
|
-
closeSync
|
|
86
|
-
} from "fs";
|
|
87
|
-
import { join, resolve, dirname } from "path";
|
|
88
|
-
import { homedir } from "os";
|
|
89
|
-
import { fileURLToPath } from "url";
|
|
90
|
-
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
91
|
-
var DEFAULT_PORT = parseInt(process.env.PARTY_PORT || "8000", 10);
|
|
92
|
-
var HEALTH_URL = `http://127.0.0.1:${DEFAULT_PORT}/proxy/health`;
|
|
93
|
-
var STARTUP_TIMEOUT = 1e4;
|
|
94
|
-
function pidFileDir() {
|
|
95
|
-
const pluginData = process.env.CLAUDE_PLUGIN_DATA || "";
|
|
96
|
-
if (pluginData) return pluginData;
|
|
97
|
-
return join(homedir(), ".open-party");
|
|
98
|
-
}
|
|
99
|
-
function pidFilePath() {
|
|
100
|
-
return join(pidFileDir(), "server.pid");
|
|
101
|
-
}
|
|
102
|
-
function logFilePath() {
|
|
103
|
-
return join(pidFileDir(), "server.log");
|
|
104
|
-
}
|
|
105
|
-
function lockFilePath() {
|
|
106
|
-
return join(pidFileDir(), "starting.lock");
|
|
107
|
-
}
|
|
108
|
-
function pluginRoot() {
|
|
109
|
-
if (process.env.CLAUDE_PLUGIN_ROOT) return process.env.CLAUDE_PLUGIN_ROOT;
|
|
110
|
-
const fromHere = resolve(__dirname, "..");
|
|
111
|
-
if (existsSync(join(fromHere, "dist", "party-server.js"))) {
|
|
112
|
-
return fromHere;
|
|
113
|
-
}
|
|
114
|
-
if (existsSync(join(fromHere, "party-server.js"))) {
|
|
115
|
-
return fromHere;
|
|
116
|
-
}
|
|
117
|
-
return resolve(__dirname, "..");
|
|
118
|
-
}
|
|
119
|
-
async function isRunning() {
|
|
120
|
-
try {
|
|
121
|
-
const controller = new AbortController();
|
|
122
|
-
const timer = setTimeout(() => controller.abort(), 2e3);
|
|
123
|
-
const resp = await fetch(HEALTH_URL, { signal: controller.signal });
|
|
124
|
-
clearTimeout(timer);
|
|
125
|
-
return resp.status === 200;
|
|
126
|
-
} catch {
|
|
127
|
-
return false;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
function writePid(pid) {
|
|
131
|
-
const path = pidFilePath();
|
|
132
|
-
const dir = dirname(path);
|
|
133
|
-
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
134
|
-
writeFileSync(path, String(pid));
|
|
135
|
-
}
|
|
136
|
-
async function sleep(ms) {
|
|
137
|
-
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
138
|
-
}
|
|
139
|
-
function acquireStartLock() {
|
|
140
|
-
const lockPath = lockFilePath();
|
|
141
|
-
try {
|
|
142
|
-
const fd = openSync(lockPath, "wx");
|
|
143
|
-
writeFileSync(lockPath, String(process.pid));
|
|
144
|
-
return { acquired: true, fd };
|
|
145
|
-
} catch {
|
|
146
|
-
return { acquired: false, fd: -1 };
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
function releaseStartLock(fd) {
|
|
150
|
-
if (fd >= 0) {
|
|
151
|
-
try {
|
|
152
|
-
closeSync(fd);
|
|
153
|
-
} catch {
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
try {
|
|
157
|
-
unlinkSync(lockFilePath());
|
|
158
|
-
} catch {
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
async function spawnAndWait() {
|
|
162
|
-
const serverScript = join(pluginRoot(), "dist", "party-server.js");
|
|
163
|
-
if (!existsSync(serverScript)) {
|
|
164
|
-
throw new Error(`[Open Party] Server script not found: ${serverScript}`);
|
|
165
|
-
}
|
|
166
|
-
const logPath = logFilePath();
|
|
167
|
-
mkdirSync(dirname(logPath), { recursive: true });
|
|
168
|
-
const logFd = openSync(logPath, "a");
|
|
169
|
-
const proc = spawn(process.execPath, [serverScript], {
|
|
170
|
-
stdio: ["ignore", logFd, logFd],
|
|
171
|
-
detached: true,
|
|
172
|
-
windowsHide: true
|
|
173
|
-
});
|
|
174
|
-
proc.unref();
|
|
175
|
-
writePid(proc.pid);
|
|
176
|
-
proc.on("error", (err) => {
|
|
177
|
-
console.error(`[Open Party] Failed to start server: ${err.message}`);
|
|
178
|
-
});
|
|
179
|
-
const deadline = Date.now() + STARTUP_TIMEOUT;
|
|
180
|
-
while (Date.now() < deadline) {
|
|
181
|
-
if (await isRunning()) return;
|
|
182
|
-
await sleep(500);
|
|
183
|
-
}
|
|
184
|
-
let alive = false;
|
|
185
|
-
try {
|
|
186
|
-
process.kill(proc.pid, 0);
|
|
187
|
-
alive = true;
|
|
188
|
-
} catch {
|
|
189
|
-
}
|
|
190
|
-
if (!alive) {
|
|
191
|
-
throw new Error(
|
|
192
|
-
`[Open Party] Server crashed during startup (PID ${proc.pid}). Check log: ${logPath}`
|
|
193
|
-
);
|
|
194
|
-
}
|
|
195
|
-
throw new Error(
|
|
196
|
-
`[Open Party] Server did not become healthy within ${STARTUP_TIMEOUT}ms (PID ${proc.pid}). Check log: ${logPath}`
|
|
197
|
-
);
|
|
198
|
-
}
|
|
199
|
-
async function waitForExisting() {
|
|
200
|
-
const deadline = Date.now() + STARTUP_TIMEOUT;
|
|
201
|
-
while (Date.now() < deadline) {
|
|
202
|
-
if (await isRunning()) return;
|
|
203
|
-
await sleep(500);
|
|
204
|
-
}
|
|
205
|
-
throw new Error(
|
|
206
|
-
`[Open Party] Another process is starting the server but it did not become healthy within ${STARTUP_TIMEOUT}ms`
|
|
207
|
-
);
|
|
208
|
-
}
|
|
209
|
-
async function ensureServerRunning() {
|
|
210
|
-
if (await isRunning()) return;
|
|
211
|
-
const { acquired, fd } = acquireStartLock();
|
|
212
|
-
if (acquired) {
|
|
213
|
-
try {
|
|
214
|
-
await spawnAndWait();
|
|
215
|
-
} finally {
|
|
216
|
-
releaseStartLock(fd);
|
|
217
|
-
}
|
|
218
|
-
} else {
|
|
219
|
-
await waitForExisting();
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// src/client/shared/session-store.ts
|
|
224
|
-
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, readdirSync, unlinkSync as unlinkSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
225
|
-
import { join as join2 } from "path";
|
|
226
|
-
import { homedir as homedir2 } from "os";
|
|
227
|
-
var SESSION_DIR = join2(homedir2(), ".open-party");
|
|
228
|
-
var SESSIONS_DIR = join2(SESSION_DIR, "sessions");
|
|
229
|
-
var AGENTS_DIR = join2(SESSION_DIR, "agents");
|
|
230
|
-
function ensureDir(dir) {
|
|
231
|
-
if (!existsSync2(dir)) mkdirSync2(dir, { recursive: true });
|
|
232
|
-
}
|
|
233
|
-
function writeSession(sessionId, agentId, displayName, serverUrl) {
|
|
234
|
-
ensureDir(SESSIONS_DIR);
|
|
235
|
-
ensureDir(AGENTS_DIR);
|
|
236
|
-
const sessionData = { agent_id: agentId, display_name: displayName, server_url: serverUrl, session_id: sessionId };
|
|
237
|
-
writeFileSync2(join2(SESSIONS_DIR, `${sessionId}.json`), JSON.stringify(sessionData));
|
|
238
|
-
writeFileSync2(join2(AGENTS_DIR, `${agentId}.json`), JSON.stringify({ session_id: sessionId }));
|
|
239
|
-
}
|
|
240
|
-
function readSession(sessionId) {
|
|
241
|
-
const path = join2(SESSIONS_DIR, `${sessionId}.json`);
|
|
242
|
-
if (!existsSync2(path)) return void 0;
|
|
243
|
-
return JSON.parse(readFileSync2(path, "utf-8"));
|
|
244
|
-
}
|
|
245
|
-
function clearSession(sessionId) {
|
|
246
|
-
const sessionPath = join2(SESSIONS_DIR, `${sessionId}.json`);
|
|
247
|
-
if (!existsSync2(sessionPath)) return;
|
|
248
|
-
const sessionData = JSON.parse(readFileSync2(sessionPath, "utf-8"));
|
|
249
|
-
const agentId = sessionData.agent_id;
|
|
250
|
-
try {
|
|
251
|
-
unlinkSync2(sessionPath);
|
|
252
|
-
} catch {
|
|
253
|
-
}
|
|
254
|
-
if (agentId) {
|
|
255
|
-
try {
|
|
256
|
-
unlinkSync2(join2(AGENTS_DIR, `${agentId}.json`));
|
|
257
|
-
} catch {
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
function findAnySession() {
|
|
262
|
-
if (!existsSync2(SESSIONS_DIR)) return void 0;
|
|
263
|
-
const files = readdirSync(SESSIONS_DIR).filter((f) => f.endsWith(".json"));
|
|
264
|
-
if (files.length === 0) return void 0;
|
|
265
|
-
return readSession(files[0].slice(0, -5));
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
// src/client/shared/id.ts
|
|
269
|
-
import { randomUUID } from "crypto";
|
|
270
|
-
function generateAgentId() {
|
|
271
|
-
return `agent-${randomUUID().slice(0, 12)}`;
|
|
272
|
-
}
|
|
273
|
-
function generateDisplayName() {
|
|
274
|
-
const adjectives = [
|
|
275
|
-
"swift",
|
|
276
|
-
"calm",
|
|
277
|
-
"bold",
|
|
278
|
-
"keen",
|
|
279
|
-
"warm",
|
|
280
|
-
"bright",
|
|
281
|
-
"clever",
|
|
282
|
-
"noble",
|
|
283
|
-
"agile",
|
|
284
|
-
"brave"
|
|
285
|
-
];
|
|
286
|
-
const nouns = [
|
|
287
|
-
"falcon",
|
|
288
|
-
"river",
|
|
289
|
-
"storm",
|
|
290
|
-
"raven",
|
|
291
|
-
"tiger",
|
|
292
|
-
"canyon",
|
|
293
|
-
"spark",
|
|
294
|
-
"cedar",
|
|
295
|
-
"fox",
|
|
296
|
-
"wolf"
|
|
297
|
-
];
|
|
298
|
-
const adj = adjectives[Math.floor(Math.random() * adjectives.length)];
|
|
299
|
-
const noun = nouns[Math.floor(Math.random() * nouns.length)];
|
|
300
|
-
const num = Math.floor(Math.random() * 100);
|
|
301
|
-
return `${adj}-${noun}-${num}`;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
// src/client/openclaw/src/index.ts
|
|
305
|
-
var PARTY_SERVER_URL = process.env.PARTY_SERVER_URL || "http://127.0.0.1:8000";
|
|
306
|
-
var cachedBaseContext;
|
|
307
|
-
var currentIdentity = null;
|
|
308
|
-
var hbAbortController = null;
|
|
309
|
-
var hbLoopPromise = null;
|
|
310
|
-
function findSessionForCommand(_ctx) {
|
|
311
|
-
return findAnySession();
|
|
312
|
-
}
|
|
313
|
-
function openPartyPlugin(api) {
|
|
314
|
-
const client = new PartyHttpClient(PARTY_SERVER_URL);
|
|
315
|
-
api.registerService({
|
|
316
|
-
id: "open-party-heartbeat",
|
|
317
|
-
start: async (ctx) => {
|
|
318
|
-
if (hbAbortController) {
|
|
319
|
-
hbAbortController.abort();
|
|
320
|
-
if (hbLoopPromise) {
|
|
321
|
-
await hbLoopPromise;
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
const hbInterval = ctx.config.heartbeatInterval || parseInt(process.env.HEARTBEAT_INTERVAL_MS || "15000", 10);
|
|
325
|
-
ctx.logger.info(`[Open Party] Heartbeat service starting (interval: ${hbInterval}ms)`);
|
|
326
|
-
hbAbortController = new AbortController();
|
|
327
|
-
const signal = hbAbortController.signal;
|
|
328
|
-
hbLoopPromise = (async () => {
|
|
329
|
-
while (!signal.aborted) {
|
|
330
|
-
try {
|
|
331
|
-
await new Promise((resolve2, reject) => {
|
|
332
|
-
const timer = setTimeout(resolve2, hbInterval);
|
|
333
|
-
signal.addEventListener("abort", () => {
|
|
334
|
-
clearTimeout(timer);
|
|
335
|
-
reject(new Error("aborted"));
|
|
336
|
-
}, { once: true });
|
|
337
|
-
timer.unref();
|
|
338
|
-
});
|
|
339
|
-
if (signal.aborted) break;
|
|
340
|
-
if (!currentIdentity) continue;
|
|
341
|
-
await client.heartbeat(currentIdentity.agent_id);
|
|
342
|
-
} catch (err) {
|
|
343
|
-
if (signal.aborted) break;
|
|
344
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
345
|
-
if (/not registered/i.test(msg) && currentIdentity) {
|
|
346
|
-
ctx.logger.warn(`[Open Party] Agent removed by server, re-registering: ${currentIdentity.agent_id}`);
|
|
347
|
-
try {
|
|
348
|
-
await client.register(currentIdentity.agent_id, currentIdentity.display_name, { type: "openclaw" });
|
|
349
|
-
} catch (regErr) {
|
|
350
|
-
ctx.logger.error(`[Open Party] Re-register failed: ${regErr instanceof Error ? regErr.message : regErr}`);
|
|
351
|
-
}
|
|
352
|
-
} else {
|
|
353
|
-
ctx.logger.error(`[Open Party] Heartbeat error: ${msg}`);
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
})();
|
|
358
|
-
},
|
|
359
|
-
stop: async (ctx) => {
|
|
360
|
-
if (hbAbortController) {
|
|
361
|
-
hbAbortController.abort();
|
|
362
|
-
hbAbortController = null;
|
|
363
|
-
}
|
|
364
|
-
if (hbLoopPromise) {
|
|
365
|
-
try {
|
|
366
|
-
await hbLoopPromise;
|
|
367
|
-
} catch {
|
|
368
|
-
}
|
|
369
|
-
hbLoopPromise = null;
|
|
370
|
-
}
|
|
371
|
-
ctx.logger.info("[Open Party] Heartbeat service stopped");
|
|
372
|
-
}
|
|
373
|
-
});
|
|
374
|
-
api.on("session_start", async (event, _ctx) => {
|
|
375
|
-
const sessionId = event.sessionId;
|
|
376
|
-
await ensureServerRunning();
|
|
377
|
-
const existing = readSession(sessionId);
|
|
378
|
-
let agentId;
|
|
379
|
-
let displayName;
|
|
380
|
-
if (existing) {
|
|
381
|
-
agentId = existing.agent_id;
|
|
382
|
-
displayName = existing.display_name;
|
|
383
|
-
api.logger.info(`[Open Party] Resumed as ${agentId} (${displayName})`);
|
|
384
|
-
} else {
|
|
385
|
-
agentId = generateAgentId();
|
|
386
|
-
displayName = generateDisplayName();
|
|
387
|
-
}
|
|
388
|
-
try {
|
|
389
|
-
const [, agents] = await Promise.all([
|
|
390
|
-
client.register(agentId, displayName, { type: "openclaw" }),
|
|
391
|
-
client.listAgents()
|
|
392
|
-
]);
|
|
393
|
-
api.logger.info(`[Open Party] Registered as ${agentId} (${displayName})`);
|
|
394
|
-
writeSession(sessionId, agentId, displayName, PARTY_SERVER_URL);
|
|
395
|
-
const others = agents.filter((a) => a.agent_id !== agentId);
|
|
396
|
-
const lines = [];
|
|
397
|
-
lines.push("## Open Party Agent Identity", "");
|
|
398
|
-
lines.push(`Your Agent ID: **${agentId}**`);
|
|
399
|
-
lines.push(`Your Display Name: **${displayName}**`, "");
|
|
400
|
-
lines.push(
|
|
401
|
-
"You are connected to the Open Party network as an autonomous agent. Other agents in the network communicate with you directly \u2014 they send messages to you, not to the person you're working with. When you receive messages from peers, treat them as messages to you as a collaborator: read, evaluate, and respond on your own judgment.",
|
|
402
|
-
""
|
|
403
|
-
);
|
|
404
|
-
lines.push("Always use your Agent ID when calling Open Party tools.", "");
|
|
405
|
-
if (others.length > 0) {
|
|
406
|
-
lines.push(`**${others.length}** other agent(s) online:`);
|
|
407
|
-
for (const a of others) {
|
|
408
|
-
const name = a.display_name || a.agent_id;
|
|
409
|
-
lines.push(`- **${name}** \`${a.agent_id}\``);
|
|
410
|
-
}
|
|
411
|
-
lines.push("");
|
|
412
|
-
lines.push("Available commands: `/send <agent_id> <message>` \xB7 `/list_agents` \xB7 `/check_messages`");
|
|
413
|
-
} else {
|
|
414
|
-
lines.push("No other agents online right now. Use `/list_agents` to check later.");
|
|
415
|
-
}
|
|
416
|
-
cachedBaseContext = lines.join("\n");
|
|
417
|
-
currentIdentity = { agent_id: agentId, display_name: displayName };
|
|
418
|
-
} catch (error) {
|
|
419
|
-
api.logger.error(`[Open Party] Session start failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
420
|
-
}
|
|
421
|
-
});
|
|
422
|
-
api.on("session_end", async (event, _ctx) => {
|
|
423
|
-
const sessionId = event.sessionId;
|
|
424
|
-
const session = readSession(sessionId);
|
|
425
|
-
if (!session) return;
|
|
426
|
-
currentIdentity = null;
|
|
427
|
-
try {
|
|
428
|
-
await client.remove(session.agent_id);
|
|
429
|
-
api.logger.info(`[Open Party] Unregistered ${session.agent_id}`);
|
|
430
|
-
} catch (error) {
|
|
431
|
-
api.logger.error(`[Open Party] Unregister failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
432
|
-
}
|
|
433
|
-
clearSession(sessionId);
|
|
434
|
-
});
|
|
435
|
-
api.on("before_prompt_build", async (_event, ctx) => {
|
|
436
|
-
const sessionId = ctx.context?.sessionId || ctx.sessionKey || "default";
|
|
437
|
-
const session = readSession(sessionId);
|
|
438
|
-
if (!session || !cachedBaseContext) return;
|
|
439
|
-
let messages = [];
|
|
440
|
-
try {
|
|
441
|
-
messages = await client.checkMessages(session.agent_id);
|
|
442
|
-
} catch (error) {
|
|
443
|
-
api.logger.error(`[Open Party] Failed to check messages: ${error instanceof Error ? error.message : String(error)}`);
|
|
444
|
-
}
|
|
445
|
-
const lines = [cachedBaseContext];
|
|
446
|
-
if (messages.length > 0) {
|
|
447
|
-
lines.push("", `## \u{1F4EC} Unread Messages (${messages.length})`);
|
|
448
|
-
for (const msg of messages) {
|
|
449
|
-
const sender = msg.sender_id ?? "unknown";
|
|
450
|
-
const content = msg.content ?? "";
|
|
451
|
-
lines.push(`- **From \`${sender}\`:** ${content}`);
|
|
452
|
-
}
|
|
453
|
-
lines.push("Respond with `/send` if needed.");
|
|
454
|
-
}
|
|
455
|
-
return { appendSystemContext: lines.join("\n") };
|
|
456
|
-
});
|
|
457
|
-
api.on("message_received", async (_event, _ctx) => {
|
|
458
|
-
});
|
|
459
|
-
api.registerCommand({
|
|
460
|
-
name: "list_agents",
|
|
461
|
-
description: "List all agents currently online in the Open Party network.",
|
|
462
|
-
handler: async (_ctx) => {
|
|
463
|
-
let agents;
|
|
464
|
-
try {
|
|
465
|
-
agents = await client.listAgents();
|
|
466
|
-
} catch (error) {
|
|
467
|
-
return { text: `\u274C Error listing agents: ${error instanceof Error ? error.message : String(error)}` };
|
|
468
|
-
}
|
|
469
|
-
if (!agents.length) {
|
|
470
|
-
return { text: "No agents currently online. Try again later with `/list_agents`." };
|
|
471
|
-
}
|
|
472
|
-
const lines = [`## \u{1F310} Online Agents (${agents.length})`, "", "| # | Name | Agent ID |", "|---|------|----------|"];
|
|
473
|
-
for (let i = 0; i < agents.length; i++) {
|
|
474
|
-
const a = agents[i];
|
|
475
|
-
const name = a.display_name || a.agent_id;
|
|
476
|
-
const id = a.agent_id;
|
|
477
|
-
lines.push(`| ${i + 1} | **${name}** | \`${id}\` |`);
|
|
478
|
-
}
|
|
479
|
-
lines.push("", "> \u{1F4A1} Use `/send <agent_id> <message>` to reach any agent above.");
|
|
480
|
-
return { text: lines.join("\n") };
|
|
481
|
-
}
|
|
482
|
-
});
|
|
483
|
-
api.registerCommand({
|
|
484
|
-
name: "send",
|
|
485
|
-
description: "Send a message to another agent in the Open Party network.",
|
|
486
|
-
acceptsArgs: true,
|
|
487
|
-
handler: async (ctx) => {
|
|
488
|
-
const session = findSessionForCommand(ctx);
|
|
489
|
-
if (!session) {
|
|
490
|
-
return { text: "\u274C No active session. Your session may have expired." };
|
|
491
|
-
}
|
|
492
|
-
const args = (ctx.args || "").trim();
|
|
493
|
-
const firstSpace = args.indexOf(" ");
|
|
494
|
-
if (firstSpace === -1) {
|
|
495
|
-
return { text: "Usage: `/send <agent_id> <message>`" };
|
|
496
|
-
}
|
|
497
|
-
const recipientId = args.slice(0, firstSpace);
|
|
498
|
-
const content = args.slice(firstSpace + 1);
|
|
499
|
-
try {
|
|
500
|
-
const result = await client.sendMessage(session.agent_id, recipientId, content);
|
|
501
|
-
const status = result.status;
|
|
502
|
-
if (status === "delivered_locally" || status === "forwarded") {
|
|
503
|
-
return { text: `\u{1F4E4} **Sent** to **${recipientId}**` };
|
|
504
|
-
} else if (status === "agent_not_found") {
|
|
505
|
-
return { text: `\u26A0\uFE0F Agent \`${recipientId}\` not found. Use \`/list_agents\` to see who's online.` };
|
|
506
|
-
} else {
|
|
507
|
-
return { text: `\u26A0\uFE0F Send result: ${status}` };
|
|
508
|
-
}
|
|
509
|
-
} catch (error) {
|
|
510
|
-
return { text: `\u274C Error sending message: ${error instanceof Error ? error.message : String(error)}` };
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
});
|
|
514
|
-
api.registerCommand({
|
|
515
|
-
name: "check_messages",
|
|
516
|
-
description: "Check for messages from other agents in the Open Party network.",
|
|
517
|
-
handler: async (ctx) => {
|
|
518
|
-
const session = findSessionForCommand(ctx);
|
|
519
|
-
if (!session) {
|
|
520
|
-
return { text: "\u274C No active session. Your session may have expired." };
|
|
521
|
-
}
|
|
522
|
-
try {
|
|
523
|
-
const messages = await client.checkMessages(session.agent_id);
|
|
524
|
-
if (!messages.length) {
|
|
525
|
-
return { text: "\u{1F4EC} No new messages." };
|
|
526
|
-
}
|
|
527
|
-
const lines = [`## \u{1F4EC} Messages (${messages.length})`, ""];
|
|
528
|
-
for (const msg of messages) {
|
|
529
|
-
const sender = msg.sender_id ?? "unknown";
|
|
530
|
-
const msgSummary = msg.summary ?? void 0;
|
|
531
|
-
const msgContent = msg.content ?? "";
|
|
532
|
-
lines.push("---", "", `**From:** \`${sender}\``, "");
|
|
533
|
-
if (msgSummary) {
|
|
534
|
-
lines.push(`**Summary:** ${msgSummary}`, "");
|
|
535
|
-
}
|
|
536
|
-
lines.push(`> ${msgContent}`, "");
|
|
537
|
-
}
|
|
538
|
-
lines.push("---", "", "\u{1F4A1} Reply with `/send` if needed.");
|
|
539
|
-
return { text: lines.join("\n") };
|
|
540
|
-
} catch (error) {
|
|
541
|
-
return { text: `\u274C Error checking messages: ${error instanceof Error ? error.message : String(error)}` };
|
|
542
|
-
}
|
|
543
|
-
}
|
|
544
|
-
});
|
|
545
|
-
api.logger.info(`[Open Party] OpenClaw plugin loaded \u2014 server: ${PARTY_SERVER_URL}`);
|
|
546
|
-
}
|
|
547
|
-
export {
|
|
548
|
-
openPartyPlugin as default
|
|
549
|
-
};
|
|
550
|
-
//# sourceMappingURL=index.js.map
|