@unblocklabs/unblock-memory 0.3.4 → 0.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/src/people-tools.js
CHANGED
|
@@ -2,7 +2,7 @@ import { jsonResult } from "openclaw/plugin-sdk/agent-runtime";
|
|
|
2
2
|
import { Type } from "typebox";
|
|
3
3
|
import { Value } from "typebox/value";
|
|
4
4
|
import { renderPeopleWhisper } from "./people-hooks.js";
|
|
5
|
-
import {
|
|
5
|
+
import { createOpenClawSlackDirectory, syncSlackDirectory, } from "./slack-directory.js";
|
|
6
6
|
const nonEmpty = Type.String({ pattern: "\\S", maxLength: 1000 });
|
|
7
7
|
const personSelector = Type.Union([
|
|
8
8
|
Type.Object({ view: Type.Literal("person"), personId: nonEmpty }, { additionalProperties: false }),
|
|
@@ -174,7 +174,7 @@ function createSyncTool(stores, reader, ctx) {
|
|
|
174
174
|
},
|
|
175
175
|
};
|
|
176
176
|
}
|
|
177
|
-
export function registerPeopleTools(api, stores, config, directoryReader
|
|
177
|
+
export function registerPeopleTools(api, stores, config, directoryReader) {
|
|
178
178
|
api.registerTool((ctx) => createInspectTool(stores, config, ctx), {
|
|
179
179
|
names: ["memory_people_inspect"],
|
|
180
180
|
optional: true,
|
|
@@ -183,7 +183,10 @@ export function registerPeopleTools(api, stores, config, directoryReader = openC
|
|
|
183
183
|
names: ["memory_people_update"],
|
|
184
184
|
optional: true,
|
|
185
185
|
});
|
|
186
|
-
api.registerTool((ctx) => createSyncTool(stores, directoryReader
|
|
186
|
+
api.registerTool((ctx) => createSyncTool(stores, directoryReader ??
|
|
187
|
+
createOpenClawSlackDirectory({
|
|
188
|
+
getConfig: () => ctx.getRuntimeConfig?.() ?? ctx.runtimeConfig ?? ctx.config,
|
|
189
|
+
}), ctx), {
|
|
187
190
|
names: ["memory_people_sync"],
|
|
188
191
|
optional: true,
|
|
189
192
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { OpenClawConfig } from "openclaw/plugin-sdk/plugin-entry";
|
|
1
2
|
import type { PeopleStore } from "./people-store.js";
|
|
2
3
|
type SlackDirectoryEntry = {
|
|
3
4
|
id: string;
|
|
@@ -11,13 +12,22 @@ export type SlackDirectoryReader = {
|
|
|
11
12
|
limit: number;
|
|
12
13
|
}): Promise<readonly SlackDirectoryEntry[]>;
|
|
13
14
|
};
|
|
14
|
-
type
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}>;
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
type SlackAccountInspector = (params: {
|
|
16
|
+
channelId: "slack";
|
|
17
|
+
cfg: OpenClawConfig;
|
|
18
|
+
accountId: string;
|
|
19
|
+
}) => Promise<Record<string, unknown> | null>;
|
|
20
|
+
type SlackRequest = (input: string | URL, init: {
|
|
21
|
+
headers: {
|
|
22
|
+
authorization: string;
|
|
23
|
+
};
|
|
24
|
+
signal: AbortSignal;
|
|
25
|
+
}) => Promise<Pick<Response, "json" | "ok" | "status">>;
|
|
26
|
+
export declare function createOpenClawSlackDirectory(params: {
|
|
27
|
+
getConfig: () => OpenClawConfig | undefined;
|
|
28
|
+
inspectAccount?: SlackAccountInspector;
|
|
29
|
+
request?: SlackRequest;
|
|
30
|
+
}): SlackDirectoryReader;
|
|
21
31
|
export declare function syncSlackDirectory(params: {
|
|
22
32
|
store: PeopleStore;
|
|
23
33
|
reader: SlackDirectoryReader;
|
|
@@ -1,55 +1,83 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { promisify } from "node:util";
|
|
3
|
-
const execFileAsync = promisify(execFile);
|
|
1
|
+
import { inspectReadOnlyChannelAccount } from "openclaw/plugin-sdk/directory-runtime";
|
|
4
2
|
function text(value, maxLength) {
|
|
5
3
|
return typeof value === "string" && value.trim() ? value.trim().slice(0, maxLength) : undefined;
|
|
6
4
|
}
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
function record(value) {
|
|
6
|
+
return value && typeof value === "object" && !Array.isArray(value)
|
|
7
|
+
? value
|
|
8
|
+
: undefined;
|
|
9
|
+
}
|
|
10
|
+
function slackToken(account) {
|
|
11
|
+
return text(account.userToken, 10_000) ?? text(account.botToken, 10_000);
|
|
12
|
+
}
|
|
13
|
+
function slackEntry(value) {
|
|
14
|
+
const member = record(value);
|
|
15
|
+
const id = text(member?.id, 200);
|
|
16
|
+
if (!id)
|
|
17
|
+
return undefined;
|
|
18
|
+
const profile = record(member?.profile);
|
|
19
|
+
return {
|
|
20
|
+
id,
|
|
21
|
+
name: text(profile?.display_name, 500) ??
|
|
22
|
+
text(profile?.real_name, 500) ??
|
|
23
|
+
text(member?.real_name, 500) ??
|
|
24
|
+
text(member?.name, 500),
|
|
25
|
+
handle: text(member?.name, 200),
|
|
26
|
+
avatarUrl: text(profile?.image_512, 2_000) ??
|
|
27
|
+
text(profile?.image_192, 2_000) ??
|
|
28
|
+
text(profile?.image_72, 2_000),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
export function createOpenClawSlackDirectory(params) {
|
|
32
|
+
const inspectAccount = params.inspectAccount ?? inspectReadOnlyChannelAccount;
|
|
33
|
+
const request = params.request ?? fetch;
|
|
11
34
|
return {
|
|
12
35
|
async listUsers({ accountId, limit }) {
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
36
|
+
const cfg = params.getConfig();
|
|
37
|
+
if (!cfg)
|
|
38
|
+
throw new Error("OpenClaw runtime config is unavailable");
|
|
39
|
+
const account = await inspectAccount({ channelId: "slack", cfg, accountId });
|
|
40
|
+
const token = account ? slackToken(account) : undefined;
|
|
41
|
+
if (!token) {
|
|
42
|
+
throw new Error(`Slack credentials for account "${accountId}" are unavailable in the active runtime snapshot`);
|
|
43
|
+
}
|
|
44
|
+
const entries = [];
|
|
45
|
+
const cursors = new Set();
|
|
46
|
+
let cursor;
|
|
47
|
+
while (entries.length < limit) {
|
|
48
|
+
const url = new URL("https://slack.com/api/users.list");
|
|
49
|
+
url.searchParams.set("limit", String(Math.min(limit, 200)));
|
|
50
|
+
if (cursor)
|
|
51
|
+
url.searchParams.set("cursor", cursor);
|
|
52
|
+
const response = await request(url, {
|
|
53
|
+
headers: { authorization: `Bearer ${token}` },
|
|
54
|
+
signal: AbortSignal.timeout(30_000),
|
|
55
|
+
});
|
|
56
|
+
const payload = record(await response.json());
|
|
57
|
+
if (!response.ok || payload?.ok !== true) {
|
|
58
|
+
const detail = text(payload?.error, 200) ?? `HTTP ${response.status}`;
|
|
59
|
+
throw new Error(`Slack directory request failed: ${detail}`);
|
|
60
|
+
}
|
|
61
|
+
const members = Array.isArray(payload.members) ? payload.members : [];
|
|
62
|
+
for (const member of members) {
|
|
63
|
+
const entry = slackEntry(member);
|
|
64
|
+
if (entry)
|
|
65
|
+
entries.push(entry);
|
|
66
|
+
if (entries.length === limit)
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
const next = text(record(payload.response_metadata)?.next_cursor, 2_000);
|
|
70
|
+
if (!next)
|
|
71
|
+
break;
|
|
72
|
+
if (cursors.has(next))
|
|
73
|
+
throw new Error("Slack directory returned a repeated cursor");
|
|
74
|
+
cursors.add(next);
|
|
75
|
+
cursor = next;
|
|
76
|
+
}
|
|
77
|
+
return entries;
|
|
49
78
|
},
|
|
50
79
|
};
|
|
51
80
|
}
|
|
52
|
-
export const openClawSlackDirectory = createOpenClawSlackDirectory();
|
|
53
81
|
export async function syncSlackDirectory(params) {
|
|
54
82
|
const entries = await params.reader.listUsers({
|
|
55
83
|
accountId: params.accountId,
|
package/openclaw.plugin.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "unblock-memory",
|
|
3
3
|
"name": "Unblock Memory",
|
|
4
|
-
"version": "0.3.
|
|
4
|
+
"version": "0.3.5",
|
|
5
5
|
"description": "Indexes, retrieves, and analyzes configured workspace memory with existing QMD vectors.",
|
|
6
6
|
"kind": "memory",
|
|
7
7
|
"activation": { "onStartup": false },
|