Skip to content

Add Jitsi bridge with downstream-configurable identity and Azure model updates#52263

Open
quandes wants to merge 2 commits intoopenclaw:mainfrom
quandes:feat/jitsi-azure-downstream-config
Open

Add Jitsi bridge with downstream-configurable identity and Azure model updates#52263
quandes wants to merge 2 commits intoopenclaw:mainfrom
quandes:feat/jitsi-azure-downstream-config

Conversation

@quandes
Copy link
Copy Markdown

@quandes quandes commented Mar 22, 2026

Summary

This PR adds two isolated commits that can also be cherry-picked independently:

  1. 8a3d6a61 - feat(jitsi): add bridge and downstream-configurable identity
  • Introduces Jitsi realtime bridge service and joiner scripts.
  • Removes hardcoded persona/identity values and moves them to downstream-configurable settings.
  • Adds configurable prompt/delegation/Telegram UI labels via downstream config.
  • Adds Telegram /jitsi and /meet bridge control integration.
  • Extends Telegram config schema/types/help/labels for channels.telegram.jitsi.
  1. 08398238 - feat(models): add azure realtime and forward-compat updates
  • Adds Azure realtime and model forward-compat updates.
  • Updates model compatibility/catalog/thinking/transcript related logic and tests.

Why

Downstream deployments need to configure identity and custom behavior without source edits, and keep Azure realtime/model support aligned with local runtime requirements.

Validation

  • pnpm tsgo
  • pnpm vitest run src/jitsi-bridge/downstream-config.test.ts src/jitsi-bridge/jitsi-url.test.ts src/jitsi-bridge/room-store.test.ts src/jitsi-bridge/audio.test.ts
  • pnpm vitest run src/config/config.secrets-schema.test.ts

Cherry-pick alternative

If maintainers prefer selective landing, cherry-pick:

  • 8a3d6a61
  • 08398238

@quandes quandes requested a review from a team as a code owner March 22, 2026 13:18
@openclaw-barnacle openclaw-barnacle bot added docs Improvements or additions to documentation scripts Repository scripts agents Agent runtime and tooling size: XL labels Mar 22, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 083982385e

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

): TelegramInlineButtons {
if (!hasActiveRoom) {
return [
[{ text: labels.createButton, callback_data: `${TELEGRAM_JITSI_CALLBACK_PREFIX}start` }],
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Wire Jitsi panel callbacks into Telegram callback handling

This adds inline /meet buttons with callback_data values (for example jitsi:start), but the new callback parser/executor (parseTelegramMeetCallback / handleTelegramMeetCallback) is never invoked anywhere, so button taps do not trigger the intended room actions. In the current Telegram callback flow (src/telegram/bot-handlers.ts), unknown callback payloads fall through to synthetic message processing, so users can end up sending raw jitsi:* text into normal agent handling instead of controlling the meeting panel.

Useful? React with 👍 / 👎.

const labels = jitsiCfg?.labels;
const envBridgeUrl = process.env.OPENCLAW_TELEGRAM_JITSI_BRIDGE_URL?.trim();
const bridgeUrl = jitsiCfg?.bridgeUrl?.trim() || envBridgeUrl || undefined;
const enabled = jitsiCfg?.enabled === true || Boolean(bridgeUrl);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Respect explicit disabled flag for Telegram Jitsi integration

The enablement check ignores an explicit channels.telegram.jitsi.enabled: false whenever a bridge URL is present, because it uses jitsi.enabled === true || Boolean(bridgeUrl). That makes opt-out impossible for accounts that still have bridgeUrl configured (or inherited from OPENCLAW_TELEGRAM_JITSI_BRIDGE_URL), so /meet and /jitsi remain active even when the config tries to disable them.

Useful? React with 👍 / 👎.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 22, 2026

Greptile Summary

This PR delivers two independent feature commits: a Jitsi realtime bridge service with downstream-configurable identity/prompts, and Azure realtime model forward-compatibility updates for gpt-realtime-1.5 and gpt-realtime-mini.

The Azure model compat work (model-forward-compat.ts, live-model-filter.ts, thinking.ts, transcript-policy.ts, etc.) is clean and well-tested — it follows established patterns precisely and poses no risk.

The Jitsi bridge is a well-structured MVP: token-gated join/enter flow, timing-safe token comparison, process-group signal escalation for joiner stop, and a sensible downstream config merge system. However, several policy violations need to be addressed before landing:

  • English-only policy (CLAUDE.md): The default prompt instructions, all Telegram UI labels, and every response string in src/jitsi-bridge/downstream-config.ts and src/jitsi-bridge/jitsi-command.ts are in German. The join-page HTML in service.ts uses lang="de" and German body text. docs/jitsi-realtime-bridge.md is written entirely in German. All of these must be in American English per the repo style guide; downstream operators who want German can override via the JSON config file.
  • Non-configurable German strings in buildMeetPanelText: The active-room panel lines ("Aktives Meeting:", "Modell:", "Start-Link:", "Briefing: noch keines gesetzt") are hardcoded in the function body and cannot be overridden through the existing labels system.
  • Personal name and private IP in docs: docs/reference/CUSTOM_DOWNSTREAM_MAINTENANCE.md embeds [email protected] and references IP-specific script names (scripts/release-192.168.179.3.sh). Per CLAUDE.md, docs must use generic placeholders such as user@gateway-host.

Confidence Score: 3/5

  • Not safe to merge as-is due to multiple CLAUDE.md policy violations; the functional code is solid but requires targeted fixes to language and docs content.
  • The Azure model compat changes are safe. The Jitsi bridge logic is well-implemented. However, there are three distinct policy violations that each require non-trivial fixes across multiple files: (1) German language throughout production code defaults and response strings, (2) non-configurable German strings in the panel renderer, and (3) personal name + IP in published docs. That's more than the single targeted fix threshold for a 4/5.
  • src/jitsi-bridge/downstream-config.ts, src/jitsi-bridge/jitsi-command.ts, src/jitsi-bridge/service.ts, docs/jitsi-realtime-bridge.md, docs/reference/CUSTOM_DOWNSTREAM_MAINTENANCE.md

Comments Outside Diff (2)

  1. src/jitsi-bridge/jitsi-command.ts, line 1051-1069 (link)

    P2 Hardcoded German strings in buildMeetPanelText bypass the configurable labels system

    While TelegramJitsiLabels exposes emptyPanelText / emptyPanelHint for the empty state, the active-room panel text is entirely hardcoded in German and is not part of the configurable label set:

    `Aktives Meeting: ${room.id}`,
    `Status: ${room.status}`,
    `Modell: ${room.realtimeModel}`,
    room.startUrl ? `Start-Link: ${room.startUrl}` : undefined,
    room.briefing ? `Briefing: ${room.briefing.slice(0, 180)}...` : "Briefing: noch keines gesetzt",

    A downstream deployer can configure every button label but cannot change these strings. Either move them into TelegramJitsiLabels / the downstream config so they're overridable, or at minimum translate the defaults to English so the out-of-the-box experience matches the repo's language policy.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: src/jitsi-bridge/jitsi-command.ts
    Line: 1051-1069
    
    Comment:
    **Hardcoded German strings in `buildMeetPanelText` bypass the configurable labels system**
    
    While `TelegramJitsiLabels` exposes `emptyPanelText` / `emptyPanelHint` for the empty state, the active-room panel text is entirely hardcoded in German and is not part of the configurable label set:
    
    ```typescript
    `Aktives Meeting: ${room.id}`,
    `Status: ${room.status}`,
    `Modell: ${room.realtimeModel}`,
    room.startUrl ? `Start-Link: ${room.startUrl}` : undefined,
    room.briefing ? `Briefing: ${room.briefing.slice(0, 180)}...` : "Briefing: noch keines gesetzt",
    ```
    
    A downstream deployer can configure every button label but cannot change these strings. Either move them into `TelegramJitsiLabels` / the downstream config so they're overridable, or at minimum translate the defaults to English so the out-of-the-box experience matches the repo's language policy.
    
    How can I resolve this? If you propose a fix, please make it concise.
  2. docs/reference/CUSTOM_DOWNSTREAM_MAINTENANCE.md, line 411-440 (link)

    P2 Personal name and private IP address in published docs

    CLAUDE.md states: "Docs content must be generic: no personal device names/hostnames/paths; use placeholders like user@gateway-host and 'gateway host'."

    The doc hardcodes both a first name and a specific private IP in multiple places:

    Example host:
    [email protected]
    
    rsync -az openclaw-<VERSION>.tgz user@gateway-host:/home/user/
    # vs actual:
    rsync -az openclaw-<VERSION>.tgz [email protected]:...
    

    The "Best Durable Setup" section also recommends creating scripts/release-192.168.179.3.sh and scripts/smoke-test-192.168.179.3.sh, which are deployment-specific script names that shouldn't appear in generic documentation.

    Replace all occurrences of [email protected] with user@gateway-host (consistent with the rsync example that already uses user@gateway-host) and use 192.0.2.X (TEST-NET) or <gateway-host-ip> as the placeholder IP address.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: docs/reference/CUSTOM_DOWNSTREAM_MAINTENANCE.md
    Line: 411-440
    
    Comment:
    **Personal name and private IP address in published docs**
    
    `CLAUDE.md` states: *"Docs content must be generic: no personal device names/hostnames/paths; use placeholders like `user@gateway-host` and 'gateway host'."*
    
    The doc hardcodes both a first name and a specific private IP in multiple places:
    
    ```
    Example host:
    [email protected]
    ```
    
    ```
    rsync -az openclaw-<VERSION>.tgz user@gateway-host:/home/user/
    # vs actual:
    rsync -az openclaw-<VERSION>.tgz [email protected]:...
    ```
    
    The "Best Durable Setup" section also recommends creating `scripts/release-192.168.179.3.sh` and `scripts/smoke-test-192.168.179.3.sh`, which are deployment-specific script names that shouldn't appear in generic documentation.
    
    Replace all occurrences of `[email protected]` with `user@gateway-host` (consistent with the rsync example that already uses `user@gateway-host`) and use `192.0.2.X` (TEST-NET) or `<gateway-host-ip>` as the placeholder IP address.
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/jitsi-bridge/downstream-config.ts
Line: 88-125

Comment:
**German strings in default prompt/UI config violate the English-only policy**

`CLAUDE.md` requires: *"Written English: use American spelling and grammar in code, comments, docs, and UI strings."*

The `DEFAULT_JITSI_BRIDGE_DOWNSTREAM_CONFIG` has German defaults for every user-facing string — `baseInstructions`, button labels, hints, and delegation messages. Because downstream deployments override these, the German defaults ship in the published package and appear verbatim for any deployment that doesn't supply a custom config file.

For example:
```
baseInstructions: [
  "Du bist ein technischer Meeting-Assistent in einem Business-Meeting.",
  ...
]
telegramUi: {
  createButton: "Neues Meeting",
  emptyPanelText: "Kein aktives Meeting in diesem Chat.",
  ...
}
```

All defaults should be English. Downstream operators who want German output can supply a JSON config file that overrides them.

The same issue applies to hardcoded German response strings throughout `src/jitsi-bridge/jitsi-command.ts` (e.g. `"Meeting ${room.id} erstellt."`, `"Joiner wurde gestartet."`, `"Briefing für ${room.id} gespeichert."`, `"Meeting ${room.id} gestoppt. Bot hat den Raum verlassen…"`, `"Aktives Meeting für diesen Chat wurde entfernt."`) and to the German HTML page in `src/jitsi-bridge/service.ts` (`lang="de"`, `"Meeting bereit"`, `"Ein Klick startet den Bot-Join…"`).

These strings also cannot currently be overridden via the downstream config or labels system, so even a downstream deployment that supplies a full config file will still receive German response text from the Telegram command handlers and the join page.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: src/jitsi-bridge/jitsi-command.ts
Line: 1051-1069

Comment:
**Hardcoded German strings in `buildMeetPanelText` bypass the configurable labels system**

While `TelegramJitsiLabels` exposes `emptyPanelText` / `emptyPanelHint` for the empty state, the active-room panel text is entirely hardcoded in German and is not part of the configurable label set:

```typescript
`Aktives Meeting: ${room.id}`,
`Status: ${room.status}`,
`Modell: ${room.realtimeModel}`,
room.startUrl ? `Start-Link: ${room.startUrl}` : undefined,
room.briefing ? `Briefing: ${room.briefing.slice(0, 180)}...` : "Briefing: noch keines gesetzt",
```

A downstream deployer can configure every button label but cannot change these strings. Either move them into `TelegramJitsiLabels` / the downstream config so they're overridable, or at minimum translate the defaults to English so the out-of-the-box experience matches the repo's language policy.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: docs/jitsi-realtime-bridge.md
Line: 1-10

Comment:
**Documentation file is entirely in German**

`CLAUDE.md` requires English for all docs in this repo. `docs/jitsi-realtime-bridge.md` is written entirely in German, including headings, body text, and explanations.

Additionally, the env-var example includes a real private-network IP address:
```
export JITSI_BRIDGE_PUBLIC_BASE_URL="http://192.168.179.3:4318"
```

Per the docs policy, use a generic placeholder such as `http://192.0.2.1:4318` or `http://<gateway-host>:4318` instead of a specific private address.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: docs/reference/CUSTOM_DOWNSTREAM_MAINTENANCE.md
Line: 411-440

Comment:
**Personal name and private IP address in published docs**

`CLAUDE.md` states: *"Docs content must be generic: no personal device names/hostnames/paths; use placeholders like `user@gateway-host` and 'gateway host'."*

The doc hardcodes both a first name and a specific private IP in multiple places:

```
Example host:
[email protected]
```

```
rsync -az openclaw-<VERSION>.tgz user@gateway-host:/home/user/
# vs actual:
rsync -az openclaw-<VERSION>.tgz [email protected]:...
```

The "Best Durable Setup" section also recommends creating `scripts/release-192.168.179.3.sh` and `scripts/smoke-test-192.168.179.3.sh`, which are deployment-specific script names that shouldn't appear in generic documentation.

Replace all occurrences of `[email protected]` with `user@gateway-host` (consistent with the rsync example that already uses `user@gateway-host`) and use `192.0.2.X` (TEST-NET) or `<gateway-host-ip>` as the placeholder IP address.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "feat(models): add azure realtime and for..." | Re-trigger Greptile

Comment on lines +88 to +125
};

function asObject(value: unknown): Record<string, unknown> | null {
return typeof value === "object" && value !== null ? (value as Record<string, unknown>) : null;
}

function asString(value: unknown): string | undefined {
return typeof value === "string" && value.trim() ? value.trim() : undefined;
}

function asStringList(value: unknown): string[] | undefined {
if (!Array.isArray(value)) {
return undefined;
}
const lines = value
.map((entry) => asString(entry))
.filter((entry): entry is string => Boolean(entry));
return lines.length > 0 ? lines : undefined;
}

function resolveDownstreamConfigPath(): string | undefined {
const explicit =
process.env.OPENCLAW_JITSI_CONFIG_PATH?.trim() ||
process.env.JITSI_DOWNSTREAM_CONFIG_PATH?.trim() ||
process.env.OPENCLAW_DOWNSTREAM_CONFIG_PATH?.trim();
if (!explicit) {
return undefined;
}
return path.isAbsolute(explicit) ? explicit : path.resolve(process.cwd(), explicit);
}

let cachedConfigPath: string | undefined;
let cachedConfig: JitsiBridgeDownstreamConfig | undefined;

export function loadJitsiBridgeDownstreamConfig(): JitsiBridgeDownstreamConfig {
const configPath = resolveDownstreamConfigPath();
if (cachedConfig && cachedConfigPath === configPath) {
return cachedConfig;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 German strings in default prompt/UI config violate the English-only policy

CLAUDE.md requires: "Written English: use American spelling and grammar in code, comments, docs, and UI strings."

The DEFAULT_JITSI_BRIDGE_DOWNSTREAM_CONFIG has German defaults for every user-facing string — baseInstructions, button labels, hints, and delegation messages. Because downstream deployments override these, the German defaults ship in the published package and appear verbatim for any deployment that doesn't supply a custom config file.

For example:

baseInstructions: [
  "Du bist ein technischer Meeting-Assistent in einem Business-Meeting.",
  ...
]
telegramUi: {
  createButton: "Neues Meeting",
  emptyPanelText: "Kein aktives Meeting in diesem Chat.",
  ...
}

All defaults should be English. Downstream operators who want German output can supply a JSON config file that overrides them.

The same issue applies to hardcoded German response strings throughout src/jitsi-bridge/jitsi-command.ts (e.g. "Meeting ${room.id} erstellt.", "Joiner wurde gestartet.", "Briefing für ${room.id} gespeichert.", "Meeting ${room.id} gestoppt. Bot hat den Raum verlassen…", "Aktives Meeting für diesen Chat wurde entfernt.") and to the German HTML page in src/jitsi-bridge/service.ts (lang="de", "Meeting bereit", "Ein Klick startet den Bot-Join…").

These strings also cannot currently be overridden via the downstream config or labels system, so even a downstream deployment that supplies a full config file will still receive German response text from the Telegram command handlers and the join page.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/jitsi-bridge/downstream-config.ts
Line: 88-125

Comment:
**German strings in default prompt/UI config violate the English-only policy**

`CLAUDE.md` requires: *"Written English: use American spelling and grammar in code, comments, docs, and UI strings."*

The `DEFAULT_JITSI_BRIDGE_DOWNSTREAM_CONFIG` has German defaults for every user-facing string — `baseInstructions`, button labels, hints, and delegation messages. Because downstream deployments override these, the German defaults ship in the published package and appear verbatim for any deployment that doesn't supply a custom config file.

For example:
```
baseInstructions: [
  "Du bist ein technischer Meeting-Assistent in einem Business-Meeting.",
  ...
]
telegramUi: {
  createButton: "Neues Meeting",
  emptyPanelText: "Kein aktives Meeting in diesem Chat.",
  ...
}
```

All defaults should be English. Downstream operators who want German output can supply a JSON config file that overrides them.

The same issue applies to hardcoded German response strings throughout `src/jitsi-bridge/jitsi-command.ts` (e.g. `"Meeting ${room.id} erstellt."`, `"Joiner wurde gestartet."`, `"Briefing für ${room.id} gespeichert."`, `"Meeting ${room.id} gestoppt. Bot hat den Raum verlassen…"`, `"Aktives Meeting für diesen Chat wurde entfernt."`) and to the German HTML page in `src/jitsi-bridge/service.ts` (`lang="de"`, `"Meeting bereit"`, `"Ein Klick startet den Bot-Join…"`).

These strings also cannot currently be overridden via the downstream config or labels system, so even a downstream deployment that supplies a full config file will still receive German response text from the Telegram command handlers and the join page.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +1 to +10
# Jitsi Realtime Bridge

Dieser Prototyp setzt das Zielbild in einer ersten lauffaehigen Form um:

1. OpenClaw oder ein Telegram-Workflow kann einen Raum per HTTP anlegen.
2. Der Dienst erzeugt eine Jitsi-URL und merkt sich Briefings pro Raum.
3. Ein Joiner-Prozess tritt mit konfigurierbarer Bot-Identitaet einem Jitsi-Raum bei.
4. Eine Azure-Realtime-Bridge kann pro Raum Antworten mit Persona + Briefing erzeugen.
5. Der Joiner schleust Remote-Audio aus Jitsi in Azure Realtime und spielt Antwort-Audio in die lokale Meeting-Mikrofonspur zurück.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Documentation file is entirely in German

CLAUDE.md requires English for all docs in this repo. docs/jitsi-realtime-bridge.md is written entirely in German, including headings, body text, and explanations.

Additionally, the env-var example includes a real private-network IP address:

export JITSI_BRIDGE_PUBLIC_BASE_URL="http://192.168.179.3:4318"

Per the docs policy, use a generic placeholder such as http://192.0.2.1:4318 or http://<gateway-host>:4318 instead of a specific private address.

Prompt To Fix With AI
This is a comment left during a code review.
Path: docs/jitsi-realtime-bridge.md
Line: 1-10

Comment:
**Documentation file is entirely in German**

`CLAUDE.md` requires English for all docs in this repo. `docs/jitsi-realtime-bridge.md` is written entirely in German, including headings, body text, and explanations.

Additionally, the env-var example includes a real private-network IP address:
```
export JITSI_BRIDGE_PUBLIC_BASE_URL="http://192.168.179.3:4318"
```

Per the docs policy, use a generic placeholder such as `http://192.0.2.1:4318` or `http://<gateway-host>:4318` instead of a specific private address.

How can I resolve this? If you propose a fix, please make it concise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling docs Improvements or additions to documentation scripts Repository scripts size: XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant