
























@@ -3,6 +3,12 @@ import type { GatewayRequestHandlerOptions } from "openclaw/plugin-sdk/gateway-r
33import { definePluginEntry, type OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry";
44import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
55import { Type } from "typebox";
6+import {
7+buildGoogleMeetCalendarDayWindow,
8+findGoogleMeetCalendarEvent,
9+type GoogleMeetCalendarLookupResult,
10+} from "./src/calendar.js";
11+import { registerGoogleMeetCli } from "./src/cli.js";
612import {
713resolveGoogleMeetConfig,
814type GoogleMeetConfig,
@@ -177,6 +183,17 @@ const GoogleMeetToolSchema = Type.Object({
177183sessionId: Type.Optional(Type.String({ description: "Meet session ID" })),
178184message: Type.Optional(Type.String({ description: "Realtime instructions to speak now" })),
179185meeting: Type.Optional(Type.String({ description: "Meet URL, meeting code, or spaces/{id}" })),
186+today: Type.Optional(
187+Type.Boolean({
188+description: "For latest, artifacts, or attendance, find a Meet link on today's calendar.",
189+}),
190+),
191+event: Type.Optional(
192+Type.String({
193+description: "For latest, artifacts, or attendance, find a matching Calendar event.",
194+}),
195+),
196+calendarId: Type.Optional(Type.String({ description: "Calendar id for today/event lookup" })),
180197conferenceRecord: Type.Optional(
181198Type.String({ description: "Meet conferenceRecords/{id} resource name or id" }),
182199),
@@ -190,6 +207,15 @@ const GoogleMeetToolSchema = Type.Object({
190207"For artifacts or attendance with meeting input, fetch all conference records instead of only the latest.",
191208}),
192209),
210+mergeDuplicateParticipants: Type.Optional(
211+Type.Boolean({ description: "For attendance, merge duplicate participant resources." }),
212+),
213+lateAfterMinutes: Type.Optional(
214+Type.Number({ description: "For attendance, mark participants late after this many minutes." }),
215+),
216+earlyBeforeMinutes: Type.Optional(
217+Type.Number({ description: "For attendance, mark early leavers before this many minutes." }),
218+),
193219accessToken: Type.Optional(Type.String({ description: "Access token override" })),
194220refreshToken: Type.Optional(Type.String({ description: "Refresh token override" })),
195221clientId: Type.Optional(Type.String({ description: "OAuth client id override" })),
@@ -274,14 +300,40 @@ async function resolveGoogleMeetTokenFromParams(
274300});
275301}
276302303+function wantsCalendarLookup(raw: Record<string, unknown>): boolean {
304+return raw.today === true || Boolean(normalizeOptionalString(raw.event));
305+}
306+307+async function resolveMeetingFromParams(params: {
308+config: GoogleMeetConfig;
309+raw: Record<string, unknown>;
310+accessToken: string;
311+}): Promise<{ meeting: string; calendarEvent?: GoogleMeetCalendarLookupResult }> {
312+if (wantsCalendarLookup(params.raw)) {
313+const window = params.raw.today === true ? buildGoogleMeetCalendarDayWindow() : {};
314+const calendarEvent = await findGoogleMeetCalendarEvent({
315+accessToken: params.accessToken,
316+calendarId: normalizeOptionalString(params.raw.calendarId),
317+eventQuery: normalizeOptionalString(params.raw.event),
318+ ...window,
319+});
320+return { meeting: calendarEvent.meetingUri, calendarEvent };
321+}
322+return { meeting: resolveMeetingInput(params.config, params.raw.meeting) };
323+}
324+277325async function resolveSpaceFromParams(config: GoogleMeetConfig, raw: Record<string, unknown>) {
278-const meeting = resolveMeetingInput(config, raw.meeting);
279326const token = await resolveGoogleMeetTokenFromParams(config, raw);
327+const { meeting, calendarEvent } = await resolveMeetingFromParams({
328+ config,
329+ raw,
330+accessToken: token.accessToken,
331+});
280332const space = await fetchGoogleMeetSpace({
281333accessToken: token.accessToken,
282334 meeting,
283335});
284-return { meeting, token, space };
336+return { meeting, token, space, calendarEvent };
285337}
286338287339async function resolveArtifactQueryFromParams(
@@ -290,17 +342,27 @@ async function resolveArtifactQueryFromParams(
290342) {
291343const meeting = normalizeOptionalString(raw.meeting) ?? config.defaults.meeting;
292344const conferenceRecord = normalizeOptionalString(raw.conferenceRecord);
293-if (!meeting && !conferenceRecord) {
294-throw new Error("Meeting input or conferenceRecord required");
295-}
296345const token = await resolveGoogleMeetTokenFromParams(config, raw);
346+const resolvedMeeting: { meeting?: string; calendarEvent?: GoogleMeetCalendarLookupResult } =
347+conferenceRecord
348+ ? { meeting }
349+ : wantsCalendarLookup(raw)
350+ ? await resolveMeetingFromParams({ config, raw, accessToken: token.accessToken })
351+ : { meeting };
352+if (!resolvedMeeting.meeting && !conferenceRecord) {
353+throw new Error("Meeting input, calendar lookup, or conferenceRecord required");
354+}
297355return {
298356 token,
299- meeting,
357+meeting: resolvedMeeting.meeting,
358+calendarEvent: resolvedMeeting.calendarEvent,
300359 conferenceRecord,
301360pageSize: resolveOptionalPositiveInteger(raw.pageSize),
302361includeTranscriptEntries: raw.includeTranscriptEntries !== false,
303362allConferenceRecords: raw.includeAllConferenceRecords === true,
363+mergeDuplicateParticipants: raw.mergeDuplicateParticipants !== false,
364+lateAfterMinutes: resolveOptionalPositiveInteger(raw.lateAfterMinutes),
365+earlyBeforeMinutes: resolveOptionalPositiveInteger(raw.earlyBeforeMinutes),
304366};
305367}
306368@@ -419,15 +481,19 @@ export default definePluginEntry({
419481async ({ params, respond }: GatewayRequestHandlerOptions) => {
420482try {
421483const raw = asParamRecord(params);
422-const meeting = resolveMeetingInput(config, raw.meeting);
423484const token = await resolveGoogleMeetTokenFromParams(config, raw);
424-respond(
425-true,
426-await fetchLatestGoogleMeetConferenceRecord({
485+const resolved = await resolveMeetingFromParams({
486+ config,
487+ raw,
488+accessToken: token.accessToken,
489+});
490+respond(true, {
491+ ...(await fetchLatestGoogleMeetConferenceRecord({
427492accessToken: token.accessToken,
428- meeting,
429-}),
430-);
493+meeting: resolved.meeting,
494+})),
495+ ...(resolved.calendarEvent ? { calendarEvent: resolved.calendarEvent } : {}),
496+});
431497} catch (err) {
432498sendError(respond, err);
433499}
@@ -471,6 +537,9 @@ export default definePluginEntry({
471537conferenceRecord: resolved.conferenceRecord,
472538pageSize: resolved.pageSize,
473539allConferenceRecords: resolved.allConferenceRecords,
540+mergeDuplicateParticipants: resolved.mergeDuplicateParticipants,
541+lateAfterMinutes: resolved.lateAfterMinutes,
542+earlyBeforeMinutes: resolved.earlyBeforeMinutes,
474543}),
475544);
476545} catch (err) {
@@ -612,14 +681,19 @@ export default definePluginEntry({
612681);
613682}
614683case "latest": {
615-const meeting = resolveMeetingInput(config, raw.meeting);
616684const token = await resolveGoogleMeetTokenFromParams(config, raw);
617-return json(
618-await fetchLatestGoogleMeetConferenceRecord({
685+const resolved = await resolveMeetingFromParams({
686+ config,
687+ raw,
688+accessToken: token.accessToken,
689+});
690+return json({
691+ ...(await fetchLatestGoogleMeetConferenceRecord({
619692accessToken: token.accessToken,
620- meeting,
621-}),
622-);
693+meeting: resolved.meeting,
694+})),
695+ ...(resolved.calendarEvent ? { calendarEvent: resolved.calendarEvent } : {}),
696+});
623697}
624698case "artifacts": {
625699const resolved = await resolveArtifactQueryFromParams(config, raw);
@@ -643,6 +717,9 @@ export default definePluginEntry({
643717conferenceRecord: resolved.conferenceRecord,
644718pageSize: resolved.pageSize,
645719allConferenceRecords: resolved.allConferenceRecords,
720+mergeDuplicateParticipants: resolved.mergeDuplicateParticipants,
721+lateAfterMinutes: resolved.lateAfterMinutes,
722+earlyBeforeMinutes: resolved.earlyBeforeMinutes,
646723}),
647724);
648725}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。