diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d5efd3a86d..9d3bca10e58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -77,6 +77,7 @@ Docs: https://docs.openclaw.ai - Plugins/Google Meet: add `googlemeet artifacts` and `googlemeet attendance` commands plus matching tool/gateway actions for conference records, recordings, transcripts and transcript entries, smart notes, and participant sessions. Thanks @steipete. - Plugins/Google Meet: add markdown and file output for `googlemeet artifacts` and `googlemeet attendance` reports. Thanks @steipete. - Plugins/Google Meet: add `googlemeet latest` plus matching tool/gateway actions to find the newest conference record for a meeting. Thanks @steipete. +- Plugins/Google Meet: make meeting-based artifact and attendance lookups use the latest conference record by default, with `--all-conference-records` for full history. Thanks @steipete. - Plugins/Google Meet: add `googlemeet doctor --oauth` so operators can verify OAuth token refresh, Meet space reads, and side-effecting space creation without printing secrets. Thanks @steipete. - Plugins/Voice Call: expose the shared `openclaw_agent_consult` realtime tool so live phone calls can ask the full OpenClaw agent for deeper/tool-backed answers. Thanks @steipete. - Plugins/Voice Call: add `voicecall setup` and a dry-run-by-default `voicecall smoke` command so Twilio/provider readiness can be checked before placing a live test call. Thanks @steipete. diff --git a/docs/plugins/google-meet.md b/docs/plugins/google-meet.md index 0225f07634e..5c442b25be9 100644 --- a/docs/plugins/google-meet.md +++ b/docs/plugins/google-meet.md @@ -635,6 +635,10 @@ openclaw googlemeet artifacts --meeting https://meet.google.com/abc-defg-hij openclaw googlemeet attendance --meeting https://meet.google.com/abc-defg-hij ``` +With `--meeting`, `artifacts` and `attendance` use the latest conference record +by default. Pass `--all-conference-records` when you want every retained record +for that meeting. + If you already know the conference record id, address it directly: ```bash diff --git a/extensions/google-meet/index.test.ts b/extensions/google-meet/index.test.ts index e8288c23ed8..0ac206e21c5 100644 --- a/extensions/google-meet/index.test.ts +++ b/extensions/google-meet/index.test.ts @@ -439,7 +439,7 @@ describe("google-meet plugin", () => { ); }); - it("lists Meet artifact metadata for conference records", async () => { + it("lists Meet artifact metadata for the latest conference record by default", async () => { const fetchMock = stubMeetArtifactsApi(); await expect( @@ -483,7 +483,7 @@ describe("google-meet plugin", () => { } const listUrl = requestUrl(listCall[0]); expect(listUrl.searchParams.get("filter")).toBe('space.name = "spaces/abc-defg-hij"'); - expect(listUrl.searchParams.get("pageSize")).toBe("2"); + expect(listUrl.searchParams.get("pageSize")).toBe("1"); expect(fetchGuardMocks.fetchWithSsrFGuard).toHaveBeenCalledWith( expect.objectContaining({ url: "https://meet.googleapis.com/v2/conferenceRecords/rec-1/smartNotes?pageSize=2", @@ -498,6 +498,28 @@ describe("google-meet plugin", () => { ); }); + it("keeps all conference records available when requested", async () => { + const fetchMock = stubMeetArtifactsApi(); + + await fetchGoogleMeetArtifacts({ + accessToken: "token", + meeting: "abc-defg-hij", + pageSize: 2, + allConferenceRecords: true, + }); + + const listCall = fetchMock.mock.calls.find(([input]) => { + const url = requestUrl(input); + return url.pathname === "/v2/conferenceRecords"; + }); + if (!listCall) { + throw new Error("Expected conferenceRecords.list fetch call"); + } + const listUrl = requestUrl(listCall[0]); + expect(listUrl.searchParams.get("pageSize")).toBe("2"); + expect(listUrl.searchParams.get("filter")).toBe('space.name = "spaces/abc-defg-hij"'); + }); + it("fetches only the latest Meet conference record for a meeting", async () => { const fetchMock = stubMeetArtifactsApi(); diff --git a/extensions/google-meet/index.ts b/extensions/google-meet/index.ts index 8190d305113..01b2b57961c 100644 --- a/extensions/google-meet/index.ts +++ b/extensions/google-meet/index.ts @@ -191,6 +191,12 @@ const GoogleMeetToolSchema = Type.Object({ includeTranscriptEntries: Type.Optional( Type.Boolean({ description: "For artifacts, include structured transcript entries" }), ), + includeAllConferenceRecords: Type.Optional( + Type.Boolean({ + description: + "For artifacts or attendance with meeting input, fetch all conference records instead of only the latest.", + }), + ), accessToken: Type.Optional(Type.String({ description: "Access token override" })), refreshToken: Type.Optional(Type.String({ description: "Refresh token override" })), clientId: Type.Optional(Type.String({ description: "OAuth client id override" })), @@ -277,6 +283,7 @@ async function resolveArtifactQueryFromParams( conferenceRecord, pageSize: resolveOptionalPositiveInteger(raw.pageSize), includeTranscriptEntries: raw.includeTranscriptEntries !== false, + allConferenceRecords: raw.includeAllConferenceRecords === true, }; } @@ -424,6 +431,7 @@ export default definePluginEntry({ conferenceRecord: resolved.conferenceRecord, pageSize: resolved.pageSize, includeTranscriptEntries: resolved.includeTranscriptEntries, + allConferenceRecords: resolved.allConferenceRecords, }), ); } catch (err) { @@ -445,6 +453,7 @@ export default definePluginEntry({ meeting: resolved.meeting, conferenceRecord: resolved.conferenceRecord, pageSize: resolved.pageSize, + allConferenceRecords: resolved.allConferenceRecords, }), ); } catch (err) { @@ -604,6 +613,7 @@ export default definePluginEntry({ conferenceRecord: resolved.conferenceRecord, pageSize: resolved.pageSize, includeTranscriptEntries: resolved.includeTranscriptEntries, + allConferenceRecords: resolved.allConferenceRecords, }), ); } @@ -615,6 +625,7 @@ export default definePluginEntry({ meeting: resolved.meeting, conferenceRecord: resolved.conferenceRecord, pageSize: resolved.pageSize, + allConferenceRecords: resolved.allConferenceRecords, }), ); } diff --git a/extensions/google-meet/src/cli.ts b/extensions/google-meet/src/cli.ts index 41d1802e857..0e752f1600d 100644 --- a/extensions/google-meet/src/cli.ts +++ b/extensions/google-meet/src/cli.ts @@ -55,6 +55,7 @@ type MeetArtifactOptions = ResolveSpaceOptions & { conferenceRecord?: string; pageSize?: string; transcriptEntries?: boolean; + allConferenceRecords?: boolean; format?: "summary" | "markdown"; output?: string; }; @@ -445,6 +446,7 @@ function resolveArtifactTokenOptions( expiresAt?: number; pageSize?: number; includeTranscriptEntries?: boolean; + allConferenceRecords?: boolean; } { const meeting = options.meeting?.trim() || config.defaults.meeting; const conferenceRecord = options.conferenceRecord?.trim(); @@ -463,6 +465,7 @@ function resolveArtifactTokenOptions( expiresAt: parseOptionalNumber(options.expiresAt) ?? config.oauth.expiresAt, pageSize: parseOptionalNumber(options.pageSize), includeTranscriptEntries: options.transcriptEntries !== false, + allConferenceRecords: Boolean(options.allConferenceRecords), }; } @@ -1030,6 +1033,7 @@ export function registerGoogleMeetCli(params: { .option("--client-secret ", "OAuth client secret override") .option("--expires-at ", "Cached access token expiry as unix epoch milliseconds") .option("--page-size ", "Max resources per Meet API page") + .option("--all-conference-records", "Fetch every conference record for --meeting") .option("--no-transcript-entries", "Skip structured transcript entry lookup") .option("--format ", "Output format: summary or markdown", "summary") .option("--output ", "Write output to a file instead of stdout") @@ -1043,6 +1047,7 @@ export function registerGoogleMeetCli(params: { conferenceRecord: resolved.conferenceRecord, pageSize: resolved.pageSize, includeTranscriptEntries: resolved.includeTranscriptEntries, + allConferenceRecords: resolved.allConferenceRecords, }); if (options.json) { await writeCliOutput( @@ -1083,6 +1088,7 @@ export function registerGoogleMeetCli(params: { .option("--client-secret ", "OAuth client secret override") .option("--expires-at ", "Cached access token expiry as unix epoch milliseconds") .option("--page-size ", "Max resources per Meet API page") + .option("--all-conference-records", "Fetch every conference record for --meeting") .option("--format ", "Output format: summary or markdown", "summary") .option("--output ", "Write output to a file instead of stdout") .option("--json", "Print JSON output", false) @@ -1094,6 +1100,7 @@ export function registerGoogleMeetCli(params: { meeting: resolved.meeting, conferenceRecord: resolved.conferenceRecord, pageSize: resolved.pageSize, + allConferenceRecords: resolved.allConferenceRecords, }); if (options.json) { await writeCliOutput( diff --git a/extensions/google-meet/src/meet.ts b/extensions/google-meet/src/meet.ts index ffebce9c0fc..bea42bd33f0 100644 --- a/extensions/google-meet/src/meet.ts +++ b/extensions/google-meet/src/meet.ts @@ -532,6 +532,7 @@ async function resolveConferenceRecordQuery(params: { meeting?: string; conferenceRecord?: string; pageSize?: number; + allConferenceRecords?: boolean; }): Promise<{ input?: string; space?: GoogleMeetSpace; @@ -557,7 +558,8 @@ async function resolveConferenceRecordQuery(params: { const conferenceRecords = await listGoogleMeetConferenceRecords({ accessToken: params.accessToken, meeting: space.name, - pageSize: params.pageSize, + pageSize: params.allConferenceRecords ? params.pageSize : 1, + maxItems: params.allConferenceRecords ? undefined : 1, }); return { input: params.meeting, @@ -572,6 +574,7 @@ export async function fetchGoogleMeetArtifacts(params: { conferenceRecord?: string; pageSize?: number; includeTranscriptEntries?: boolean; + allConferenceRecords?: boolean; }): Promise { const resolved = await resolveConferenceRecordQuery(params); const artifacts = await Promise.all( @@ -652,6 +655,7 @@ export async function fetchGoogleMeetAttendance(params: { meeting?: string; conferenceRecord?: string; pageSize?: number; + allConferenceRecords?: boolean; }): Promise { const resolved = await resolveConferenceRecordQuery(params); const nestedRows = await Promise.all(