@alfe.ai/openclaw-google-chat 0.0.8 → 0.0.9
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/plugin2.cjs +54 -13
- package/dist/plugin2.js +54 -13
- package/package.json +2 -2
package/dist/plugin2.cjs
CHANGED
|
@@ -55,6 +55,17 @@ var StateManager = class {
|
|
|
55
55
|
getLastSeenTimestamp(spaceName) {
|
|
56
56
|
return this.state.spaces[spaceName]?.lastSeenTimestamp;
|
|
57
57
|
}
|
|
58
|
+
/** Get cached agent user ID, but only if it was resolved for the same email. */
|
|
59
|
+
getCachedAgentUserId(currentEmail) {
|
|
60
|
+
if (this.state.agentEmail !== currentEmail) return void 0;
|
|
61
|
+
return this.state.agentUserId;
|
|
62
|
+
}
|
|
63
|
+
/** Cache the agent's global user ID and the email it was resolved from. */
|
|
64
|
+
setAgentIdentity(userId, email) {
|
|
65
|
+
this.state.agentUserId = userId;
|
|
66
|
+
this.state.agentEmail = email;
|
|
67
|
+
this.dirty = true;
|
|
68
|
+
}
|
|
58
69
|
/** Get the agent's userId for a space (if previously resolved). */
|
|
59
70
|
getAgentUserId(spaceName) {
|
|
60
71
|
return this.state.spaces[spaceName]?.agentUserId;
|
|
@@ -143,6 +154,10 @@ async function sendMessage(token, spaceName, text) {
|
|
|
143
154
|
body: JSON.stringify({ text })
|
|
144
155
|
});
|
|
145
156
|
}
|
|
157
|
+
/** Get a specific member of a space by user resource name or email alias. */
|
|
158
|
+
async function getMember(token, spaceName, userId) {
|
|
159
|
+
return request(token, `/${spaceName}/members/${userId}`);
|
|
160
|
+
}
|
|
146
161
|
/** List members of a space. */
|
|
147
162
|
async function listMembers(token, spaceName) {
|
|
148
163
|
const allMembers = [];
|
|
@@ -207,6 +222,7 @@ var GChatPoller = class {
|
|
|
207
222
|
log;
|
|
208
223
|
stateManager;
|
|
209
224
|
agentEmail;
|
|
225
|
+
agentClient;
|
|
210
226
|
spaces = /* @__PURE__ */ new Map();
|
|
211
227
|
seenMessages = /* @__PURE__ */ new Map();
|
|
212
228
|
discoveryTimer = null;
|
|
@@ -217,6 +233,7 @@ var GChatPoller = class {
|
|
|
217
233
|
this.runtime = init.runtime;
|
|
218
234
|
this.log = init.log;
|
|
219
235
|
this.agentEmail = init.agentEmail;
|
|
236
|
+
this.agentClient = init.agentClient ?? null;
|
|
220
237
|
this.stateManager = new StateManager(init.log);
|
|
221
238
|
}
|
|
222
239
|
/** Start the polling engine. */
|
|
@@ -272,8 +289,7 @@ var GChatPoller = class {
|
|
|
272
289
|
let peerUserId = this.stateManager.getPeerUserId(spaceName) ?? "";
|
|
273
290
|
let peerDisplayName = null;
|
|
274
291
|
if (!agentUserId || !peerUserId) try {
|
|
275
|
-
const
|
|
276
|
-
const resolved = this.resolveMembers(members);
|
|
292
|
+
const resolved = await this.resolveMembers(token, spaceName);
|
|
277
293
|
agentUserId = resolved.agentUserId;
|
|
278
294
|
peerUserId = resolved.peerUserId;
|
|
279
295
|
peerDisplayName = resolved.peerDisplayName;
|
|
@@ -299,20 +315,25 @@ var GChatPoller = class {
|
|
|
299
315
|
this.seenMessages.set(spaceName, /* @__PURE__ */ new Set());
|
|
300
316
|
this.scheduleSpacePoll(state);
|
|
301
317
|
}
|
|
302
|
-
resolveMembers(
|
|
303
|
-
let agentUserId = "";
|
|
318
|
+
async resolveMembers(token, spaceName) {
|
|
319
|
+
let agentUserId = this.stateManager.getCachedAgentUserId(this.agentEmail) ?? "";
|
|
320
|
+
if (!agentUserId && this.agentEmail) try {
|
|
321
|
+
agentUserId = (await getMember(token, spaceName, `users/${this.agentEmail}`)).member.name;
|
|
322
|
+
this.stateManager.setAgentIdentity(agentUserId, this.agentEmail);
|
|
323
|
+
this.log.info(`Resolved agent user ID: ${agentUserId}`);
|
|
324
|
+
} catch (err) {
|
|
325
|
+
this.log.warn(`Failed to look up agent by email: ${err instanceof Error ? err.message : String(err)}`);
|
|
326
|
+
}
|
|
327
|
+
const humans = (await listMembers(token, spaceName)).filter((m) => m.member.type === "HUMAN");
|
|
304
328
|
let peerUserId = "";
|
|
305
329
|
let peerDisplayName = null;
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
const humans = members.filter((m) => m.member.type === "HUMAN");
|
|
309
|
-
for (const m of humans) if (agentPrefix && normalize(m.member.displayName ?? "").includes(agentPrefix)) agentUserId = m.member.name;
|
|
310
|
-
for (const m of humans) if (m.member.name !== agentUserId) {
|
|
330
|
+
if (agentUserId) for (const m of humans) {
|
|
331
|
+
if (m.member.name === agentUserId) continue;
|
|
311
332
|
peerUserId = m.member.name;
|
|
312
333
|
peerDisplayName = m.member.displayName || null;
|
|
313
334
|
break;
|
|
314
335
|
}
|
|
315
|
-
if (
|
|
336
|
+
else if (humans.length >= 2) {
|
|
316
337
|
agentUserId = humans[0].member.name;
|
|
317
338
|
peerUserId = humans[1].member.name;
|
|
318
339
|
peerDisplayName = humans[1].member.displayName || null;
|
|
@@ -380,6 +401,23 @@ var GChatPoller = class {
|
|
|
380
401
|
const senderDisplayName = message.sender.displayName;
|
|
381
402
|
const peerLabel = senderDisplayName || state.peerDisplayName || "User";
|
|
382
403
|
this.log.info(`Dispatching message from ${peerLabel} in ${state.spaceName}`);
|
|
404
|
+
let resolvedIdentityId;
|
|
405
|
+
let accessAllowed = true;
|
|
406
|
+
if (this.agentClient) try {
|
|
407
|
+
const senderUserId = senderName.startsWith("users/") ? senderName.slice(6) : senderName;
|
|
408
|
+
const result = await this.agentClient.resolveGoogleChatSender({
|
|
409
|
+
senderUserId,
|
|
410
|
+
spaceId: state.spaceName
|
|
411
|
+
});
|
|
412
|
+
resolvedIdentityId = result.identityId ?? void 0;
|
|
413
|
+
accessAllowed = result.accessAllowed;
|
|
414
|
+
if (!accessAllowed) {
|
|
415
|
+
this.log.info(`Skipping dispatch — access denied for sender ${peerLabel} (${senderUserId})`);
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
} catch (err) {
|
|
419
|
+
this.log.warn(`Sender resolve failed; dispatching without IdentityId: ${err instanceof Error ? err.message : String(err)}`);
|
|
420
|
+
}
|
|
383
421
|
try {
|
|
384
422
|
const cfg = this.runtime.config.loadConfig();
|
|
385
423
|
await this.dispatchInbound({
|
|
@@ -402,7 +440,8 @@ var GChatPoller = class {
|
|
|
402
440
|
extraContext: {
|
|
403
441
|
ChannelMode: "gchat",
|
|
404
442
|
ConversationId: conversationId,
|
|
405
|
-
...senderDisplayName ? { SenderName: senderDisplayName } : {}
|
|
443
|
+
...senderDisplayName ? { SenderName: senderDisplayName } : {},
|
|
444
|
+
...resolvedIdentityId ? { IdentityId: resolvedIdentityId } : {}
|
|
406
445
|
},
|
|
407
446
|
deliver: async (payload) => {
|
|
408
447
|
const raw = payload.text ?? "";
|
|
@@ -550,7 +589,7 @@ const plugin = {
|
|
|
550
589
|
log.info("Google Chat not connected — polling disabled");
|
|
551
590
|
return;
|
|
552
591
|
}
|
|
553
|
-
|
|
592
|
+
const init = {
|
|
554
593
|
tokenManager: new (await (Promise.resolve().then(() => require("./gchat-token.cjs")))).TokenManager({
|
|
555
594
|
refreshToken: creds.refreshToken,
|
|
556
595
|
clientId: creds.clientId,
|
|
@@ -560,7 +599,9 @@ const plugin = {
|
|
|
560
599
|
runtime: pluginRuntime,
|
|
561
600
|
log,
|
|
562
601
|
agentEmail: creds.email
|
|
563
|
-
}
|
|
602
|
+
};
|
|
603
|
+
init.agentClient = client;
|
|
604
|
+
poller = new GChatPoller(init);
|
|
564
605
|
await poller.start();
|
|
565
606
|
log.info(`Google Chat poller started (account: ${creds.email})`);
|
|
566
607
|
};
|
package/dist/plugin2.js
CHANGED
|
@@ -55,6 +55,17 @@ var StateManager = class {
|
|
|
55
55
|
getLastSeenTimestamp(spaceName) {
|
|
56
56
|
return this.state.spaces[spaceName]?.lastSeenTimestamp;
|
|
57
57
|
}
|
|
58
|
+
/** Get cached agent user ID, but only if it was resolved for the same email. */
|
|
59
|
+
getCachedAgentUserId(currentEmail) {
|
|
60
|
+
if (this.state.agentEmail !== currentEmail) return void 0;
|
|
61
|
+
return this.state.agentUserId;
|
|
62
|
+
}
|
|
63
|
+
/** Cache the agent's global user ID and the email it was resolved from. */
|
|
64
|
+
setAgentIdentity(userId, email) {
|
|
65
|
+
this.state.agentUserId = userId;
|
|
66
|
+
this.state.agentEmail = email;
|
|
67
|
+
this.dirty = true;
|
|
68
|
+
}
|
|
58
69
|
/** Get the agent's userId for a space (if previously resolved). */
|
|
59
70
|
getAgentUserId(spaceName) {
|
|
60
71
|
return this.state.spaces[spaceName]?.agentUserId;
|
|
@@ -143,6 +154,10 @@ async function sendMessage(token, spaceName, text) {
|
|
|
143
154
|
body: JSON.stringify({ text })
|
|
144
155
|
});
|
|
145
156
|
}
|
|
157
|
+
/** Get a specific member of a space by user resource name or email alias. */
|
|
158
|
+
async function getMember(token, spaceName, userId) {
|
|
159
|
+
return request(token, `/${spaceName}/members/${userId}`);
|
|
160
|
+
}
|
|
146
161
|
/** List members of a space. */
|
|
147
162
|
async function listMembers(token, spaceName) {
|
|
148
163
|
const allMembers = [];
|
|
@@ -207,6 +222,7 @@ var GChatPoller = class {
|
|
|
207
222
|
log;
|
|
208
223
|
stateManager;
|
|
209
224
|
agentEmail;
|
|
225
|
+
agentClient;
|
|
210
226
|
spaces = /* @__PURE__ */ new Map();
|
|
211
227
|
seenMessages = /* @__PURE__ */ new Map();
|
|
212
228
|
discoveryTimer = null;
|
|
@@ -217,6 +233,7 @@ var GChatPoller = class {
|
|
|
217
233
|
this.runtime = init.runtime;
|
|
218
234
|
this.log = init.log;
|
|
219
235
|
this.agentEmail = init.agentEmail;
|
|
236
|
+
this.agentClient = init.agentClient ?? null;
|
|
220
237
|
this.stateManager = new StateManager(init.log);
|
|
221
238
|
}
|
|
222
239
|
/** Start the polling engine. */
|
|
@@ -272,8 +289,7 @@ var GChatPoller = class {
|
|
|
272
289
|
let peerUserId = this.stateManager.getPeerUserId(spaceName) ?? "";
|
|
273
290
|
let peerDisplayName = null;
|
|
274
291
|
if (!agentUserId || !peerUserId) try {
|
|
275
|
-
const
|
|
276
|
-
const resolved = this.resolveMembers(members);
|
|
292
|
+
const resolved = await this.resolveMembers(token, spaceName);
|
|
277
293
|
agentUserId = resolved.agentUserId;
|
|
278
294
|
peerUserId = resolved.peerUserId;
|
|
279
295
|
peerDisplayName = resolved.peerDisplayName;
|
|
@@ -299,20 +315,25 @@ var GChatPoller = class {
|
|
|
299
315
|
this.seenMessages.set(spaceName, /* @__PURE__ */ new Set());
|
|
300
316
|
this.scheduleSpacePoll(state);
|
|
301
317
|
}
|
|
302
|
-
resolveMembers(
|
|
303
|
-
let agentUserId = "";
|
|
318
|
+
async resolveMembers(token, spaceName) {
|
|
319
|
+
let agentUserId = this.stateManager.getCachedAgentUserId(this.agentEmail) ?? "";
|
|
320
|
+
if (!agentUserId && this.agentEmail) try {
|
|
321
|
+
agentUserId = (await getMember(token, spaceName, `users/${this.agentEmail}`)).member.name;
|
|
322
|
+
this.stateManager.setAgentIdentity(agentUserId, this.agentEmail);
|
|
323
|
+
this.log.info(`Resolved agent user ID: ${agentUserId}`);
|
|
324
|
+
} catch (err) {
|
|
325
|
+
this.log.warn(`Failed to look up agent by email: ${err instanceof Error ? err.message : String(err)}`);
|
|
326
|
+
}
|
|
327
|
+
const humans = (await listMembers(token, spaceName)).filter((m) => m.member.type === "HUMAN");
|
|
304
328
|
let peerUserId = "";
|
|
305
329
|
let peerDisplayName = null;
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
const humans = members.filter((m) => m.member.type === "HUMAN");
|
|
309
|
-
for (const m of humans) if (agentPrefix && normalize(m.member.displayName ?? "").includes(agentPrefix)) agentUserId = m.member.name;
|
|
310
|
-
for (const m of humans) if (m.member.name !== agentUserId) {
|
|
330
|
+
if (agentUserId) for (const m of humans) {
|
|
331
|
+
if (m.member.name === agentUserId) continue;
|
|
311
332
|
peerUserId = m.member.name;
|
|
312
333
|
peerDisplayName = m.member.displayName || null;
|
|
313
334
|
break;
|
|
314
335
|
}
|
|
315
|
-
if (
|
|
336
|
+
else if (humans.length >= 2) {
|
|
316
337
|
agentUserId = humans[0].member.name;
|
|
317
338
|
peerUserId = humans[1].member.name;
|
|
318
339
|
peerDisplayName = humans[1].member.displayName || null;
|
|
@@ -380,6 +401,23 @@ var GChatPoller = class {
|
|
|
380
401
|
const senderDisplayName = message.sender.displayName;
|
|
381
402
|
const peerLabel = senderDisplayName || state.peerDisplayName || "User";
|
|
382
403
|
this.log.info(`Dispatching message from ${peerLabel} in ${state.spaceName}`);
|
|
404
|
+
let resolvedIdentityId;
|
|
405
|
+
let accessAllowed = true;
|
|
406
|
+
if (this.agentClient) try {
|
|
407
|
+
const senderUserId = senderName.startsWith("users/") ? senderName.slice(6) : senderName;
|
|
408
|
+
const result = await this.agentClient.resolveGoogleChatSender({
|
|
409
|
+
senderUserId,
|
|
410
|
+
spaceId: state.spaceName
|
|
411
|
+
});
|
|
412
|
+
resolvedIdentityId = result.identityId ?? void 0;
|
|
413
|
+
accessAllowed = result.accessAllowed;
|
|
414
|
+
if (!accessAllowed) {
|
|
415
|
+
this.log.info(`Skipping dispatch — access denied for sender ${peerLabel} (${senderUserId})`);
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
} catch (err) {
|
|
419
|
+
this.log.warn(`Sender resolve failed; dispatching without IdentityId: ${err instanceof Error ? err.message : String(err)}`);
|
|
420
|
+
}
|
|
383
421
|
try {
|
|
384
422
|
const cfg = this.runtime.config.loadConfig();
|
|
385
423
|
await this.dispatchInbound({
|
|
@@ -402,7 +440,8 @@ var GChatPoller = class {
|
|
|
402
440
|
extraContext: {
|
|
403
441
|
ChannelMode: "gchat",
|
|
404
442
|
ConversationId: conversationId,
|
|
405
|
-
...senderDisplayName ? { SenderName: senderDisplayName } : {}
|
|
443
|
+
...senderDisplayName ? { SenderName: senderDisplayName } : {},
|
|
444
|
+
...resolvedIdentityId ? { IdentityId: resolvedIdentityId } : {}
|
|
406
445
|
},
|
|
407
446
|
deliver: async (payload) => {
|
|
408
447
|
const raw = payload.text ?? "";
|
|
@@ -550,7 +589,7 @@ const plugin = {
|
|
|
550
589
|
log.info("Google Chat not connected — polling disabled");
|
|
551
590
|
return;
|
|
552
591
|
}
|
|
553
|
-
|
|
592
|
+
const init = {
|
|
554
593
|
tokenManager: new (await (import("./gchat-token.js"))).TokenManager({
|
|
555
594
|
refreshToken: creds.refreshToken,
|
|
556
595
|
clientId: creds.clientId,
|
|
@@ -560,7 +599,9 @@ const plugin = {
|
|
|
560
599
|
runtime: pluginRuntime,
|
|
561
600
|
log,
|
|
562
601
|
agentEmail: creds.email
|
|
563
|
-
}
|
|
602
|
+
};
|
|
603
|
+
init.agentClient = client;
|
|
604
|
+
poller = new GChatPoller(init);
|
|
564
605
|
await poller.start();
|
|
565
606
|
log.info(`Google Chat poller started (account: ${creds.email})`);
|
|
566
607
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alfe.ai/openclaw-google-chat",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.9",
|
|
4
4
|
"description": "OpenClaw Google Chat plugin — DM polling and auto-reply via connected Google account",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/plugin.js",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"openclaw.plugin.json"
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@alfe.ai/agent-api-client": "^0.0
|
|
30
|
+
"@alfe.ai/agent-api-client": "^0.1.0",
|
|
31
31
|
"@alfe.ai/config": "^0.0.8"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|