@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 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 members = await listMembers(token, spaceName);
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(members) {
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 members) {
307
- if (m.member.type !== "HUMAN") continue;
308
- if (this.agentEmail && m.member.displayName?.toLowerCase().includes(this.agentEmail.split("@")[0].toLowerCase())) agentUserId = m.member.name;
309
- else {
310
- peerUserId = m.member.name;
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 (!agentUserId && members.length >= 2) {
315
- agentUserId = members[0].member.name;
316
- peerUserId = members[1].member.name;
317
- peerDisplayName = members[1].member.displayName || null;
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
- poller = new GChatPoller({
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 members = await listMembers(token, spaceName);
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(members) {
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 members) {
307
- if (m.member.type !== "HUMAN") continue;
308
- if (this.agentEmail && m.member.displayName?.toLowerCase().includes(this.agentEmail.split("@")[0].toLowerCase())) agentUserId = m.member.name;
309
- else {
310
- peerUserId = m.member.name;
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 (!agentUserId && members.length >= 2) {
315
- agentUserId = members[0].member.name;
316
- peerUserId = members[1].member.name;
317
- peerDisplayName = members[1].member.displayName || null;
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
- poller = new GChatPoller({
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.7",
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.12",
30
+ "@alfe.ai/agent-api-client": "^0.1.0",
31
31
  "@alfe.ai/config": "^0.0.8"
32
32
  },
33
33
  "peerDependencies": {