@alfe.ai/openclaw-google-chat 0.0.7 → 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 +60 -18
- package/dist/plugin2.js +60 -18
- 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,22 +315,28 @@ 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
|
-
for (const m of
|
|
307
|
-
if (m.member.
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
peerDisplayName = m.member.displayName || null;
|
|
312
|
-
}
|
|
330
|
+
if (agentUserId) for (const m of humans) {
|
|
331
|
+
if (m.member.name === agentUserId) continue;
|
|
332
|
+
peerUserId = m.member.name;
|
|
333
|
+
peerDisplayName = m.member.displayName || null;
|
|
334
|
+
break;
|
|
313
335
|
}
|
|
314
|
-
if (
|
|
315
|
-
agentUserId =
|
|
316
|
-
peerUserId =
|
|
317
|
-
peerDisplayName =
|
|
336
|
+
else if (humans.length >= 2) {
|
|
337
|
+
agentUserId = humans[0].member.name;
|
|
338
|
+
peerUserId = humans[1].member.name;
|
|
339
|
+
peerDisplayName = humans[1].member.displayName || null;
|
|
318
340
|
}
|
|
319
341
|
return {
|
|
320
342
|
agentUserId,
|
|
@@ -379,6 +401,23 @@ var GChatPoller = class {
|
|
|
379
401
|
const senderDisplayName = message.sender.displayName;
|
|
380
402
|
const peerLabel = senderDisplayName || state.peerDisplayName || "User";
|
|
381
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
|
+
}
|
|
382
421
|
try {
|
|
383
422
|
const cfg = this.runtime.config.loadConfig();
|
|
384
423
|
await this.dispatchInbound({
|
|
@@ -401,7 +440,8 @@ var GChatPoller = class {
|
|
|
401
440
|
extraContext: {
|
|
402
441
|
ChannelMode: "gchat",
|
|
403
442
|
ConversationId: conversationId,
|
|
404
|
-
...senderDisplayName ? { SenderName: senderDisplayName } : {}
|
|
443
|
+
...senderDisplayName ? { SenderName: senderDisplayName } : {},
|
|
444
|
+
...resolvedIdentityId ? { IdentityId: resolvedIdentityId } : {}
|
|
405
445
|
},
|
|
406
446
|
deliver: async (payload) => {
|
|
407
447
|
const raw = payload.text ?? "";
|
|
@@ -549,7 +589,7 @@ const plugin = {
|
|
|
549
589
|
log.info("Google Chat not connected — polling disabled");
|
|
550
590
|
return;
|
|
551
591
|
}
|
|
552
|
-
|
|
592
|
+
const init = {
|
|
553
593
|
tokenManager: new (await (Promise.resolve().then(() => require("./gchat-token.cjs")))).TokenManager({
|
|
554
594
|
refreshToken: creds.refreshToken,
|
|
555
595
|
clientId: creds.clientId,
|
|
@@ -559,7 +599,9 @@ const plugin = {
|
|
|
559
599
|
runtime: pluginRuntime,
|
|
560
600
|
log,
|
|
561
601
|
agentEmail: creds.email
|
|
562
|
-
}
|
|
602
|
+
};
|
|
603
|
+
init.agentClient = client;
|
|
604
|
+
poller = new GChatPoller(init);
|
|
563
605
|
await poller.start();
|
|
564
606
|
log.info(`Google Chat poller started (account: ${creds.email})`);
|
|
565
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,22 +315,28 @@ 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
|
-
for (const m of
|
|
307
|
-
if (m.member.
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
peerDisplayName = m.member.displayName || null;
|
|
312
|
-
}
|
|
330
|
+
if (agentUserId) for (const m of humans) {
|
|
331
|
+
if (m.member.name === agentUserId) continue;
|
|
332
|
+
peerUserId = m.member.name;
|
|
333
|
+
peerDisplayName = m.member.displayName || null;
|
|
334
|
+
break;
|
|
313
335
|
}
|
|
314
|
-
if (
|
|
315
|
-
agentUserId =
|
|
316
|
-
peerUserId =
|
|
317
|
-
peerDisplayName =
|
|
336
|
+
else if (humans.length >= 2) {
|
|
337
|
+
agentUserId = humans[0].member.name;
|
|
338
|
+
peerUserId = humans[1].member.name;
|
|
339
|
+
peerDisplayName = humans[1].member.displayName || null;
|
|
318
340
|
}
|
|
319
341
|
return {
|
|
320
342
|
agentUserId,
|
|
@@ -379,6 +401,23 @@ var GChatPoller = class {
|
|
|
379
401
|
const senderDisplayName = message.sender.displayName;
|
|
380
402
|
const peerLabel = senderDisplayName || state.peerDisplayName || "User";
|
|
381
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
|
+
}
|
|
382
421
|
try {
|
|
383
422
|
const cfg = this.runtime.config.loadConfig();
|
|
384
423
|
await this.dispatchInbound({
|
|
@@ -401,7 +440,8 @@ var GChatPoller = class {
|
|
|
401
440
|
extraContext: {
|
|
402
441
|
ChannelMode: "gchat",
|
|
403
442
|
ConversationId: conversationId,
|
|
404
|
-
...senderDisplayName ? { SenderName: senderDisplayName } : {}
|
|
443
|
+
...senderDisplayName ? { SenderName: senderDisplayName } : {},
|
|
444
|
+
...resolvedIdentityId ? { IdentityId: resolvedIdentityId } : {}
|
|
405
445
|
},
|
|
406
446
|
deliver: async (payload) => {
|
|
407
447
|
const raw = payload.text ?? "";
|
|
@@ -549,7 +589,7 @@ const plugin = {
|
|
|
549
589
|
log.info("Google Chat not connected — polling disabled");
|
|
550
590
|
return;
|
|
551
591
|
}
|
|
552
|
-
|
|
592
|
+
const init = {
|
|
553
593
|
tokenManager: new (await (import("./gchat-token.js"))).TokenManager({
|
|
554
594
|
refreshToken: creds.refreshToken,
|
|
555
595
|
clientId: creds.clientId,
|
|
@@ -559,7 +599,9 @@ const plugin = {
|
|
|
559
599
|
runtime: pluginRuntime,
|
|
560
600
|
log,
|
|
561
601
|
agentEmail: creds.email
|
|
562
|
-
}
|
|
602
|
+
};
|
|
603
|
+
init.agentClient = client;
|
|
604
|
+
poller = new GChatPoller(init);
|
|
563
605
|
await poller.start();
|
|
564
606
|
log.info(`Google Chat poller started (account: ${creds.email})`);
|
|
565
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": {
|