mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 05:30:42 +00:00
feat(plugins): simplify google meet realtime defaults
This commit is contained in:
@@ -13,6 +13,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Dependencies/Pi: update bundled Pi packages to `0.70.0`, use Pi's upstream `gpt-5.5` catalog metadata for OpenAI and OpenAI Codex, and keep only local `gpt-5.5-pro` forward-compat handling.
|
||||
- Models/CLI: split `openclaw models list` row-source orchestration and registry loading into narrower helpers without changing list output behavior. (#70867) Thanks @shakkernerd.
|
||||
- Plugins/Google Meet: add a bundled participant plugin with personal Google auth, explicit meeting URL joins, Chrome and Twilio transports, and realtime voice support. (#70765) Thanks @steipete.
|
||||
- Plugins/Google Meet: default Chrome realtime sessions to OpenAI plus SoX `rec`/`play` audio bridge commands, so the usual setup only needs the plugin enabled and `OPENAI_API_KEY`.
|
||||
- Providers/OpenAI: add image generation and reference-image editing through Codex OAuth, so `openai/gpt-image-2` works without an `OPENAI_API_KEY`. Fixes #70703.
|
||||
- Providers/OpenRouter: add image generation and reference-image editing through `image_generate`, so OpenRouter image models work with `OPENROUTER_API_KEY`. Fixes #55066 via #67668. Thanks @notamicrodose.
|
||||
- Image generation: let agents request provider-supported quality and output format hints, and pass OpenAI-specific background, moderation, compression, and user hints through the `image_generate` tool. (#70503) Thanks @ottodeng.
|
||||
|
||||
@@ -103,7 +103,15 @@ Workspace Developer Preview Program for Meet media APIs.
|
||||
|
||||
## Config
|
||||
|
||||
Set config under `plugins.entries.google-meet.config`:
|
||||
The common Chrome realtime path only needs the plugin enabled, BlackHole, SoX,
|
||||
and an OpenAI key:
|
||||
|
||||
```bash
|
||||
brew install blackhole-2ch sox
|
||||
export OPENAI_API_KEY=sk-...
|
||||
```
|
||||
|
||||
Set the plugin config under `plugins.entries.google-meet.config`:
|
||||
|
||||
```json5
|
||||
{
|
||||
@@ -111,86 +119,58 @@ Set config under `plugins.entries.google-meet.config`:
|
||||
entries: {
|
||||
"google-meet": {
|
||||
enabled: true,
|
||||
config: {
|
||||
defaultTransport: "chrome",
|
||||
defaultMode: "realtime",
|
||||
defaults: {
|
||||
meeting: "https://meet.google.com/abc-defg-hij",
|
||||
},
|
||||
preview: {
|
||||
enrollmentAcknowledged: false,
|
||||
},
|
||||
chrome: {
|
||||
audioBackend: "blackhole-2ch",
|
||||
launch: true,
|
||||
browserProfile: "Default",
|
||||
// Command-pair bridge: input writes 8 kHz G.711 mu-law audio to stdout.
|
||||
audioInputCommand: [
|
||||
"rec",
|
||||
"-q",
|
||||
"-t",
|
||||
"raw",
|
||||
"-r",
|
||||
"8000",
|
||||
"-c",
|
||||
"1",
|
||||
"-e",
|
||||
"mu-law",
|
||||
"-b",
|
||||
"8",
|
||||
"-",
|
||||
],
|
||||
// Output reads 8 kHz G.711 mu-law audio from stdin.
|
||||
audioOutputCommand: [
|
||||
"play",
|
||||
"-q",
|
||||
"-t",
|
||||
"raw",
|
||||
"-r",
|
||||
"8000",
|
||||
"-c",
|
||||
"1",
|
||||
"-e",
|
||||
"mu-law",
|
||||
"-b",
|
||||
"8",
|
||||
"-",
|
||||
],
|
||||
},
|
||||
twilio: {
|
||||
defaultDialInNumber: "+15551234567",
|
||||
defaultPin: "123456",
|
||||
},
|
||||
voiceCall: {
|
||||
enabled: true,
|
||||
gatewayUrl: "ws://127.0.0.1:18789",
|
||||
dtmfDelayMs: 2500,
|
||||
},
|
||||
realtime: {
|
||||
provider: "openai",
|
||||
model: "gpt-realtime",
|
||||
instructions: "You are joining a private Google Meet as my OpenClaw agent. Keep replies brief unless asked.",
|
||||
toolPolicy: "safe-read-only",
|
||||
providers: {
|
||||
openai: {
|
||||
apiKey: { env: "OPENAI_API_KEY" },
|
||||
},
|
||||
},
|
||||
},
|
||||
auth: {
|
||||
provider: "google-oauth",
|
||||
},
|
||||
oauth: {
|
||||
clientId: "your-google-oauth-client-id.apps.googleusercontent.com",
|
||||
refreshToken: "stored-refresh-token",
|
||||
},
|
||||
},
|
||||
config: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Defaults:
|
||||
|
||||
- `defaultTransport: "chrome"`
|
||||
- `defaultMode: "realtime"`
|
||||
- `chrome.audioBackend: "blackhole-2ch"`
|
||||
- `chrome.audioInputCommand`: SoX `rec` command writing 8 kHz G.711 mu-law
|
||||
audio to stdout
|
||||
- `chrome.audioOutputCommand`: SoX `play` command reading 8 kHz G.711 mu-law
|
||||
audio from stdin
|
||||
- `realtime.provider: "openai"`
|
||||
- `realtime.toolPolicy: "safe-read-only"`
|
||||
- `realtime.instructions`: brief spoken replies, with
|
||||
`openclaw_agent_consult` for deeper answers
|
||||
|
||||
Optional overrides:
|
||||
|
||||
```json5
|
||||
{
|
||||
defaults: {
|
||||
meeting: "https://meet.google.com/abc-defg-hij",
|
||||
},
|
||||
chrome: {
|
||||
browserProfile: "Default",
|
||||
},
|
||||
realtime: {
|
||||
toolPolicy: "owner",
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Twilio-only config:
|
||||
|
||||
```json5
|
||||
{
|
||||
defaultTransport: "twilio",
|
||||
twilio: {
|
||||
defaultDialInNumber: "+15551234567",
|
||||
defaultPin: "123456",
|
||||
},
|
||||
voiceCall: {
|
||||
gatewayUrl: "ws://127.0.0.1:18789",
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
## Tool
|
||||
|
||||
Agents can use the `google_meet` tool:
|
||||
|
||||
@@ -113,12 +113,49 @@ describe("google-meet plugin", () => {
|
||||
preview: { enrollmentAcknowledged: false },
|
||||
defaultTransport: "chrome",
|
||||
defaultMode: "realtime",
|
||||
chrome: { audioBackend: "blackhole-2ch", launch: true },
|
||||
chrome: {
|
||||
audioBackend: "blackhole-2ch",
|
||||
launch: true,
|
||||
audioInputCommand: [
|
||||
"rec",
|
||||
"-q",
|
||||
"-t",
|
||||
"raw",
|
||||
"-r",
|
||||
"8000",
|
||||
"-c",
|
||||
"1",
|
||||
"-e",
|
||||
"mu-law",
|
||||
"-b",
|
||||
"8",
|
||||
"-",
|
||||
],
|
||||
audioOutputCommand: [
|
||||
"play",
|
||||
"-q",
|
||||
"-t",
|
||||
"raw",
|
||||
"-r",
|
||||
"8000",
|
||||
"-c",
|
||||
"1",
|
||||
"-e",
|
||||
"mu-law",
|
||||
"-b",
|
||||
"8",
|
||||
"-",
|
||||
],
|
||||
},
|
||||
voiceCall: { enabled: true, requestTimeoutMs: 30000, dtmfDelayMs: 2500 },
|
||||
realtime: { toolPolicy: "safe-read-only" },
|
||||
realtime: {
|
||||
provider: "openai",
|
||||
toolPolicy: "safe-read-only",
|
||||
},
|
||||
oauth: {},
|
||||
auth: { provider: "google-oauth" },
|
||||
});
|
||||
expect(resolveGoogleMeetConfig({}).realtime.instructions).toContain("openclaw_agent_consult");
|
||||
});
|
||||
|
||||
it("uses env fallbacks for OAuth, preview, and default meeting values", () => {
|
||||
|
||||
@@ -78,7 +78,7 @@ const googleMeetConfigSchema = {
|
||||
"voiceCall.introMessage": { label: "Voice Call Intro Message", advanced: true },
|
||||
"realtime.provider": {
|
||||
label: "Realtime Provider",
|
||||
help: "Uses the first registered realtime voice provider when unset.",
|
||||
help: "Defaults to OpenAI; uses OPENAI_API_KEY when no provider config is set.",
|
||||
},
|
||||
"realtime.model": { label: "Realtime Model", advanced: true },
|
||||
"realtime.instructions": { label: "Realtime Instructions", advanced: true },
|
||||
|
||||
@@ -93,7 +93,7 @@
|
||||
},
|
||||
"realtime.provider": {
|
||||
"label": "Realtime Provider",
|
||||
"help": "Uses the first registered realtime voice provider when unset."
|
||||
"help": "Defaults to OpenAI; uses OPENAI_API_KEY when no provider config is set."
|
||||
},
|
||||
"realtime.model": {
|
||||
"label": "Realtime Model",
|
||||
@@ -157,11 +157,13 @@
|
||||
},
|
||||
"defaultTransport": {
|
||||
"type": "string",
|
||||
"enum": ["chrome", "twilio"]
|
||||
"enum": ["chrome", "twilio"],
|
||||
"default": "chrome"
|
||||
},
|
||||
"defaultMode": {
|
||||
"type": "string",
|
||||
"enum": ["realtime", "transcribe"]
|
||||
"enum": ["realtime", "transcribe"],
|
||||
"default": "realtime"
|
||||
},
|
||||
"chrome": {
|
||||
"type": "object",
|
||||
@@ -169,25 +171,58 @@
|
||||
"properties": {
|
||||
"audioBackend": {
|
||||
"type": "string",
|
||||
"enum": ["blackhole-2ch"]
|
||||
"enum": ["blackhole-2ch"],
|
||||
"default": "blackhole-2ch"
|
||||
},
|
||||
"launch": {
|
||||
"type": "boolean"
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"browserProfile": {
|
||||
"type": "string"
|
||||
},
|
||||
"joinTimeoutMs": {
|
||||
"type": "number"
|
||||
"type": "number",
|
||||
"default": 30000
|
||||
},
|
||||
"audioInputCommand": {
|
||||
"type": "array",
|
||||
"default": [
|
||||
"rec",
|
||||
"-q",
|
||||
"-t",
|
||||
"raw",
|
||||
"-r",
|
||||
"8000",
|
||||
"-c",
|
||||
"1",
|
||||
"-e",
|
||||
"mu-law",
|
||||
"-b",
|
||||
"8",
|
||||
"-"
|
||||
],
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"audioOutputCommand": {
|
||||
"type": "array",
|
||||
"default": [
|
||||
"play",
|
||||
"-q",
|
||||
"-t",
|
||||
"raw",
|
||||
"-r",
|
||||
"8000",
|
||||
"-c",
|
||||
"1",
|
||||
"-e",
|
||||
"mu-law",
|
||||
"-b",
|
||||
"8",
|
||||
"-"
|
||||
],
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
@@ -226,7 +261,8 @@
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"enabled": {
|
||||
"type": "boolean"
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"gatewayUrl": {
|
||||
"type": "string"
|
||||
@@ -235,10 +271,12 @@
|
||||
"type": "string"
|
||||
},
|
||||
"requestTimeoutMs": {
|
||||
"type": "number"
|
||||
"type": "number",
|
||||
"default": 30000
|
||||
},
|
||||
"dtmfDelayMs": {
|
||||
"type": "number"
|
||||
"type": "number",
|
||||
"default": 2500
|
||||
},
|
||||
"introMessage": {
|
||||
"type": "string"
|
||||
@@ -250,17 +288,20 @@
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"provider": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"default": "openai"
|
||||
},
|
||||
"model": {
|
||||
"type": "string"
|
||||
},
|
||||
"instructions": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"default": "You are joining a private Google Meet as an OpenClaw agent. Keep spoken replies brief and natural. When a question needs deeper reasoning, current information, or tools, call openclaw_agent_consult before answering."
|
||||
},
|
||||
"toolPolicy": {
|
||||
"type": "string",
|
||||
"enum": ["safe-read-only", "owner", "none"]
|
||||
"enum": ["safe-read-only", "owner", "none"],
|
||||
"default": "safe-read-only"
|
||||
},
|
||||
"providers": {
|
||||
"type": "object",
|
||||
|
||||
@@ -62,6 +62,41 @@ export type GoogleMeetConfig = {
|
||||
};
|
||||
};
|
||||
|
||||
export const DEFAULT_GOOGLE_MEET_AUDIO_INPUT_COMMAND = [
|
||||
"rec",
|
||||
"-q",
|
||||
"-t",
|
||||
"raw",
|
||||
"-r",
|
||||
"8000",
|
||||
"-c",
|
||||
"1",
|
||||
"-e",
|
||||
"mu-law",
|
||||
"-b",
|
||||
"8",
|
||||
"-",
|
||||
] as const;
|
||||
|
||||
export const DEFAULT_GOOGLE_MEET_AUDIO_OUTPUT_COMMAND = [
|
||||
"play",
|
||||
"-q",
|
||||
"-t",
|
||||
"raw",
|
||||
"-r",
|
||||
"8000",
|
||||
"-c",
|
||||
"1",
|
||||
"-e",
|
||||
"mu-law",
|
||||
"-b",
|
||||
"8",
|
||||
"-",
|
||||
] as const;
|
||||
|
||||
export const DEFAULT_GOOGLE_MEET_REALTIME_INSTRUCTIONS =
|
||||
"You are joining a private Google Meet as an OpenClaw agent. Keep spoken replies brief and natural. When a question needs deeper reasoning, current information, or tools, call openclaw_agent_consult before answering.";
|
||||
|
||||
export const DEFAULT_GOOGLE_MEET_CONFIG: GoogleMeetConfig = {
|
||||
enabled: true,
|
||||
defaults: {},
|
||||
@@ -74,6 +109,8 @@ export const DEFAULT_GOOGLE_MEET_CONFIG: GoogleMeetConfig = {
|
||||
audioBackend: "blackhole-2ch",
|
||||
launch: true,
|
||||
joinTimeoutMs: 30_000,
|
||||
audioInputCommand: [...DEFAULT_GOOGLE_MEET_AUDIO_INPUT_COMMAND],
|
||||
audioOutputCommand: [...DEFAULT_GOOGLE_MEET_AUDIO_OUTPUT_COMMAND],
|
||||
},
|
||||
twilio: {},
|
||||
voiceCall: {
|
||||
@@ -82,6 +119,8 @@ export const DEFAULT_GOOGLE_MEET_CONFIG: GoogleMeetConfig = {
|
||||
dtmfDelayMs: 2_500,
|
||||
},
|
||||
realtime: {
|
||||
provider: "openai",
|
||||
instructions: DEFAULT_GOOGLE_MEET_REALTIME_INSTRUCTIONS,
|
||||
toolPolicy: "safe-read-only",
|
||||
providers: {},
|
||||
},
|
||||
@@ -255,8 +294,12 @@ export function resolveGoogleMeetConfigWithEnv(
|
||||
chrome.joinTimeoutMs,
|
||||
DEFAULT_GOOGLE_MEET_CONFIG.chrome.joinTimeoutMs,
|
||||
),
|
||||
audioInputCommand: resolveStringArray(chrome.audioInputCommand),
|
||||
audioOutputCommand: resolveStringArray(chrome.audioOutputCommand),
|
||||
audioInputCommand: resolveStringArray(chrome.audioInputCommand) ?? [
|
||||
...DEFAULT_GOOGLE_MEET_AUDIO_INPUT_COMMAND,
|
||||
],
|
||||
audioOutputCommand: resolveStringArray(chrome.audioOutputCommand) ?? [
|
||||
...DEFAULT_GOOGLE_MEET_AUDIO_OUTPUT_COMMAND,
|
||||
],
|
||||
audioBridgeCommand: resolveStringArray(chrome.audioBridgeCommand),
|
||||
audioBridgeHealthCommand: resolveStringArray(chrome.audioBridgeHealthCommand),
|
||||
},
|
||||
@@ -280,9 +323,12 @@ export function resolveGoogleMeetConfigWithEnv(
|
||||
introMessage: normalizeOptionalString(voiceCall.introMessage),
|
||||
},
|
||||
realtime: {
|
||||
provider: normalizeOptionalString(realtime.provider),
|
||||
model: normalizeOptionalString(realtime.model),
|
||||
instructions: normalizeOptionalString(realtime.instructions),
|
||||
provider:
|
||||
normalizeOptionalString(realtime.provider) ?? DEFAULT_GOOGLE_MEET_CONFIG.realtime.provider,
|
||||
model: normalizeOptionalString(realtime.model) ?? DEFAULT_GOOGLE_MEET_CONFIG.realtime.model,
|
||||
instructions:
|
||||
normalizeOptionalString(realtime.instructions) ??
|
||||
DEFAULT_GOOGLE_MEET_CONFIG.realtime.instructions,
|
||||
toolPolicy: resolveToolPolicy(
|
||||
realtime.toolPolicy,
|
||||
DEFAULT_GOOGLE_MEET_CONFIG.realtime.toolPolicy,
|
||||
|
||||
Reference in New Issue
Block a user