@openclaw/google-meet 2026.5.28 → 2026.5.30-beta.1
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/{chrome-create-B3zyjf5f.js → chrome-create-By4DuikO.js} +2 -1
- package/dist/{cli-Cc7dWaK8.js → cli-CORe6B8A.js} +20 -11
- package/dist/config-HmaADLv3.js +464 -0
- package/dist/{create-OMWgK9on.js → create-BzkoPzD2.js} +2 -2
- package/dist/index.js +118 -451
- package/dist/{oauth-B3tz8JcD.js → oauth--J53aI66.js} +6 -5
- package/npm-shrinkwrap.json +3 -3
- package/package.json +4 -4
- package/dist/calendar-IxWkFtfn.js +0 -136
package/dist/index.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import { a as isSameMeetUrlForReuse, c as resolveChromeNode, f as endGoogleMeetActiveConference, g as fetchLatestGoogleMeetConferenceRecord, h as fetchGoogleMeetSpace, i as callBrowserProxyOnNode, l as resolveChromeNodeInfo, m as fetchGoogleMeetAttendance, n as isGoogleMeetBrowserManualActionError, o as normalizeMeetUrlForReuse, p as fetchGoogleMeetArtifacts, r as asBrowserTabs, s as readBrowserTab, t as createMeetWithBrowserProxyOnNode, u as buildGoogleMeetPreflightReport } from "./chrome-create-
|
|
2
|
-
import { n as findGoogleMeetCalendarEvent, r as listGoogleMeetCalendarEvents, t as
|
|
1
|
+
import { a as isSameMeetUrlForReuse, c as resolveChromeNode, f as endGoogleMeetActiveConference, g as fetchLatestGoogleMeetConferenceRecord, h as fetchGoogleMeetSpace, i as callBrowserProxyOnNode, l as resolveChromeNodeInfo, m as fetchGoogleMeetAttendance, n as isGoogleMeetBrowserManualActionError, o as normalizeMeetUrlForReuse, p as fetchGoogleMeetArtifacts, r as asBrowserTabs, s as readBrowserTab, t as createMeetWithBrowserProxyOnNode, u as buildGoogleMeetPreflightReport } from "./chrome-create-By4DuikO.js";
|
|
2
|
+
import { a as buildGoogleMeetCalendarDayWindow, i as resolveGoogleMeetGatewayOperationTimeoutMs, n as DEFAULT_GOOGLE_MEET_AUDIO_OUTPUT_COMMAND, o as findGoogleMeetCalendarEvent, r as resolveGoogleMeetConfig, s as listGoogleMeetCalendarEvents, t as DEFAULT_GOOGLE_MEET_AUDIO_INPUT_COMMAND } from "./config-HmaADLv3.js";
|
|
3
3
|
import { optionalPositiveIntegerSchema, readPositiveIntegerParam } from "openclaw/plugin-sdk/channel-actions";
|
|
4
4
|
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
5
5
|
import { ErrorCodes, GatewayClient, callGatewayFromCli, errorShape, startGatewayClientWhenEventLoopReady } from "openclaw/plugin-sdk/gateway-runtime";
|
|
6
6
|
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
|
|
7
|
-
import { asRecord,
|
|
7
|
+
import { asRecord, normalizeOptionalString, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
8
8
|
import { Type } from "typebox";
|
|
9
9
|
import { isBlockedHostnameOrIp } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
10
|
-
import {
|
|
10
|
+
import { addTimerTimeoutGraceMs } from "openclaw/plugin-sdk/number-runtime";
|
|
11
|
+
import { REALTIME_VOICE_AGENT_CONSULT_TOOL_NAME, REALTIME_VOICE_AUDIO_FORMAT_G711_ULAW_8KHZ, REALTIME_VOICE_AUDIO_FORMAT_PCM16_24KHZ, buildRealtimeVoiceAgentConsultWorkingResponse, consultRealtimeVoiceAgent, convertPcmToMulaw8k, createRealtimeVoiceAgentTalkbackQueue, createRealtimeVoiceBridgeSession, createRealtimeVoiceOutputActivityTracker, createTalkSessionController, extendRealtimeVoiceOutputEchoSuppression, getRealtimeVoiceBridgeEventHealth, getRealtimeVoiceTranscriptHealth, isLikelyRealtimeVoiceAssistantEchoTranscript, mulawToPcm, recordRealtimeVoiceBridgeEvent, recordRealtimeVoiceTranscript, recordTalkObservabilityEvent, resamplePcm, resolveConfiguredRealtimeVoiceProvider, resolveRealtimeVoiceAgentConsultTools, resolveRealtimeVoiceAgentConsultToolsAllow } from "openclaw/plugin-sdk/realtime-voice";
|
|
11
12
|
import { spawn, spawnSync } from "node:child_process";
|
|
12
13
|
import { randomUUID } from "node:crypto";
|
|
13
14
|
import { setTimeout as setTimeout$1 } from "node:timers/promises";
|
|
@@ -17,328 +18,6 @@ import os from "node:os";
|
|
|
17
18
|
import path from "node:path";
|
|
18
19
|
import { normalizeAgentId } from "openclaw/plugin-sdk/routing";
|
|
19
20
|
import { getRealtimeTranscriptionProvider, listRealtimeTranscriptionProviders } from "openclaw/plugin-sdk/realtime-transcription";
|
|
20
|
-
//#region extensions/google-meet/src/config.ts
|
|
21
|
-
const SOX_DEFAULT_BUFFER_BYTES = 8192;
|
|
22
|
-
const SOX_MIN_BUFFER_BYTES = 17;
|
|
23
|
-
const DEFAULT_GOOGLE_MEET_AUDIO_BUFFER_BYTES = SOX_DEFAULT_BUFFER_BYTES / 2;
|
|
24
|
-
const PLAIN_DECIMAL_NUMBER_RE = /^\d+(?:\.\d+)?$/;
|
|
25
|
-
function withSoxBuffer(command, bufferBytes) {
|
|
26
|
-
return [
|
|
27
|
-
command[0] ?? "sox",
|
|
28
|
-
"-q",
|
|
29
|
-
"--buffer",
|
|
30
|
-
String(bufferBytes),
|
|
31
|
-
...command.slice(2)
|
|
32
|
-
];
|
|
33
|
-
}
|
|
34
|
-
const DEFAULT_GOOGLE_MEET_AUDIO_INPUT_COMMAND_BASE = [
|
|
35
|
-
"sox",
|
|
36
|
-
"-q",
|
|
37
|
-
"-t",
|
|
38
|
-
"coreaudio",
|
|
39
|
-
"BlackHole 2ch",
|
|
40
|
-
"-t",
|
|
41
|
-
"raw",
|
|
42
|
-
"-r",
|
|
43
|
-
"24000",
|
|
44
|
-
"-c",
|
|
45
|
-
"1",
|
|
46
|
-
"-e",
|
|
47
|
-
"signed-integer",
|
|
48
|
-
"-b",
|
|
49
|
-
"16",
|
|
50
|
-
"-L",
|
|
51
|
-
"-"
|
|
52
|
-
];
|
|
53
|
-
const DEFAULT_GOOGLE_MEET_AUDIO_OUTPUT_COMMAND_BASE = [
|
|
54
|
-
"sox",
|
|
55
|
-
"-q",
|
|
56
|
-
"-t",
|
|
57
|
-
"raw",
|
|
58
|
-
"-r",
|
|
59
|
-
"24000",
|
|
60
|
-
"-c",
|
|
61
|
-
"1",
|
|
62
|
-
"-e",
|
|
63
|
-
"signed-integer",
|
|
64
|
-
"-b",
|
|
65
|
-
"16",
|
|
66
|
-
"-L",
|
|
67
|
-
"-",
|
|
68
|
-
"-t",
|
|
69
|
-
"coreaudio",
|
|
70
|
-
"BlackHole 2ch"
|
|
71
|
-
];
|
|
72
|
-
const LEGACY_GOOGLE_MEET_AUDIO_INPUT_COMMAND_BASE = [
|
|
73
|
-
"rec",
|
|
74
|
-
"-q",
|
|
75
|
-
"-t",
|
|
76
|
-
"raw",
|
|
77
|
-
"-r",
|
|
78
|
-
"8000",
|
|
79
|
-
"-c",
|
|
80
|
-
"1",
|
|
81
|
-
"-e",
|
|
82
|
-
"mu-law",
|
|
83
|
-
"-b",
|
|
84
|
-
"8",
|
|
85
|
-
"-"
|
|
86
|
-
];
|
|
87
|
-
const LEGACY_GOOGLE_MEET_AUDIO_OUTPUT_COMMAND_BASE = [
|
|
88
|
-
"play",
|
|
89
|
-
"-q",
|
|
90
|
-
"-t",
|
|
91
|
-
"raw",
|
|
92
|
-
"-r",
|
|
93
|
-
"8000",
|
|
94
|
-
"-c",
|
|
95
|
-
"1",
|
|
96
|
-
"-e",
|
|
97
|
-
"mu-law",
|
|
98
|
-
"-b",
|
|
99
|
-
"8",
|
|
100
|
-
"-"
|
|
101
|
-
];
|
|
102
|
-
const DEFAULT_GOOGLE_MEET_AUDIO_INPUT_COMMAND = withSoxBuffer(DEFAULT_GOOGLE_MEET_AUDIO_INPUT_COMMAND_BASE, DEFAULT_GOOGLE_MEET_AUDIO_BUFFER_BYTES);
|
|
103
|
-
const DEFAULT_GOOGLE_MEET_AUDIO_OUTPUT_COMMAND = withSoxBuffer(DEFAULT_GOOGLE_MEET_AUDIO_OUTPUT_COMMAND_BASE, DEFAULT_GOOGLE_MEET_AUDIO_BUFFER_BYTES);
|
|
104
|
-
const DEFAULT_GOOGLE_MEET_CHROME_AUDIO_FORMAT = "pcm16-24khz";
|
|
105
|
-
const DEFAULT_GOOGLE_MEET_BARGE_IN_RMS_THRESHOLD = 650;
|
|
106
|
-
const DEFAULT_GOOGLE_MEET_BARGE_IN_PEAK_THRESHOLD = 2500;
|
|
107
|
-
const DEFAULT_GOOGLE_MEET_BARGE_IN_COOLDOWN_MS = 900;
|
|
108
|
-
const DEFAULT_GOOGLE_MEET_REALTIME_INSTRUCTIONS = `You are joining a private Google Meet as an OpenClaw voice transport. Keep spoken replies brief and natural. In agent mode, wait for OpenClaw consult results and speak them exactly. In bidi mode, answer directly and call ${REALTIME_VOICE_AGENT_CONSULT_TOOL_NAME} for deeper reasoning, current information, or tools.`;
|
|
109
|
-
const DEFAULT_GOOGLE_MEET_REALTIME_INTRO_MESSAGE = "Say exactly: I'm here and listening.";
|
|
110
|
-
const DEFAULT_GOOGLE_MEET_CONFIG = {
|
|
111
|
-
enabled: true,
|
|
112
|
-
defaults: {},
|
|
113
|
-
preview: { enrollmentAcknowledged: false },
|
|
114
|
-
defaultTransport: "chrome",
|
|
115
|
-
defaultMode: "agent",
|
|
116
|
-
chrome: {
|
|
117
|
-
audioBackend: "blackhole-2ch",
|
|
118
|
-
audioFormat: DEFAULT_GOOGLE_MEET_CHROME_AUDIO_FORMAT,
|
|
119
|
-
audioBufferBytes: DEFAULT_GOOGLE_MEET_AUDIO_BUFFER_BYTES,
|
|
120
|
-
launch: true,
|
|
121
|
-
guestName: "OpenClaw Agent",
|
|
122
|
-
reuseExistingTab: true,
|
|
123
|
-
autoJoin: true,
|
|
124
|
-
joinTimeoutMs: 3e4,
|
|
125
|
-
waitForInCallMs: 2e4,
|
|
126
|
-
audioInputCommand: [...DEFAULT_GOOGLE_MEET_AUDIO_INPUT_COMMAND],
|
|
127
|
-
audioOutputCommand: [...DEFAULT_GOOGLE_MEET_AUDIO_OUTPUT_COMMAND],
|
|
128
|
-
bargeInRmsThreshold: DEFAULT_GOOGLE_MEET_BARGE_IN_RMS_THRESHOLD,
|
|
129
|
-
bargeInPeakThreshold: DEFAULT_GOOGLE_MEET_BARGE_IN_PEAK_THRESHOLD,
|
|
130
|
-
bargeInCooldownMs: DEFAULT_GOOGLE_MEET_BARGE_IN_COOLDOWN_MS
|
|
131
|
-
},
|
|
132
|
-
chromeNode: {},
|
|
133
|
-
twilio: {},
|
|
134
|
-
voiceCall: {
|
|
135
|
-
enabled: true,
|
|
136
|
-
requestTimeoutMs: 3e4,
|
|
137
|
-
dtmfDelayMs: 12e3,
|
|
138
|
-
postDtmfSpeechDelayMs: 5e3
|
|
139
|
-
},
|
|
140
|
-
realtime: {
|
|
141
|
-
strategy: "agent",
|
|
142
|
-
provider: "openai",
|
|
143
|
-
transcriptionProvider: "openai",
|
|
144
|
-
instructions: DEFAULT_GOOGLE_MEET_REALTIME_INSTRUCTIONS,
|
|
145
|
-
introMessage: DEFAULT_GOOGLE_MEET_REALTIME_INTRO_MESSAGE,
|
|
146
|
-
toolPolicy: "safe-read-only",
|
|
147
|
-
providers: {}
|
|
148
|
-
},
|
|
149
|
-
oauth: {},
|
|
150
|
-
auth: { provider: "google-oauth" }
|
|
151
|
-
};
|
|
152
|
-
const GOOGLE_MEET_CLIENT_ID_KEYS = ["OPENCLAW_GOOGLE_MEET_CLIENT_ID", "GOOGLE_MEET_CLIENT_ID"];
|
|
153
|
-
const GOOGLE_MEET_CLIENT_SECRET_KEYS = ["OPENCLAW_GOOGLE_MEET_CLIENT_SECRET", "GOOGLE_MEET_CLIENT_SECRET"];
|
|
154
|
-
const GOOGLE_MEET_REFRESH_TOKEN_KEYS = ["OPENCLAW_GOOGLE_MEET_REFRESH_TOKEN", "GOOGLE_MEET_REFRESH_TOKEN"];
|
|
155
|
-
const GOOGLE_MEET_ACCESS_TOKEN_KEYS = ["OPENCLAW_GOOGLE_MEET_ACCESS_TOKEN", "GOOGLE_MEET_ACCESS_TOKEN"];
|
|
156
|
-
const GOOGLE_MEET_ACCESS_TOKEN_EXPIRES_AT_KEYS = ["OPENCLAW_GOOGLE_MEET_ACCESS_TOKEN_EXPIRES_AT", "GOOGLE_MEET_ACCESS_TOKEN_EXPIRES_AT"];
|
|
157
|
-
const GOOGLE_MEET_DEFAULT_MEETING_KEYS = ["OPENCLAW_GOOGLE_MEET_DEFAULT_MEETING", "GOOGLE_MEET_DEFAULT_MEETING"];
|
|
158
|
-
const GOOGLE_MEET_PREVIEW_ACK_KEYS = ["OPENCLAW_GOOGLE_MEET_PREVIEW_ACK", "GOOGLE_MEET_PREVIEW_ACK"];
|
|
159
|
-
function resolveBoolean(value, fallback) {
|
|
160
|
-
return typeof value === "boolean" ? value : fallback;
|
|
161
|
-
}
|
|
162
|
-
function resolveNumber(value, fallback) {
|
|
163
|
-
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : fallback;
|
|
164
|
-
}
|
|
165
|
-
function resolveOptionalNumber(value) {
|
|
166
|
-
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
167
|
-
if (typeof value === "string" && value.trim()) {
|
|
168
|
-
const trimmed = value.trim();
|
|
169
|
-
const parsed = PLAIN_DECIMAL_NUMBER_RE.test(trimmed) ? Number(trimmed) : NaN;
|
|
170
|
-
return Number.isFinite(parsed) ? parsed : void 0;
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
function readEnvString(env, keys) {
|
|
174
|
-
for (const key of keys) {
|
|
175
|
-
const value = normalizeOptionalString(env[key]);
|
|
176
|
-
if (value) return value;
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
function normalizeStringAllowEmpty(value) {
|
|
180
|
-
return typeof value === "string" ? value.trim() : void 0;
|
|
181
|
-
}
|
|
182
|
-
function readEnvBoolean(env, keys) {
|
|
183
|
-
const normalized = normalizeOptionalLowercaseString(readEnvString(env, keys));
|
|
184
|
-
if (!normalized) return;
|
|
185
|
-
if ([
|
|
186
|
-
"1",
|
|
187
|
-
"true",
|
|
188
|
-
"yes",
|
|
189
|
-
"on"
|
|
190
|
-
].includes(normalized)) return true;
|
|
191
|
-
if ([
|
|
192
|
-
"0",
|
|
193
|
-
"false",
|
|
194
|
-
"no",
|
|
195
|
-
"off"
|
|
196
|
-
].includes(normalized)) return false;
|
|
197
|
-
}
|
|
198
|
-
function readEnvNumber(env, keys) {
|
|
199
|
-
return resolveOptionalNumber(readEnvString(env, keys));
|
|
200
|
-
}
|
|
201
|
-
function resolveStringArray(value) {
|
|
202
|
-
return normalizeOptionalTrimmedStringList(value);
|
|
203
|
-
}
|
|
204
|
-
function resolveProvidersConfig(value) {
|
|
205
|
-
const raw = asRecord(value);
|
|
206
|
-
const providers = {};
|
|
207
|
-
for (const [key, entry] of Object.entries(raw)) {
|
|
208
|
-
const providerId = normalizeOptionalLowercaseString(key);
|
|
209
|
-
if (!providerId) continue;
|
|
210
|
-
providers[providerId] = asRecord(entry);
|
|
211
|
-
}
|
|
212
|
-
return providers;
|
|
213
|
-
}
|
|
214
|
-
function resolveTransport$1(value, fallback) {
|
|
215
|
-
const normalized = normalizeOptionalLowercaseString(value);
|
|
216
|
-
return normalized === "chrome" || normalized === "chrome-node" || normalized === "twilio" ? normalized : fallback;
|
|
217
|
-
}
|
|
218
|
-
function resolveMode$1(value, fallback) {
|
|
219
|
-
const normalized = normalizeOptionalLowercaseString(value);
|
|
220
|
-
if (normalized === "realtime") return "agent";
|
|
221
|
-
return normalized === "agent" || normalized === "bidi" || normalized === "transcribe" ? normalized : fallback;
|
|
222
|
-
}
|
|
223
|
-
function resolveRealtimeStrategy(value, fallback) {
|
|
224
|
-
const normalized = normalizeOptionalLowercaseString(value);
|
|
225
|
-
return normalized === "agent" || normalized === "bidi" ? normalized : fallback;
|
|
226
|
-
}
|
|
227
|
-
function resolveChromeAudioFormat(value) {
|
|
228
|
-
switch (normalizeOptionalString(value)?.toLowerCase().replaceAll("_", "-")) {
|
|
229
|
-
case "pcm16-24khz":
|
|
230
|
-
case "pcm16-24k":
|
|
231
|
-
case "pcm24":
|
|
232
|
-
case "pcm": return "pcm16-24khz";
|
|
233
|
-
case "g711-ulaw-8khz":
|
|
234
|
-
case "g711-ulaw-8k":
|
|
235
|
-
case "g711-ulaw":
|
|
236
|
-
case "mulaw":
|
|
237
|
-
case "mu-law": return "g711-ulaw-8khz";
|
|
238
|
-
default: return;
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
function resolveAudioBufferBytes(value, fallback) {
|
|
242
|
-
const number = resolveNumber(value, fallback);
|
|
243
|
-
if (!Number.isFinite(number) || number <= 0) return fallback;
|
|
244
|
-
return Math.max(SOX_MIN_BUFFER_BYTES, Math.trunc(number));
|
|
245
|
-
}
|
|
246
|
-
function defaultAudioInputCommand(format, bufferBytes) {
|
|
247
|
-
return withSoxBuffer(format === "g711-ulaw-8khz" ? LEGACY_GOOGLE_MEET_AUDIO_INPUT_COMMAND_BASE : DEFAULT_GOOGLE_MEET_AUDIO_INPUT_COMMAND_BASE, bufferBytes);
|
|
248
|
-
}
|
|
249
|
-
function defaultAudioOutputCommand(format, bufferBytes) {
|
|
250
|
-
return withSoxBuffer(format === "g711-ulaw-8khz" ? LEGACY_GOOGLE_MEET_AUDIO_OUTPUT_COMMAND_BASE : DEFAULT_GOOGLE_MEET_AUDIO_OUTPUT_COMMAND_BASE, bufferBytes);
|
|
251
|
-
}
|
|
252
|
-
function resolveGoogleMeetConfig(input) {
|
|
253
|
-
return resolveGoogleMeetConfigWithEnv(input);
|
|
254
|
-
}
|
|
255
|
-
function resolveGoogleMeetConfigWithEnv(input, env = process.env) {
|
|
256
|
-
const raw = asRecord(input);
|
|
257
|
-
const defaults = asRecord(raw.defaults);
|
|
258
|
-
const preview = asRecord(raw.preview);
|
|
259
|
-
const chrome = asRecord(raw.chrome);
|
|
260
|
-
const configuredAudioInputCommand = resolveStringArray(chrome.audioInputCommand);
|
|
261
|
-
const configuredAudioOutputCommand = resolveStringArray(chrome.audioOutputCommand);
|
|
262
|
-
const hasCustomAudioCommand = configuredAudioInputCommand !== void 0 || configuredAudioOutputCommand !== void 0;
|
|
263
|
-
const audioFormat = resolveChromeAudioFormat(chrome.audioFormat) ?? (hasCustomAudioCommand ? "g711-ulaw-8khz" : DEFAULT_GOOGLE_MEET_CONFIG.chrome.audioFormat);
|
|
264
|
-
const audioBufferBytes = resolveAudioBufferBytes(chrome.audioBufferBytes, DEFAULT_GOOGLE_MEET_CONFIG.chrome.audioBufferBytes);
|
|
265
|
-
const chromeNode = asRecord(raw.chromeNode);
|
|
266
|
-
const twilio = asRecord(raw.twilio);
|
|
267
|
-
const voiceCall = asRecord(raw.voiceCall);
|
|
268
|
-
const realtime = asRecord(raw.realtime);
|
|
269
|
-
const realtimeProvider = normalizeOptionalString(realtime.provider);
|
|
270
|
-
const resolvedRealtimeProvider = realtimeProvider ?? DEFAULT_GOOGLE_MEET_CONFIG.realtime.provider;
|
|
271
|
-
const oauth = asRecord(raw.oauth);
|
|
272
|
-
const auth = asRecord(raw.auth);
|
|
273
|
-
return {
|
|
274
|
-
enabled: resolveBoolean(raw.enabled, DEFAULT_GOOGLE_MEET_CONFIG.enabled),
|
|
275
|
-
defaults: { meeting: normalizeOptionalString(defaults.meeting) ?? readEnvString(env, GOOGLE_MEET_DEFAULT_MEETING_KEYS) },
|
|
276
|
-
preview: { enrollmentAcknowledged: resolveBoolean(preview.enrollmentAcknowledged, readEnvBoolean(env, GOOGLE_MEET_PREVIEW_ACK_KEYS) ?? DEFAULT_GOOGLE_MEET_CONFIG.preview.enrollmentAcknowledged) },
|
|
277
|
-
defaultTransport: resolveTransport$1(raw.defaultTransport, DEFAULT_GOOGLE_MEET_CONFIG.defaultTransport),
|
|
278
|
-
defaultMode: resolveMode$1(raw.defaultMode, DEFAULT_GOOGLE_MEET_CONFIG.defaultMode),
|
|
279
|
-
chrome: {
|
|
280
|
-
audioBackend: "blackhole-2ch",
|
|
281
|
-
audioFormat,
|
|
282
|
-
audioBufferBytes,
|
|
283
|
-
launch: resolveBoolean(chrome.launch, DEFAULT_GOOGLE_MEET_CONFIG.chrome.launch),
|
|
284
|
-
browserProfile: normalizeOptionalString(chrome.browserProfile),
|
|
285
|
-
guestName: normalizeOptionalString(chrome.guestName) ?? DEFAULT_GOOGLE_MEET_CONFIG.chrome.guestName,
|
|
286
|
-
reuseExistingTab: resolveBoolean(chrome.reuseExistingTab, DEFAULT_GOOGLE_MEET_CONFIG.chrome.reuseExistingTab),
|
|
287
|
-
autoJoin: resolveBoolean(chrome.autoJoin, DEFAULT_GOOGLE_MEET_CONFIG.chrome.autoJoin),
|
|
288
|
-
joinTimeoutMs: resolveNumber(chrome.joinTimeoutMs, DEFAULT_GOOGLE_MEET_CONFIG.chrome.joinTimeoutMs),
|
|
289
|
-
waitForInCallMs: resolveNumber(chrome.waitForInCallMs, DEFAULT_GOOGLE_MEET_CONFIG.chrome.waitForInCallMs),
|
|
290
|
-
audioInputCommand: configuredAudioInputCommand ?? defaultAudioInputCommand(audioFormat, audioBufferBytes),
|
|
291
|
-
audioOutputCommand: configuredAudioOutputCommand ?? defaultAudioOutputCommand(audioFormat, audioBufferBytes),
|
|
292
|
-
bargeInInputCommand: resolveStringArray(chrome.bargeInInputCommand),
|
|
293
|
-
bargeInRmsThreshold: resolveNumber(chrome.bargeInRmsThreshold, DEFAULT_GOOGLE_MEET_CONFIG.chrome.bargeInRmsThreshold),
|
|
294
|
-
bargeInPeakThreshold: resolveNumber(chrome.bargeInPeakThreshold, DEFAULT_GOOGLE_MEET_CONFIG.chrome.bargeInPeakThreshold),
|
|
295
|
-
bargeInCooldownMs: resolveNumber(chrome.bargeInCooldownMs, DEFAULT_GOOGLE_MEET_CONFIG.chrome.bargeInCooldownMs),
|
|
296
|
-
audioBridgeCommand: resolveStringArray(chrome.audioBridgeCommand),
|
|
297
|
-
audioBridgeHealthCommand: resolveStringArray(chrome.audioBridgeHealthCommand)
|
|
298
|
-
},
|
|
299
|
-
chromeNode: { node: normalizeOptionalString(chromeNode.node) },
|
|
300
|
-
twilio: {
|
|
301
|
-
defaultDialInNumber: normalizeOptionalString(twilio.defaultDialInNumber),
|
|
302
|
-
defaultPin: normalizeOptionalString(twilio.defaultPin),
|
|
303
|
-
defaultDtmfSequence: normalizeOptionalString(twilio.defaultDtmfSequence)
|
|
304
|
-
},
|
|
305
|
-
voiceCall: {
|
|
306
|
-
enabled: resolveBoolean(voiceCall.enabled, DEFAULT_GOOGLE_MEET_CONFIG.voiceCall.enabled),
|
|
307
|
-
gatewayUrl: normalizeOptionalString(voiceCall.gatewayUrl),
|
|
308
|
-
token: normalizeOptionalString(voiceCall.token),
|
|
309
|
-
requestTimeoutMs: resolveNumber(voiceCall.requestTimeoutMs, DEFAULT_GOOGLE_MEET_CONFIG.voiceCall.requestTimeoutMs),
|
|
310
|
-
dtmfDelayMs: resolveNumber(voiceCall.dtmfDelayMs, DEFAULT_GOOGLE_MEET_CONFIG.voiceCall.dtmfDelayMs),
|
|
311
|
-
postDtmfSpeechDelayMs: resolveNumber(voiceCall.postDtmfSpeechDelayMs, DEFAULT_GOOGLE_MEET_CONFIG.voiceCall.postDtmfSpeechDelayMs),
|
|
312
|
-
introMessage: normalizeOptionalString(voiceCall.introMessage)
|
|
313
|
-
},
|
|
314
|
-
realtime: {
|
|
315
|
-
strategy: resolveRealtimeStrategy(realtime.strategy, DEFAULT_GOOGLE_MEET_CONFIG.realtime.strategy),
|
|
316
|
-
provider: resolvedRealtimeProvider,
|
|
317
|
-
transcriptionProvider: normalizeOptionalString(realtime.transcriptionProvider) ?? (realtimeProvider && realtimeProvider !== "google" ? resolvedRealtimeProvider : DEFAULT_GOOGLE_MEET_CONFIG.realtime.transcriptionProvider),
|
|
318
|
-
voiceProvider: normalizeOptionalString(realtime.voiceProvider),
|
|
319
|
-
model: normalizeOptionalString(realtime.model) ?? DEFAULT_GOOGLE_MEET_CONFIG.realtime.model,
|
|
320
|
-
instructions: normalizeOptionalString(realtime.instructions) ?? DEFAULT_GOOGLE_MEET_CONFIG.realtime.instructions,
|
|
321
|
-
introMessage: normalizeStringAllowEmpty(realtime.introMessage) ?? DEFAULT_GOOGLE_MEET_CONFIG.realtime.introMessage,
|
|
322
|
-
agentId: normalizeOptionalString(realtime.agentId),
|
|
323
|
-
toolPolicy: resolveRealtimeVoiceAgentConsultToolPolicy(realtime.toolPolicy, DEFAULT_GOOGLE_MEET_CONFIG.realtime.toolPolicy),
|
|
324
|
-
providers: resolveProvidersConfig(realtime.providers)
|
|
325
|
-
},
|
|
326
|
-
oauth: {
|
|
327
|
-
clientId: normalizeOptionalString(oauth.clientId) ?? normalizeOptionalString(auth.clientId) ?? readEnvString(env, GOOGLE_MEET_CLIENT_ID_KEYS),
|
|
328
|
-
clientSecret: normalizeOptionalString(oauth.clientSecret) ?? normalizeOptionalString(auth.clientSecret) ?? readEnvString(env, GOOGLE_MEET_CLIENT_SECRET_KEYS),
|
|
329
|
-
refreshToken: normalizeOptionalString(oauth.refreshToken) ?? readEnvString(env, GOOGLE_MEET_REFRESH_TOKEN_KEYS),
|
|
330
|
-
accessToken: normalizeOptionalString(oauth.accessToken) ?? readEnvString(env, GOOGLE_MEET_ACCESS_TOKEN_KEYS),
|
|
331
|
-
expiresAt: resolveOptionalNumber(oauth.expiresAt) ?? readEnvNumber(env, GOOGLE_MEET_ACCESS_TOKEN_EXPIRES_AT_KEYS)
|
|
332
|
-
},
|
|
333
|
-
auth: {
|
|
334
|
-
provider: "google-oauth",
|
|
335
|
-
clientId: normalizeOptionalString(auth.clientId),
|
|
336
|
-
clientSecret: normalizeOptionalString(auth.clientSecret),
|
|
337
|
-
tokenPath: normalizeOptionalString(auth.tokenPath)
|
|
338
|
-
}
|
|
339
|
-
};
|
|
340
|
-
}
|
|
341
|
-
//#endregion
|
|
342
21
|
//#region extensions/google-meet/src/transports/chrome-audio-device.ts
|
|
343
22
|
const GOOGLE_MEET_SYSTEM_PROFILER_COMMAND = "/usr/sbin/system_profiler";
|
|
344
23
|
function outputMentionsBlackHole2ch(output) {
|
|
@@ -1930,20 +1609,73 @@ function normalizeGoogleMeetTtsPromptText(text) {
|
|
|
1930
1609
|
if (sayExactly) return sayExactly.replace(/^["']|["']$/g, "").trim() || trimmed;
|
|
1931
1610
|
return trimmed;
|
|
1932
1611
|
}
|
|
1612
|
+
function startGoogleMeetNodeAudioInputLoop(params) {
|
|
1613
|
+
let lastInputAt;
|
|
1614
|
+
let lastInputBytes = 0;
|
|
1615
|
+
let suppressedInputBytes = 0;
|
|
1616
|
+
let lastSuppressedInputAt;
|
|
1617
|
+
let consecutiveInputErrors = 0;
|
|
1618
|
+
let lastInputError;
|
|
1619
|
+
(async () => {
|
|
1620
|
+
for (;;) {
|
|
1621
|
+
if (params.isStopped()) break;
|
|
1622
|
+
try {
|
|
1623
|
+
const raw = await params.runtime.nodes.invoke({
|
|
1624
|
+
nodeId: params.nodeId,
|
|
1625
|
+
command: "googlemeet.chrome",
|
|
1626
|
+
params: {
|
|
1627
|
+
action: "pullAudio",
|
|
1628
|
+
bridgeId: params.bridgeId,
|
|
1629
|
+
timeoutMs: 250
|
|
1630
|
+
},
|
|
1631
|
+
timeoutMs: 2e3
|
|
1632
|
+
});
|
|
1633
|
+
const result = asRecord$1(asRecord$1(raw).payload ?? raw);
|
|
1634
|
+
consecutiveInputErrors = 0;
|
|
1635
|
+
lastInputError = void 0;
|
|
1636
|
+
const base64 = readString(result.base64);
|
|
1637
|
+
if (base64) {
|
|
1638
|
+
const audio = Buffer.from(base64, "base64");
|
|
1639
|
+
if (params.isInputSuppressed()) {
|
|
1640
|
+
lastSuppressedInputAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1641
|
+
suppressedInputBytes += audio.byteLength;
|
|
1642
|
+
continue;
|
|
1643
|
+
}
|
|
1644
|
+
lastInputAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1645
|
+
lastInputBytes += audio.byteLength;
|
|
1646
|
+
params.onAudio(audio);
|
|
1647
|
+
}
|
|
1648
|
+
if (result.closed === true) await params.stop();
|
|
1649
|
+
} catch (error) {
|
|
1650
|
+
if (!params.isStopped()) {
|
|
1651
|
+
const message = formatErrorMessage(error);
|
|
1652
|
+
consecutiveInputErrors += 1;
|
|
1653
|
+
lastInputError = message;
|
|
1654
|
+
params.logger.warn(`[google-meet] ${params.logPrefix} audio input failed (${consecutiveInputErrors}/5): ${message}`);
|
|
1655
|
+
if (consecutiveInputErrors >= 5 || /unknown bridgeId|bridge is not open/i.test(message)) await params.stop();
|
|
1656
|
+
else await new Promise((resolve) => setTimeout(resolve, 250));
|
|
1657
|
+
}
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1660
|
+
})();
|
|
1661
|
+
return { getHealth: () => ({
|
|
1662
|
+
audioInputActive: lastInputBytes > 0,
|
|
1663
|
+
lastInputAt,
|
|
1664
|
+
lastSuppressedInputAt,
|
|
1665
|
+
lastInputBytes,
|
|
1666
|
+
suppressedInputBytes,
|
|
1667
|
+
consecutiveInputErrors,
|
|
1668
|
+
lastInputError
|
|
1669
|
+
}) };
|
|
1670
|
+
}
|
|
1933
1671
|
async function startNodeAgentAudioBridge(params) {
|
|
1934
1672
|
let stopped = false;
|
|
1935
1673
|
let sttSession = null;
|
|
1936
1674
|
let realtimeReady = false;
|
|
1937
|
-
let lastInputAt;
|
|
1938
1675
|
let lastOutputAt;
|
|
1939
|
-
let lastInputBytes = 0;
|
|
1940
1676
|
const outputActivity = createRealtimeVoiceOutputActivityTracker();
|
|
1941
|
-
let suppressedInputBytes = 0;
|
|
1942
|
-
let lastSuppressedInputAt;
|
|
1943
1677
|
let suppressInputUntil = 0;
|
|
1944
1678
|
let lastOutputPlayableUntilMs = 0;
|
|
1945
|
-
let consecutiveInputErrors = 0;
|
|
1946
|
-
let lastInputError;
|
|
1947
1679
|
const resolved = resolveGoogleMeetRealtimeTranscriptionProvider({
|
|
1948
1680
|
config: params.config,
|
|
1949
1681
|
fullConfig: params.fullConfig,
|
|
@@ -2067,48 +1799,19 @@ async function startNodeAgentAudioBridge(params) {
|
|
|
2067
1799
|
});
|
|
2068
1800
|
await sttSession.connect();
|
|
2069
1801
|
realtimeReady = true;
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
},
|
|
2082
|
-
timeoutMs: 2e3
|
|
2083
|
-
});
|
|
2084
|
-
const result = asRecord$1(asRecord$1(raw).payload ?? raw);
|
|
2085
|
-
consecutiveInputErrors = 0;
|
|
2086
|
-
lastInputError = void 0;
|
|
2087
|
-
const base64 = readString(result.base64);
|
|
2088
|
-
if (base64) {
|
|
2089
|
-
const audio = Buffer.from(base64, "base64");
|
|
2090
|
-
if (Date.now() < suppressInputUntil) {
|
|
2091
|
-
lastSuppressedInputAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2092
|
-
suppressedInputBytes += audio.byteLength;
|
|
2093
|
-
continue;
|
|
2094
|
-
}
|
|
2095
|
-
lastInputAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2096
|
-
lastInputBytes += audio.byteLength;
|
|
2097
|
-
sttSession?.sendAudio(convertGoogleMeetBridgeAudioForStt(audio, params.config));
|
|
2098
|
-
}
|
|
2099
|
-
if (result.closed === true) await stop();
|
|
2100
|
-
} catch (error) {
|
|
2101
|
-
if (!stopped) {
|
|
2102
|
-
const message = formatErrorMessage(error);
|
|
2103
|
-
consecutiveInputErrors += 1;
|
|
2104
|
-
lastInputError = message;
|
|
2105
|
-
params.logger.warn(`[google-meet] node agent audio input failed (${consecutiveInputErrors}/5): ${message}`);
|
|
2106
|
-
if (consecutiveInputErrors >= 5 || /unknown bridgeId|bridge is not open/i.test(message)) await stop();
|
|
2107
|
-
else await new Promise((resolve) => setTimeout(resolve, 250));
|
|
2108
|
-
}
|
|
2109
|
-
}
|
|
1802
|
+
const audioInputLoop = startGoogleMeetNodeAudioInputLoop({
|
|
1803
|
+
runtime: params.runtime,
|
|
1804
|
+
nodeId: params.nodeId,
|
|
1805
|
+
bridgeId: params.bridgeId,
|
|
1806
|
+
logger: params.logger,
|
|
1807
|
+
logPrefix: "node agent",
|
|
1808
|
+
isStopped: () => stopped,
|
|
1809
|
+
stop,
|
|
1810
|
+
isInputSuppressed: () => Date.now() < suppressInputUntil,
|
|
1811
|
+
onAudio: (audio) => {
|
|
1812
|
+
sttSession?.sendAudio(convertGoogleMeetBridgeAudioForStt(audio, params.config));
|
|
2110
1813
|
}
|
|
2111
|
-
})
|
|
1814
|
+
});
|
|
2112
1815
|
return {
|
|
2113
1816
|
type: "node-command-pair",
|
|
2114
1817
|
providerId: resolved.provider.id,
|
|
@@ -2118,17 +1821,11 @@ async function startNodeAgentAudioBridge(params) {
|
|
|
2118
1821
|
getHealth: () => ({
|
|
2119
1822
|
providerConnected: sttSession?.isConnected() ?? false,
|
|
2120
1823
|
realtimeReady,
|
|
2121
|
-
|
|
1824
|
+
...audioInputLoop.getHealth(),
|
|
2122
1825
|
audioOutputActive: outputActivity.isActive(),
|
|
2123
|
-
lastInputAt,
|
|
2124
1826
|
lastOutputAt,
|
|
2125
|
-
lastSuppressedInputAt,
|
|
2126
|
-
lastInputBytes,
|
|
2127
1827
|
lastOutputBytes: outputActivity.snapshot().sinkAudioBytes,
|
|
2128
|
-
suppressedInputBytes,
|
|
2129
1828
|
...getGoogleMeetRealtimeTranscriptHealth(transcript),
|
|
2130
|
-
consecutiveInputErrors,
|
|
2131
|
-
lastInputError,
|
|
2132
1829
|
bridgeClosed: stopped
|
|
2133
1830
|
}),
|
|
2134
1831
|
stop
|
|
@@ -2138,17 +1835,11 @@ async function startNodeRealtimeAudioBridge(params) {
|
|
|
2138
1835
|
let stopped = false;
|
|
2139
1836
|
let bridge = null;
|
|
2140
1837
|
let realtimeReady = false;
|
|
2141
|
-
let lastInputAt;
|
|
2142
1838
|
let lastOutputAt;
|
|
2143
1839
|
let lastClearAt;
|
|
2144
|
-
let lastInputBytes = 0;
|
|
2145
1840
|
const outputActivity = createRealtimeVoiceOutputActivityTracker();
|
|
2146
|
-
let suppressedInputBytes = 0;
|
|
2147
|
-
let lastSuppressedInputAt;
|
|
2148
1841
|
let suppressInputUntil = 0;
|
|
2149
1842
|
let lastOutputPlayableUntilMs = 0;
|
|
2150
|
-
let consecutiveInputErrors = 0;
|
|
2151
|
-
let lastInputError;
|
|
2152
1843
|
let clearCount = 0;
|
|
2153
1844
|
const resolved = resolveGoogleMeetRealtimeProvider({
|
|
2154
1845
|
config: params.config,
|
|
@@ -2442,53 +2133,24 @@ async function startNodeRealtimeAudioBridge(params) {
|
|
|
2442
2133
|
}
|
|
2443
2134
|
});
|
|
2444
2135
|
await bridge.connect();
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
}
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
lastInputError = void 0;
|
|
2462
|
-
const base64 = readString(result.base64);
|
|
2463
|
-
if (base64) {
|
|
2464
|
-
const audio = Buffer.from(base64, "base64");
|
|
2465
|
-
if (Date.now() < suppressInputUntil) {
|
|
2466
|
-
lastSuppressedInputAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2467
|
-
suppressedInputBytes += audio.byteLength;
|
|
2468
|
-
continue;
|
|
2469
|
-
}
|
|
2470
|
-
lastInputAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2471
|
-
lastInputBytes += audio.byteLength;
|
|
2472
|
-
emitTalkEvent({
|
|
2473
|
-
type: "input.audio.delta",
|
|
2474
|
-
turnId: ensureTalkTurn(),
|
|
2475
|
-
payload: { byteLength: audio.byteLength }
|
|
2476
|
-
});
|
|
2477
|
-
bridge?.sendAudio(audio);
|
|
2478
|
-
}
|
|
2479
|
-
if (result.closed === true) await stop();
|
|
2480
|
-
} catch (error) {
|
|
2481
|
-
if (!stopped) {
|
|
2482
|
-
const message = formatErrorMessage(error);
|
|
2483
|
-
consecutiveInputErrors += 1;
|
|
2484
|
-
lastInputError = message;
|
|
2485
|
-
params.logger.warn(`[google-meet] node audio input failed (${consecutiveInputErrors}/5): ${message}`);
|
|
2486
|
-
if (consecutiveInputErrors >= 5 || /unknown bridgeId|bridge is not open/i.test(message)) await stop();
|
|
2487
|
-
else await new Promise((resolve) => setTimeout(resolve, 250));
|
|
2488
|
-
}
|
|
2489
|
-
}
|
|
2136
|
+
const audioInputLoop = startGoogleMeetNodeAudioInputLoop({
|
|
2137
|
+
runtime: params.runtime,
|
|
2138
|
+
nodeId: params.nodeId,
|
|
2139
|
+
bridgeId: params.bridgeId,
|
|
2140
|
+
logger: params.logger,
|
|
2141
|
+
logPrefix: "node",
|
|
2142
|
+
isStopped: () => stopped,
|
|
2143
|
+
stop,
|
|
2144
|
+
isInputSuppressed: () => Date.now() < suppressInputUntil,
|
|
2145
|
+
onAudio: (audio) => {
|
|
2146
|
+
emitTalkEvent({
|
|
2147
|
+
type: "input.audio.delta",
|
|
2148
|
+
turnId: ensureTalkTurn(),
|
|
2149
|
+
payload: { byteLength: audio.byteLength }
|
|
2150
|
+
});
|
|
2151
|
+
bridge?.sendAudio(audio);
|
|
2490
2152
|
}
|
|
2491
|
-
})
|
|
2153
|
+
});
|
|
2492
2154
|
return {
|
|
2493
2155
|
type: "node-command-pair",
|
|
2494
2156
|
providerId: resolved.provider.id,
|
|
@@ -2500,20 +2162,14 @@ async function startNodeRealtimeAudioBridge(params) {
|
|
|
2500
2162
|
getHealth: () => ({
|
|
2501
2163
|
providerConnected: bridge?.bridge.isConnected() ?? false,
|
|
2502
2164
|
realtimeReady,
|
|
2503
|
-
|
|
2165
|
+
...audioInputLoop.getHealth(),
|
|
2504
2166
|
audioOutputActive: outputActivity.isActive(),
|
|
2505
|
-
lastInputAt,
|
|
2506
2167
|
lastOutputAt,
|
|
2507
|
-
lastSuppressedInputAt,
|
|
2508
2168
|
lastClearAt,
|
|
2509
|
-
lastInputBytes,
|
|
2510
2169
|
lastOutputBytes: outputActivity.snapshot().sinkAudioBytes,
|
|
2511
|
-
suppressedInputBytes,
|
|
2512
2170
|
...getGoogleMeetRealtimeTranscriptHealth(transcript),
|
|
2513
2171
|
...getGoogleMeetRealtimeEventHealth(realtimeEvents),
|
|
2514
2172
|
recentTalkEvents: summarizeGoogleMeetTalkEvents(recentTalkEvents),
|
|
2515
|
-
consecutiveInputErrors,
|
|
2516
|
-
lastInputError,
|
|
2517
2173
|
clearCount,
|
|
2518
2174
|
bridgeClosed: stopped
|
|
2519
2175
|
}),
|
|
@@ -2650,7 +2306,7 @@ function parseMeetBrowserStatus(result) {
|
|
|
2650
2306
|
async function callLocalBrowserRequest(params) {
|
|
2651
2307
|
return await chromeTransportDeps.callGatewayFromCli("browser.request", {
|
|
2652
2308
|
json: true,
|
|
2653
|
-
timeout: String(params.timeoutMs
|
|
2309
|
+
timeout: String(resolveBrowserGatewayTimeoutMs(params.timeoutMs))
|
|
2654
2310
|
}, {
|
|
2655
2311
|
method: params.method,
|
|
2656
2312
|
path: params.path,
|
|
@@ -2658,6 +2314,9 @@ async function callLocalBrowserRequest(params) {
|
|
|
2658
2314
|
timeoutMs: params.timeoutMs
|
|
2659
2315
|
}, { progress: false });
|
|
2660
2316
|
}
|
|
2317
|
+
function resolveBrowserGatewayTimeoutMs(timeoutMs) {
|
|
2318
|
+
return addTimerTimeoutGraceMs(timeoutMs) ?? 1;
|
|
2319
|
+
}
|
|
2661
2320
|
function mergeBrowserNotes(browser, notes) {
|
|
2662
2321
|
if (!browser || notes.length === 0) return browser;
|
|
2663
2322
|
return {
|
|
@@ -3214,7 +2873,7 @@ async function launchChromeMeetOnNode(params) {
|
|
|
3214
2873
|
audioBridgeCommand: params.config.chrome.audioBridgeCommand,
|
|
3215
2874
|
audioBridgeHealthCommand: params.config.chrome.audioBridgeHealthCommand
|
|
3216
2875
|
},
|
|
3217
|
-
timeoutMs: params.config.chrome.joinTimeoutMs
|
|
2876
|
+
timeoutMs: addTimerTimeoutGraceMs(params.config.chrome.joinTimeoutMs) ?? 1
|
|
3218
2877
|
}));
|
|
3219
2878
|
if (result.audioBridge?.type === "node-command-pair") {
|
|
3220
2879
|
if (!result.bridgeId) throw new Error("Google Meet node did not return an audio bridge id.");
|
|
@@ -4082,6 +3741,16 @@ var GoogleMeetRuntime = class {
|
|
|
4082
3741
|
};
|
|
4083
3742
|
//#endregion
|
|
4084
3743
|
//#region extensions/google-meet/index.ts
|
|
3744
|
+
let googleMeetCreateModulePromise = null;
|
|
3745
|
+
let googleMeetCliModulePromise = null;
|
|
3746
|
+
const loadGoogleMeetCreateModule = async () => {
|
|
3747
|
+
googleMeetCreateModulePromise ??= import("./create-BzkoPzD2.js");
|
|
3748
|
+
return await googleMeetCreateModulePromise;
|
|
3749
|
+
};
|
|
3750
|
+
const loadGoogleMeetCliModule = async () => {
|
|
3751
|
+
googleMeetCliModulePromise ??= import("./cli-CORe6B8A.js");
|
|
3752
|
+
return await googleMeetCliModulePromise;
|
|
3753
|
+
};
|
|
4085
3754
|
const googleMeetConfigSchema = {
|
|
4086
3755
|
parse(value) {
|
|
4087
3756
|
return resolveGoogleMeetConfig(value);
|
|
@@ -4404,7 +4073,8 @@ const testing = {
|
|
|
4404
4073
|
setPlatformForTests(next) {
|
|
4405
4074
|
googleMeetToolDeps.platform = next ?? (() => process.platform);
|
|
4406
4075
|
},
|
|
4407
|
-
isGoogleMeetAgentToolActionUnsupportedOnHost
|
|
4076
|
+
isGoogleMeetAgentToolActionUnsupportedOnHost,
|
|
4077
|
+
resolveGoogleMeetGatewayOperationTimeoutMs
|
|
4408
4078
|
};
|
|
4409
4079
|
function googleMeetGatewayMethodForToolAction(action) {
|
|
4410
4080
|
switch (action) {
|
|
@@ -4428,9 +4098,6 @@ function assertGoogleMeetAgentToolActionSupported(params) {
|
|
|
4428
4098
|
if (!isGoogleMeetAgentToolActionUnsupportedOnHost(params)) return;
|
|
4429
4099
|
throw new Error("Google Meet local Chrome talk-back audio is macOS-only. On this host, use mode: transcribe, transport: twilio, or transport: chrome-node backed by a macOS node.");
|
|
4430
4100
|
}
|
|
4431
|
-
function resolveGoogleMeetToolGatewayTimeoutMs(config) {
|
|
4432
|
-
return Math.max(6e4, config.chrome.joinTimeoutMs + 3e4, config.voiceCall.requestTimeoutMs + 1e4);
|
|
4433
|
-
}
|
|
4434
4101
|
function readGatewayErrorDetails(err) {
|
|
4435
4102
|
if (!err || typeof err !== "object" || !("details" in err)) return;
|
|
4436
4103
|
return err.details;
|
|
@@ -4439,7 +4106,7 @@ async function callGoogleMeetGatewayFromTool(params) {
|
|
|
4439
4106
|
try {
|
|
4440
4107
|
return await googleMeetToolDeps.callGatewayFromCli(googleMeetGatewayMethodForToolAction(params.action), {
|
|
4441
4108
|
json: true,
|
|
4442
|
-
timeout: String(
|
|
4109
|
+
timeout: String(resolveGoogleMeetGatewayOperationTimeoutMs(params.config))
|
|
4443
4110
|
}, params.raw, { progress: false });
|
|
4444
4111
|
} catch (err) {
|
|
4445
4112
|
const details = readGatewayErrorDetails(err);
|
|
@@ -4448,13 +4115,13 @@ async function callGoogleMeetGatewayFromTool(params) {
|
|
|
4448
4115
|
}
|
|
4449
4116
|
}
|
|
4450
4117
|
async function createMeetFromParams(params) {
|
|
4451
|
-
return (await
|
|
4118
|
+
return (await loadGoogleMeetCreateModule()).createMeetFromParams(params);
|
|
4452
4119
|
}
|
|
4453
4120
|
async function createAndJoinMeetFromParams(params) {
|
|
4454
|
-
return (await
|
|
4121
|
+
return (await loadGoogleMeetCreateModule()).createAndJoinMeetFromParams(params);
|
|
4455
4122
|
}
|
|
4456
4123
|
async function resolveGoogleMeetTokenFromParams(config, raw) {
|
|
4457
|
-
const { resolveGoogleMeetAccessToken } = await import("./oauth
|
|
4124
|
+
const { resolveGoogleMeetAccessToken } = await import("./oauth--J53aI66.js");
|
|
4458
4125
|
return resolveGoogleMeetAccessToken({
|
|
4459
4126
|
clientId: normalizeOptionalString(raw.clientId) ?? config.oauth.clientId,
|
|
4460
4127
|
clientSecret: normalizeOptionalString(raw.clientSecret) ?? config.oauth.clientSecret,
|
|
@@ -4543,7 +4210,7 @@ async function exportGoogleMeetBundleFromParams(config, raw) {
|
|
|
4543
4210
|
lateAfterMinutes: resolved.lateAfterMinutes,
|
|
4544
4211
|
earlyBeforeMinutes: resolved.earlyBeforeMinutes
|
|
4545
4212
|
})]);
|
|
4546
|
-
const { buildGoogleMeetExportManifest, googleMeetExportFileNames, writeMeetExportBundle } = await
|
|
4213
|
+
const { buildGoogleMeetExportManifest, googleMeetExportFileNames, writeMeetExportBundle } = await loadGoogleMeetCliModule();
|
|
4547
4214
|
const calendarId = normalizeOptionalString(raw.calendarId);
|
|
4548
4215
|
const request = {
|
|
4549
4216
|
...resolved.meeting ? { meeting: resolved.meeting } : {},
|
|
@@ -4959,7 +4626,7 @@ var google_meet_default = definePluginEntry({
|
|
|
4959
4626
|
handle: handleGoogleMeetNodeHostCommand
|
|
4960
4627
|
});
|
|
4961
4628
|
api.registerCli(async ({ program }) => {
|
|
4962
|
-
const { registerGoogleMeetCli } = await
|
|
4629
|
+
const { registerGoogleMeetCli } = await loadGoogleMeetCliModule();
|
|
4963
4630
|
registerGoogleMeetCli({
|
|
4964
4631
|
program,
|
|
4965
4632
|
config,
|