Skip to content

Conversation

@tleyden
Copy link
Contributor

@tleyden tleyden commented Dec 29, 2025

Summary by CodeRabbit

  • New Features

    • Add group-level prompt customization and a "Customize Overall Tool Group Prompt" action.
    • Voice session status events now show richer connection progress updates.
  • Bug Fixes

    • Missing Google Drive client ID now shows a clear error banner with icon and error styling.
  • Style

    • Improved disabled action card/title visuals and consistent error banner/icon/text styling.
    • Added descriptive text for several toolkit groups.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 29, 2025

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

Adds GDrive UI error/disabled styling and renames connector ID to google_drive; enables group-level tool prompt customization; introduces a new vm-webrtc API emitVoiceSessionStatus with JS/native emissions during voice-session lifecycle and threads group descriptions/prompts into toolkit loading.

Changes

Cohort / File(s) Summary
GDrive connector UI
components/settings/GDriveConnectorConfigCore.tsx
Prioritize disabled action title color; add statusBannerError, statusIconError, statusTextError; render error banner when client ID missing; add actionCardDisabled and actionTitleDisabled styling.
Connector IDs / config
components/settings/connectorOptions.ts, components/settings/ConnectorsConfig.tsx
Replace gdrive with google_drive in ConnectorId and CONNECTOR_OPTIONS; update connectorId checks to google_drive.
Tools UI — group prompts
components/settings/ConfigureToolsSheet.tsx, components/settings/ToolList.tsx
Add group-prompt mode (isGroupPrompt), getPromptKey() helper, wire onCustomizeGroupPrompt?: () => void through ToolList, add UI button to customize group prompt, and use group prompt key for promptDrafts load/save flows.
vm-webrtc JS surface
modules/vm-webrtc/index.ts, modules/vm-webrtc/src/VmWebrtcModule.ts, modules/vm-webrtc/src/VmWebrtc.types.ts
Add/export emitVoiceSessionStatus(statusUpdate: string) in JS wrapper and index; add groupDescription?: string on toolkit types and update signatures to accept it.
vm-webrtc iOS native
modules/vm-webrtc/ios/OpenAIWebRTCClient.swift, modules/vm-webrtc/ios/VmWebrtcModule.swift, modules/vm-webrtc/ios/WebRtcClientHelpers.swift
Insert onVoiceSessionStatus emissions at connection lifecycle milestones; add exported VmWebrtcModule.emitVoiceSessionStatus to emit events from JS; small logging emoji change.
Toolkit group & prompt threading
modules/vm-webrtc/src/ToolkitManager.ts, modules/vm-webrtc/src/VmWebrtc.types.ts, modules/vm-webrtc/toolkits/toolkitGroups.json
Thread optional groupDescription through fetch/convert/schedule functions; load and prepend _group_.{group} prompts when present; add group descriptions to toolkitGroups.json.
VoiceChat integration
app/VoiceChat.tsx
Import/use emitVoiceSessionStatus; set isConnecting/isSessionActive/sessionCostUsd earlier; emit status updates on OpenAI retries and on errors during connection start.

Sequence Diagram(s)

sequenceDiagram
    participant UI as VoiceChat (UI)
    participant JS as VmWebrtc (JS wrapper)
    participant Native as VmWebrtc Native (iOS)
    participant OpenAI as OpenAI WebRTC Endpoint

    UI->>JS: call emitVoiceSessionStatus("Connecting to OpenAI...")
    JS->>Native: invoke native emitVoiceSessionStatus(status)
    Note right of Native: Native emits onVoiceSessionStatus events\nat multiple lifecycle milestones
    Native->>JS: onVoiceSessionStatus event(payload)
    JS->>UI: propagate event to JS listeners
    UI->>UI: update UI state (isConnecting / retry / error)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I hopped through code with tiny paws,
Tweaked banners, IDs, and prompt-key laws.
I whispered statuses across the wire,
Group prompts now hum with added fire.
A cheerful rabbit claps: “Deploy, admire!” 🎉

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The PR title 'UI updates while testing' is vague and does not clearly summarize the main changes; it lacks specificity about what UI updates are being made. Provide a more descriptive title that clearly identifies the primary changes, such as 'Add group prompt customization and GDrive connector error handling' or similar that reflects the substantive work.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b3bf4cb and 529ba5a.

📒 Files selected for processing (1)
  • app/VoiceChat.tsx

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@dosubot
Copy link

dosubot bot commented Dec 29, 2025

Related Documentation

Checked 1 published document(s) in 1 knowledge base(s). No updates required.

How did I do? Any feedback?  Join Discord

@github-actions
Copy link

OSSF Scorecard (PR vs base)

  • Base score: 4.4
  • PR score: 4.4
  • Change: 0.00 (unchanged)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
components/settings/GDriveConnectorConfigCore.tsx (1)

368-389: Remove test/debug code from production.

The handleDisconnectLongPress callback and generateSecureRandomToken helper appear to be test/debug functionality that allows injecting random access tokens via long-press. This bypasses the normal OAuth flow and could be a security risk if users discover it.

Recommendation: Remove this code or protect it behind a development-only flag (e.g., __DEV__).

🔎 Proposed fix to remove debug code
- const handleDisconnectLongPress = useCallback(async () => {
-   try {
-     const randomToken = await generateSecureRandomToken();
-     await saveGDriveAccessToken(randomToken);
-     Alert.alert("access token randomized");
-   } catch {
-     Alert.alert("Error", "Failed to randomize access token.");
-   }
- }, []);
-
- // Helper to generate a secure random "ya29." token (with 32-byte hex string)
- async function generateSecureRandomToken(): Promise<string> {
-   // Use expo-random for cryptographically secure PRNG in React Native/Expo
-   // Generates 32 random bytes and encodes as hex
-   const { getRandomBytesAsync } = await import("expo-random");
-   const bytes = await getRandomBytesAsync(32);
-   // Convert bytes to hex string
-   const hex = Array.from(bytes)
-     .map((b) => b.toString(16).padStart(2, "0"))
-     .join("");
-   return `ya29.${hex}`;
- }

And remove the long press handler:

              <ButtonCard
                icon="🧹"
                title="Disconnect"
                note="Disconnects and clears stored auth tokens."
                variant="destructive"
                disabled={!hasAuthTokens || isLoading}
                onPress={handleDisconnect}
-               onLongPress={handleDisconnectLongPress}
-               suppressOnPressAfterLongPress
              />
🧹 Nitpick comments (2)
components/settings/GDriveConnectorConfigCore.tsx (2)

694-709: Consider consolidating duplicate icon styles.

The statusIconError style (line 706) is identical to statusIcon (line 705). You could reuse the existing statusIcon style instead of creating a duplicate.

🔎 Proposed consolidation

Remove the duplicate style definition and reuse statusIcon:

- <Text style={styles.statusIconError}>⚠️</Text>
+ <Text style={styles.statusIcon}>⚠️</Text>

Then remove line 706:

  statusIcon: { fontSize: 16, marginRight: 8 },
- statusIconError: { fontSize: 16, marginRight: 8 },

244-613: Consider extracting sub-components to improve maintainability.

The GDriveConnectorConfigCore component spans ~370 lines with multiple concerns (status display, connection actions, advanced settings). While the code is well-organized, extracting sub-components like StatusBanner, ConnectionActions, and AdvancedSettings would improve readability and testability.

Based on coding guidelines: "avoid making components too large - better refactor them into smaller reusable components."

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 544229f and e9810a3.

📒 Files selected for processing (1)
  • components/settings/GDriveConnectorConfigCore.tsx
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,jsx,ts,tsx}: When creating Expo React Native UI, avoid making components too large - better refactor them into smaller reusable components
Use Expo libraries instead of Node.js built-ins - use expo-file-system instead of Node.js fs module for file operations
Use Expo fetch instead of standard fetch for HTTP requests
Never use Node.js crypto module - instead use expo-crypto package with Crypto.digestStringAsync() for cryptographic operations

Files:

  • components/settings/GDriveConnectorConfigCore.tsx
🔇 Additional comments (3)
components/settings/GDriveConnectorConfigCore.tsx (3)

210-216: LGTM! Improved disabled state handling.

The disabled-first styling logic correctly prioritizes the disabled state over variant styles, ensuring consistent visual feedback when the button is disabled.


457-462: LGTM! Better visual distinction for configuration errors.

The new error banner with warning icon and red styling provides clearer feedback when the client ID is missing, improving the user experience.


732-735: LGTM! Explicit disabled state styling.

The explicit background color and full opacity for disabled cards provides better visual clarity compared to opacity-only approaches.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
modules/vm-webrtc/src/VmWebrtc.types.ts (1)

152-155: Consider using a newline separator instead of a space.

When concatenating groupDescription with toolkit.description, a single space may produce awkward or unclear text boundaries. A newline or double-newline would provide clearer separation consistent with the prompt additions below.

🔎 Suggested change
   // Start with group description if provided
   let description = groupDescription
-    ? `${groupDescription} ${toolkit.description}`
+    ? `${groupDescription}\n\n${toolkit.description}`
     : toolkit.description;
modules/vm-webrtc/src/ToolkitManager.ts (1)

562-627: LGTM on the group description threading with one optional nit.

The group-level prompt loading logic is well implemented with appropriate error handling via try-catch blocks. The description composition follows the same pattern as exportToolDefinition in VmWebrtc.types.ts.

Optional nit: Lines 595-598 and 611-613 use console.warn while the rest of the file uses the structured log.warn. Consider using log.warn for consistency with the file's logging pattern, which would make these warnings appear in structured logs alongside other toolkit manager events.

🔎 Example change for consistency
   } catch (error) {
     // If loading fails, just continue without group prompt
-    console.warn(
-      `Failed to load group prompt addition for MCP tool ${groupPromptKey}:`,
-      error,
+    log.warn(
+      "[ToolkitManager] Failed to load group prompt addition for MCP tool",
+      {},
+      {
+        promptKey: groupPromptKey,
+        error: error instanceof Error ? error.message : String(error),
+      },
     );
   }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e9810a3 and b3bf4cb.

📒 Files selected for processing (13)
  • app/VoiceChat.tsx
  • components/settings/ConfigureToolsSheet.tsx
  • components/settings/ConnectorsConfig.tsx
  • components/settings/ToolList.tsx
  • components/settings/connectorOptions.ts
  • modules/vm-webrtc/index.ts
  • modules/vm-webrtc/ios/OpenAIWebRTCClient.swift
  • modules/vm-webrtc/ios/VmWebrtcModule.swift
  • modules/vm-webrtc/ios/WebRtcClientHelpers.swift
  • modules/vm-webrtc/src/ToolkitManager.ts
  • modules/vm-webrtc/src/VmWebrtc.types.ts
  • modules/vm-webrtc/src/VmWebrtcModule.ts
  • modules/vm-webrtc/toolkits/toolkitGroups.json
✅ Files skipped from review due to trivial changes (1)
  • modules/vm-webrtc/ios/WebRtcClientHelpers.swift
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,jsx,ts,tsx}: When creating Expo React Native UI, avoid making components too large - better refactor them into smaller reusable components
Use Expo libraries instead of Node.js built-ins - use expo-file-system instead of Node.js fs module for file operations
Use Expo fetch instead of standard fetch for HTTP requests
Never use Node.js crypto module - instead use expo-crypto package with Crypto.digestStringAsync() for cryptographic operations

Files:

  • modules/vm-webrtc/index.ts
  • modules/vm-webrtc/src/VmWebrtcModule.ts
  • modules/vm-webrtc/src/VmWebrtc.types.ts
  • components/settings/ToolList.tsx
  • components/settings/connectorOptions.ts
  • app/VoiceChat.tsx
  • components/settings/ConfigureToolsSheet.tsx
  • components/settings/ConnectorsConfig.tsx
  • modules/vm-webrtc/src/ToolkitManager.ts
**/*.swift

📄 CodeRabbit inference engine (AGENTS.md)

Swift objects like AVAudioPlayerDelegate should have serialized access when called from multiple threads - protect shared state with a serial DispatchQueue or ensure all method calls dispatch to the main queue

Files:

  • modules/vm-webrtc/ios/OpenAIWebRTCClient.swift
  • modules/vm-webrtc/ios/VmWebrtcModule.swift
🧬 Code graph analysis (5)
modules/vm-webrtc/src/VmWebrtcModule.ts (3)
modules/vm-webrtc/index.ts (1)
  • emitVoiceSessionStatus (9-9)
lib/logger.ts (1)
  • log (257-338)
modules/vm-webrtc/ios/NativeLogger.swift (1)
  • log (26-68)
modules/vm-webrtc/src/VmWebrtc.types.ts (1)
lib/toolPrompts.ts (1)
  • loadToolPromptAddition (15-16)
app/VoiceChat.tsx (2)
modules/vm-webrtc/index.ts (1)
  • emitVoiceSessionStatus (9-9)
modules/vm-webrtc/src/VmWebrtcModule.ts (1)
  • emitVoiceSessionStatus (207-218)
components/settings/ConfigureToolsSheet.tsx (1)
lib/toolPrompts.ts (2)
  • loadToolPromptAddition (15-16)
  • saveToolPromptAddition (18-73)
modules/vm-webrtc/src/ToolkitManager.ts (2)
modules/vm-webrtc/src/VmWebrtc.types.ts (1)
  • exportToolDefinition (136-195)
lib/toolPrompts.ts (1)
  • loadToolPromptAddition (15-16)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: iOS Simulator Build
🔇 Additional comments (22)
components/settings/connectorOptions.ts (1)

3-3: LGTM! Clean connector ID rename.

The rename from "gdrive" to "google_drive" is consistent with the broader PR changes in ConnectorsConfig.tsx and toolkitGroups.json.

Also applies to: 30-30

components/settings/ConnectorsConfig.tsx (1)

51-52: LGTM!

The conditional check correctly updated to match the new "google_drive" connector ID.

components/settings/ToolList.tsx (2)

15-15: LGTM!

Clean implementation of the optional onCustomizeGroupPrompt prop with proper TypeScript typing.

Also applies to: 24-24


51-71: LGTM! Well-structured conditional UI block.

The group prompt customization button is properly:

  • Conditionally rendered only when the callback is provided
  • Accessible with appropriate role and label
  • Styled consistently with the existing tool buttons pattern
modules/vm-webrtc/src/VmWebrtc.types.ts (2)

157-171: LGTM! Robust group-level prompt loading.

The error-tolerant approach with console.warn is appropriate here—failing to load a prompt addition should not break tool definition export. The _group_.{group} key pattern aligns with the UI implementation in ConfigureToolsSheet.tsx.


173-187: LGTM!

Tool-specific prompt loading follows the same resilient pattern as group prompts.

components/settings/ConfigureToolsSheet.tsx (4)

36-36: LGTM!

Clean state addition to track group vs tool prompt mode.


172-186: LGTM! Well-designed group prompt flow.

The pseudo-tool pattern effectively reuses the existing ConfigurePromptModal infrastructure for group-level prompts. Using requestAnimationFrame to defer modal opening after sheet close ensures smooth UI transitions.


193-198: LGTM! Clean key generation logic.

The getPromptKey helper centralizes the key format distinction between group (_group_.{group}) and tool ({group}.{name}) prompts, consistent with the loading logic in VmWebrtc.types.ts.


272-276: LGTM!

Dynamic title properly reflects whether the user is customizing a group or individual tool prompt.

modules/vm-webrtc/index.ts (1)

9-9: LGTM!

Clean re-export of emitVoiceSessionStatus to expose the new voice session status API.

modules/vm-webrtc/toolkits/toolkitGroups.json (1)

5-5: LGTM! Useful group descriptions added.

The descriptions provide clear, concise summaries of each toolkit group's capabilities. These will enhance the group-level prompt composition feature.

Also applies to: 134-134, 236-236, 278-278, 421-421, 445-445, 469-469, 493-493, 512-512

modules/vm-webrtc/ios/VmWebrtcModule.swift (1)

343-349: LGTM!

Clean implementation of emitVoiceSessionStatus that emits the onVoiceSessionStatus event to JavaScript. The function correctly matches the event declared in the Events() block (line 91) and the TypeScript type VoiceSessionStatusEventPayload.

modules/vm-webrtc/src/VmWebrtcModule.ts (2)

57-57: LGTM!

The interface declaration for emitVoiceSessionStatus is consistent with the existing method signatures in the module.


207-218: LGTM!

The wrapper implementation follows the established pattern correctly:

  • Module availability check with appropriate error
  • Debug logging with the status update payload
  • Delegation to native module

Clean and consistent with other exported functions like muteUnmuteOutgoingAudio.

app/VoiceChat.tsx (2)

24-24: LGTM!

Import correctly added alongside other vm-webrtc exports.


369-372: LGTM!

Moving state resets before the try block ensures the UI updates immediately when the user presses the start button, providing better feedback responsiveness.

modules/vm-webrtc/ios/OpenAIWebRTCClient.swift (2)

496-501: LGTM!

Good placement of status emissions throughout the connection flow. The instrumentation provides clear progress feedback at each milestone without affecting the existing control flow or error handling.


561-565: LGTM!

The status emissions follow a consistent pattern and are strategically placed at meaningful connection milestones:

  • Audio session setup
  • Peer connection establishment
  • ICE gathering
  • SDP exchange
  • Connection finalization
  • Final connected state

The emitModuleEvent method already handles the case where no emitter is configured (logs and returns), so these calls are safe.

Also applies to: 578-582, 592-596, 617-621, 630-634, 642-646

modules/vm-webrtc/src/ToolkitManager.ts (3)

242-250: LGTM!

The static toolkit export now correctly threads through the group description, aligning with the signature update in exportToolDefinition.


684-703: LGTM!

The group description lookup and threading through to loadRemoteToolkitDefinitions is clean. The optional chaining on group?.description properly handles the case where the group might not be found.


837-852: LGTM!

The groupDescription parameter is consistently threaded through the entire remote toolkit loading chain:

  • convertToolsForCache
  • fetchAndCacheRemoteToolkitDefinitions
  • scheduleRemoteToolkitRefresh
  • loadRemoteToolkitDefinitions

All call sites are updated to pass the parameter correctly, and the optional nature (groupDescription?: string) maintains backward compatibility.

Also applies to: 855-892, 919-984, 986-1064

@tleyden tleyden merged commit ad49453 into main Dec 31, 2025
8 of 9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants