@occum-net/occumclaw 0.5.0 → 0.6.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/index.ts +201 -1
- package/package.json +1 -1
package/index.ts
CHANGED
|
@@ -327,12 +327,85 @@ function listAccountIds(cfg: any): string[] {
|
|
|
327
327
|
return [];
|
|
328
328
|
}
|
|
329
329
|
|
|
330
|
+
// ─── Directory Helpers ───────────────────────────────────────────────────────
|
|
331
|
+
|
|
332
|
+
interface DirectoryEntry {
|
|
333
|
+
kind: "user" | "group" | "channel";
|
|
334
|
+
id: string;
|
|
335
|
+
name?: string;
|
|
336
|
+
handle?: string;
|
|
337
|
+
avatarUrl?: string;
|
|
338
|
+
rank?: number;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/** Case-insensitive substring filter on id, name, and handle. */
|
|
342
|
+
function filterEntries(entries: DirectoryEntry[], query?: string | null, limit?: number | null): DirectoryEntry[] {
|
|
343
|
+
if (query) {
|
|
344
|
+
const q = query.trim().toLowerCase();
|
|
345
|
+
entries = entries.filter(
|
|
346
|
+
(e) =>
|
|
347
|
+
e.id.toLowerCase().includes(q) ||
|
|
348
|
+
e.name?.toLowerCase().includes(q) ||
|
|
349
|
+
e.handle?.toLowerCase().includes(q),
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
if (limit && limit > 0) entries = entries.slice(0, limit);
|
|
353
|
+
return entries;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/** Convert an occum.net channel member to a directory entry. */
|
|
357
|
+
function memberToEntry(m: any): DirectoryEntry {
|
|
358
|
+
return {
|
|
359
|
+
kind: "user",
|
|
360
|
+
id: m.memberType === "agent" ? m.agentId : m.userId,
|
|
361
|
+
name: m.displayName ?? m.invitedName ?? undefined,
|
|
362
|
+
handle: m.memberType === "agent" ? m.agentId : undefined,
|
|
363
|
+
avatarUrl: m.avatarUrl ?? undefined,
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/** Convert an occum.net channel to a directory group entry. */
|
|
368
|
+
function channelToEntry(ch: any): DirectoryEntry {
|
|
369
|
+
return {
|
|
370
|
+
kind: "group",
|
|
371
|
+
id: ch.id,
|
|
372
|
+
name: ch.name ?? undefined,
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Build a ToolConfig from either the gateway closure or from the cfg param.
|
|
378
|
+
* The gateway sets cachedConfig/controlChannelId at startup; the CLI resolver
|
|
379
|
+
* only has cfg, so we fall back to resolveAccount + /agents/me.
|
|
380
|
+
*/
|
|
381
|
+
async function resolveDirectoryContext(
|
|
382
|
+
cachedConfig: ToolConfig | null,
|
|
383
|
+
controlChannelId: string | null,
|
|
384
|
+
cfg?: any,
|
|
385
|
+
): Promise<{ config: ToolConfig; controlChannelId: string } | null> {
|
|
386
|
+
if (cachedConfig && controlChannelId) {
|
|
387
|
+
return { config: cachedConfig, controlChannelId };
|
|
388
|
+
}
|
|
389
|
+
// Fallback: build config from cfg param (used by CLI commands)
|
|
390
|
+
const account = resolveAccount(cfg ?? {});
|
|
391
|
+
if (!account.agentToken) return null;
|
|
392
|
+
const config: ToolConfig = { agentToken: account.agentToken, apiUrl: account.apiUrl };
|
|
393
|
+
try {
|
|
394
|
+
const me = await apiRequest(config, "/agents/me");
|
|
395
|
+
if (!me.controlChannelId) return null;
|
|
396
|
+
return { config, controlChannelId: me.controlChannelId };
|
|
397
|
+
} catch {
|
|
398
|
+
return null;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
330
402
|
// ─── Channel Plugin ─────────────────────────────────────────────────────────
|
|
331
403
|
|
|
332
404
|
function createOccumChannelPlugin(logger: PluginLogger) {
|
|
333
|
-
// Shared state: set by startAccount, read by resolveTarget/sendText.
|
|
405
|
+
// Shared state: set by startAccount, read by resolveTarget/sendText/directory.
|
|
334
406
|
// All outbound delivery routes to the agent's control channel.
|
|
335
407
|
let controlChannelId: string | null = null;
|
|
408
|
+
let cachedConfig: ToolConfig | null = null;
|
|
336
409
|
|
|
337
410
|
return {
|
|
338
411
|
id: "occum" as const,
|
|
@@ -353,6 +426,132 @@ function createOccumChannelPlugin(logger: PluginLogger) {
|
|
|
353
426
|
resolveToolPolicy: resolveOccumToolPolicy,
|
|
354
427
|
},
|
|
355
428
|
|
|
429
|
+
directory: {
|
|
430
|
+
async self(params: { cfg?: any }) {
|
|
431
|
+
const ctx = await resolveDirectoryContext(cachedConfig, controlChannelId, params.cfg);
|
|
432
|
+
if (!ctx) return null;
|
|
433
|
+
try {
|
|
434
|
+
const me = await apiRequest(ctx.config, "/agents/me");
|
|
435
|
+
return { kind: "user" as const, id: me.id, name: me.name ?? undefined };
|
|
436
|
+
} catch {
|
|
437
|
+
return null;
|
|
438
|
+
}
|
|
439
|
+
},
|
|
440
|
+
|
|
441
|
+
async listPeers(params: { cfg?: any; query?: string | null; limit?: number | null; accountId?: string | null }) {
|
|
442
|
+
const ctx = await resolveDirectoryContext(cachedConfig, controlChannelId, params.cfg);
|
|
443
|
+
if (!ctx) return [];
|
|
444
|
+
try {
|
|
445
|
+
const members: any[] = await apiRequest(ctx.config, `/channels/${ctx.controlChannelId}/members`);
|
|
446
|
+
const entries = members.map(memberToEntry).filter((e) => !!e.id);
|
|
447
|
+
return filterEntries(entries, params.query, params.limit);
|
|
448
|
+
} catch {
|
|
449
|
+
return [];
|
|
450
|
+
}
|
|
451
|
+
},
|
|
452
|
+
|
|
453
|
+
async listPeersLive(params: { cfg?: any; query?: string | null; limit?: number | null; accountId?: string | null }) {
|
|
454
|
+
const ctx = await resolveDirectoryContext(cachedConfig, controlChannelId, params.cfg);
|
|
455
|
+
if (!ctx) return [];
|
|
456
|
+
try {
|
|
457
|
+
const members: any[] = await apiRequest(ctx.config, `/channels/${ctx.controlChannelId}/members`);
|
|
458
|
+
const entries = members.map(memberToEntry).filter((e) => !!e.id);
|
|
459
|
+
return filterEntries(entries, params.query, params.limit);
|
|
460
|
+
} catch {
|
|
461
|
+
return [];
|
|
462
|
+
}
|
|
463
|
+
},
|
|
464
|
+
|
|
465
|
+
async listGroups(params: { cfg?: any; query?: string | null; limit?: number | null; accountId?: string | null }) {
|
|
466
|
+
const ctx = await resolveDirectoryContext(cachedConfig, controlChannelId, params.cfg);
|
|
467
|
+
if (!ctx) return [];
|
|
468
|
+
try {
|
|
469
|
+
const channels: any[] = await apiRequest(ctx.config, "/channels");
|
|
470
|
+
const entries = channels.map(channelToEntry);
|
|
471
|
+
return filterEntries(entries, params.query, params.limit);
|
|
472
|
+
} catch {
|
|
473
|
+
return [];
|
|
474
|
+
}
|
|
475
|
+
},
|
|
476
|
+
|
|
477
|
+
async listGroupsLive(params: { cfg?: any; query?: string | null; limit?: number | null; accountId?: string | null }) {
|
|
478
|
+
const ctx = await resolveDirectoryContext(cachedConfig, controlChannelId, params.cfg);
|
|
479
|
+
if (!ctx) return [];
|
|
480
|
+
try {
|
|
481
|
+
const channels: any[] = await apiRequest(ctx.config, "/channels");
|
|
482
|
+
const entries = channels.map(channelToEntry);
|
|
483
|
+
return filterEntries(entries, params.query, params.limit);
|
|
484
|
+
} catch {
|
|
485
|
+
return [];
|
|
486
|
+
}
|
|
487
|
+
},
|
|
488
|
+
|
|
489
|
+
async listGroupMembers(params: { cfg?: any; groupId: string; limit?: number | null; accountId?: string | null }) {
|
|
490
|
+
const ctx = await resolveDirectoryContext(cachedConfig, controlChannelId, params.cfg);
|
|
491
|
+
if (!ctx) return [];
|
|
492
|
+
try {
|
|
493
|
+
const members: any[] = await apiRequest(ctx.config, `/channels/${params.groupId}/members`);
|
|
494
|
+
const entries = members.map(memberToEntry).filter((e) => !!e.id);
|
|
495
|
+
return params.limit && params.limit > 0 ? entries.slice(0, params.limit) : entries;
|
|
496
|
+
} catch {
|
|
497
|
+
return [];
|
|
498
|
+
}
|
|
499
|
+
},
|
|
500
|
+
},
|
|
501
|
+
|
|
502
|
+
resolver: {
|
|
503
|
+
async resolveTargets(params: {
|
|
504
|
+
cfg?: any;
|
|
505
|
+
accountId?: string | null;
|
|
506
|
+
inputs: string[];
|
|
507
|
+
kind: "user" | "group";
|
|
508
|
+
}) {
|
|
509
|
+
const ctx = await resolveDirectoryContext(cachedConfig, controlChannelId, params.cfg);
|
|
510
|
+
if (!ctx) {
|
|
511
|
+
return params.inputs.map((input) => ({ input, resolved: false, note: "Not configured" }));
|
|
512
|
+
}
|
|
513
|
+
if (params.kind === "group") {
|
|
514
|
+
try {
|
|
515
|
+
const channels: any[] = await apiRequest(ctx.config, "/channels");
|
|
516
|
+
return params.inputs.map((input) => {
|
|
517
|
+
const q = input.trim().toLowerCase();
|
|
518
|
+
const match = channels.find(
|
|
519
|
+
(ch) => ch.id === input || ch.name?.toLowerCase().includes(q),
|
|
520
|
+
);
|
|
521
|
+
return match
|
|
522
|
+
? { input, resolved: true, id: match.id, name: match.name ?? undefined }
|
|
523
|
+
: { input, resolved: false };
|
|
524
|
+
});
|
|
525
|
+
} catch {
|
|
526
|
+
return params.inputs.map((input) => ({ input, resolved: false }));
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
// kind === "user"
|
|
530
|
+
try {
|
|
531
|
+
const members: any[] = await apiRequest(ctx.config, `/channels/${ctx.controlChannelId}/members`);
|
|
532
|
+
return params.inputs.map((input) => {
|
|
533
|
+
const q = input.trim().toLowerCase();
|
|
534
|
+
const match = members.find(
|
|
535
|
+
(m) =>
|
|
536
|
+
m.userId === input ||
|
|
537
|
+
m.agentId === input ||
|
|
538
|
+
m.displayName?.toLowerCase().includes(q) ||
|
|
539
|
+
m.invitedName?.toLowerCase().includes(q),
|
|
540
|
+
);
|
|
541
|
+
if (!match) return { input, resolved: false };
|
|
542
|
+
return {
|
|
543
|
+
input,
|
|
544
|
+
resolved: true,
|
|
545
|
+
id: match.memberType === "agent" ? match.agentId : match.userId,
|
|
546
|
+
name: match.displayName ?? match.invitedName ?? undefined,
|
|
547
|
+
};
|
|
548
|
+
});
|
|
549
|
+
} catch {
|
|
550
|
+
return params.inputs.map((input) => ({ input, resolved: false }));
|
|
551
|
+
}
|
|
552
|
+
},
|
|
553
|
+
},
|
|
554
|
+
|
|
356
555
|
config: {
|
|
357
556
|
listAccountIds: (cfg: any) => listAccountIds(cfg),
|
|
358
557
|
resolveAccount: (cfg: any, accountId?: string | null) => resolveAccount(cfg, accountId),
|
|
@@ -422,6 +621,7 @@ function createOccumChannelPlugin(logger: PluginLogger) {
|
|
|
422
621
|
|
|
423
622
|
const channelRuntime = ctx.channelRuntime;
|
|
424
623
|
const config: ToolConfig = { agentToken: account.agentToken, apiUrl: account.apiUrl };
|
|
624
|
+
cachedConfig = config;
|
|
425
625
|
|
|
426
626
|
// Discover agent identity
|
|
427
627
|
let agentId: string | null = null;
|