Skip to content

Conversation

@tleyden
Copy link
Contributor

@tleyden tleyden commented Jan 6, 2026

Add ability to disable compaction since it currently has a bug that resets the conversation

Summary by CodeRabbit

  • New Features
    • Added a "Disable Compaction" preference that can be toggled; the choice is persisted and applied to voice chat sessions.
  • UI
    • Context settings now disable related controls when compaction is turned off.
    • Bottom sheets now scroll when content is long and enforce a maximum height for better layout on tall screens.

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 6, 2026

📝 Walkthrough

Walkthrough

A new boolean flag disableCompaction is added end-to-end: a persisted developer setting and UI toggle, threaded through React props into the WebRTC bridge, passed into the native iOS WebRTC client, and used at runtime to disable conversation compaction in the event handler.

Changes

Cohort / File(s) Summary
React UI & App
app/VoiceChat.tsx, app/index.tsx, components/settings/ConfigureContextWindow.tsx
Add disableCompaction prop/state and handlers; persist/load preference via developerSettings; render a Switch in ConfigureContextWindow; pass flag into VoiceChat.
Persistence / Settings
lib/developerSettings.ts
Add DISABLE_COMPACTION_KEY and exported helpers loadCompactionDisabled() and saveCompactionDisabled(value: boolean) for storing the toggle.
WebRTC Types & Bridge
modules/vm-webrtc/src/VmWebrtc.types.ts, modules/vm-webrtc/ios/VmWebrtcModule.swift
Extend OpenAIConnectionOptions with optional disableCompaction and forward it through the module to native openConnection.
iOS WebRTC Client & Handler
modules/vm-webrtc/ios/OpenAIWebRTCClient.swift, modules/vm-webrtc/ios/WebRTCEventHandler.swift
openConnection accepts disableCompaction; WebRTCEventHandler stores disableCompaction, exposes configureDisableCompaction(disabled:), and guards compactConversationItems when disabled.
UI Layout
components/ui/BottomSheet.tsx
Wrap content in a ScrollView, add maxHeight, and minor layout/styling adjustments to make sheet content scrollable.

Sequence Diagram

sequenceDiagram
    actor User
    participant Configure as ConfigureContextWindow
    participant App as app/index.tsx
    participant DevSettings as developerSettings
    participant Voice as VoiceChat
    participant Bridge as VmWebrtcModule
    participant Client as OpenAIWebRTCClient
    participant Handler as WebRTCEventHandler

    rect rgb(220,235,245)
    App->>DevSettings: loadCompactionDisabled()
    DevSettings-->>App: boolean
    App->>Configure: render(disableCompaction)
    end

    rect rgb(220,245,220)
    User->>Configure: toggle Switch
    Configure->>App: onDisableCompactionChange(value)
    App->>DevSettings: saveCompactionDisabled(value)
    App->>Voice: render(disableCompaction)
    end

    rect rgb(245,235,210)
    Voice->>Bridge: openConnection(customConnectionOptions{disableCompaction})
    Bridge->>Client: openConnection(..., disableCompaction: Bool?)
    Client->>Handler: configureDisableCompaction(disabled: Bool)
    Handler->>Handler: set flag
    end

    rect rgb(245,220,220)
    Handler->>Handler: compactConversationItems()
    alt disableCompaction == true
        Handler->>Handler: log & skip compaction
    else
        Handler->>Handler: perform compaction
    end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐇 I nudged a switch to hush the chatter,
From UI to Swift the small flag did scatter,
Saved in storage, passed on through,
Now compaction listens to what I do —
A quiet hop, a gentle clatter.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
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.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Make compaction optional' directly describes the main change: adding the ability to disable/make optional the compaction feature throughout the codebase.
✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cafa259 and e6c6a27.

📒 Files selected for processing (2)
  • app/VoiceChat.tsx
  • modules/vm-webrtc/ios/WebRTCEventHandler.swift
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/VoiceChat.tsx
🧰 Additional context used
📓 Path-based instructions (1)
**/*.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/WebRTCEventHandler.swift
🧬 Code graph analysis (1)
modules/vm-webrtc/ios/WebRTCEventHandler.swift (1)
lib/logger.ts (3)
  • log (257-338)
  • info (302-304)
  • debug (299-301)
⏰ 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 (3)
modules/vm-webrtc/ios/WebRTCEventHandler.swift (3)

163-163: LGTM: Flag declaration is correct.

The disableCompaction flag is properly declared as private and initialized to false (compaction enabled by default). Thread safety is correctly handled via the conversationQueue serial dispatch queue in accessor methods.


2096-2109: LGTM: Configuration method is thread-safe and well-implemented.

The configureDisableCompaction method correctly uses conversationQueue.async to serialize access to the disableCompaction flag, following the coding guidelines for thread-safe state management. Logging provides good visibility for debugging.


2473-2485: LGTM: Critical issue from previous review has been correctly addressed.

The guard clause properly checks if compaction is disabled and, importantly, resets the compactionInProgress flag (lines 2477-2479) before returning. This prevents the permanent deadlock issue identified in the previous review where the flag would remain locked after an early return.

Thread safety is correctly implemented:

  • Read access to disableCompaction via conversationQueue.sync (line 2474)
  • Write access to reset compactionInProgress via conversationQueue.sync (lines 2477-2479)

The implementation follows the coding guidelines for serialized access to shared state.


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.

@github-actions
Copy link

github-actions bot commented Jan 6, 2026

OSSF Scorecard (PR vs base)

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

@dosubot
Copy link

dosubot bot commented Jan 6, 2026

Related Documentation

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

How did I do? Any feedback?  Join Discord

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

🤖 Fix all issues with AI Agents
In @app/VoiceChat.tsx:
- Line 418: The useCallback for handleStartVoiceSession closes over the
disableCompaction prop but disableCompaction is not included in its dependency
array, causing stale reads; update the dependency array for
handleStartVoiceSession to include disableCompaction so the callback re-creates
when the prop changes (locate the useCallback that defines
handleStartVoiceSession and add disableCompaction to its dependency list).

In @modules/vm-webrtc/ios/WebRTCEventHandler.swift:
- Around line 2473-2481: When compaction is disabled the early return in
compactConversationItems leaves the compactionInProgress flag set and blocks
future compactions; before returning from the guard branch in
compactConversationItems, reset compactionInProgress to false (perform the
mutation on the same conversationQueue.sync context as the read) so callers that
set compactionInProgress (e.g., where compactionInProgress = true is set around
lines 1667 and 1800) are not left in a permanently locked state; keep the
existing log call and then set compactionInProgress = false before exiting.
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ad49453 and f70bbde.

📒 Files selected for processing (8)
  • app/VoiceChat.tsx
  • app/index.tsx
  • components/settings/ConfigureContextWindow.tsx
  • lib/developerSettings.ts
  • modules/vm-webrtc/ios/OpenAIWebRTCClient.swift
  • modules/vm-webrtc/ios/VmWebrtcModule.swift
  • modules/vm-webrtc/ios/WebRTCEventHandler.swift
  • modules/vm-webrtc/src/VmWebrtc.types.ts
🧰 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/src/VmWebrtc.types.ts
  • lib/developerSettings.ts
  • components/settings/ConfigureContextWindow.tsx
  • app/VoiceChat.tsx
  • app/index.tsx
**/*.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/VmWebrtcModule.swift
  • modules/vm-webrtc/ios/WebRTCEventHandler.swift
  • modules/vm-webrtc/ios/OpenAIWebRTCClient.swift
🧠 Learnings (1)
📚 Learning: 2025-11-26T07:57:56.704Z
Learnt from: CR
Repo: vibemachine-labs/arty PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-26T07:57:56.704Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : When creating Expo React Native UI, avoid making components too large - better refactor them into smaller reusable components

Applied to files:

  • components/settings/ConfigureContextWindow.tsx
🧬 Code graph analysis (4)
lib/developerSettings.ts (1)
lib/logger.ts (2)
  • error (308-310)
  • warn (305-307)
app/index.tsx (1)
lib/developerSettings.ts (2)
  • loadCompactionDisabled (68-79)
  • saveCompactionDisabled (81-90)
modules/vm-webrtc/ios/WebRTCEventHandler.swift (3)
modules/vm-webrtc/ios/NativeLogger.swift (1)
  • log (26-68)
modules/vm-webrtc/ios/ConversationStateMachine.swift (1)
  • log (910-933)
modules/vm-webrtc/ios/VmWebrtcLogging.swift (1)
  • logAttributes (34-41)
modules/vm-webrtc/ios/OpenAIWebRTCClient.swift (1)
modules/vm-webrtc/ios/WebRTCEventHandler.swift (2)
  • configureConversationTurnLimit (2071-2094)
  • configureDisableCompaction (2096-2109)
⏰ 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 (19)
modules/vm-webrtc/src/VmWebrtc.types.ts (1)

224-224: LGTM!

The optional disableCompaction field is correctly added to the OpenAIConnectionOptions interface with a clear comment explaining its purpose.

components/settings/ConfigureContextWindow.tsx (3)

2-2: LGTM!

The new props are correctly added and destructured following the existing pattern.

Also applies to: 11-11, 14-14, 22-22, 25-25


87-87: Good UX decision to disable the slider.

Disabling the Max Conversation Turns slider when compaction is disabled makes logical sense since the turns limit won't be enforced.


91-106: LGTM!

The new Disable Compaction section follows the existing UI patterns and provides clear user feedback about the feature's behavior.

app/VoiceChat.tsx (1)

53-53: LGTM!

The new disableCompaction prop is correctly added to the component interface and destructured.

Also applies to: 66-66

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

38-39: LGTM!

The optional disableCompaction field is correctly added to the OpenAIConnectionOptions struct following the existing pattern for optional fields.


226-226: LGTM!

The disableCompaction option is correctly passed through to the WebRTC client's openConnection method.

lib/developerSettings.ts (3)

5-5: LGTM!

The constant follows the existing naming convention for developer settings keys.


68-79: LGTM!

The loadCompactionDisabled function correctly implements the same pattern as existing settings loaders with appropriate default behavior (compaction enabled) and error handling.


81-90: LGTM!

The saveCompactionDisabled function follows the existing pattern with consistent error handling.

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

91-91: LGTM! Property declaration is correct.

The disableCompaction property follows the same pattern as other configuration flags in the class, with an appropriate default of false (compaction enabled).


438-438: LGTM! Function signature extension is consistent.

The disableCompaction: Bool? parameter is appropriately optional and follows the same pattern as other configuration parameters in the function signature.


487-492: LGTM! Configuration is properly stored and propagated.

The disableCompaction value is correctly defaulted to false when not provided and properly passed to the event handler configuration. Thread safety is maintained through the @MainActor annotation on openConnection.

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

163-163: LGTM! Property declaration is correct.

The disableCompaction property is appropriately placed with other conversation tracking configuration and defaults to false (compaction enabled).


2096-2109: LGTM! Configuration function is properly implemented.

The configureDisableCompaction function correctly uses conversationQueue for thread-safe access and follows the same pattern as other configuration functions in the class.

app/index.tsx (4)

32-35: LGTM! Imports are correct.

The persistence functions loadCompactionDisabled and saveCompactionDisabled are properly imported from the developer settings module.


125-125: LGTM! State initialization and preference loading are correct.

The disableCompaction state is properly initialized with a default of false (compaction enabled) and loaded from persistent storage during component mount, following the same pattern as other preference values.

Also applies to: 204-222


364-372: LGTM! Change handler is properly implemented.

The handleDisableCompactionChange callback correctly updates both local state and persisted storage, following the same pattern as other preference handlers in the component.


521-521: LGTM! Props are correctly propagated to child components.

The disableCompaction preference is properly threaded through to VoiceChat (for connection configuration) and ConfigureContextWindow (for UI control), with the change handler callback correctly wired to propagate updates.

Also applies to: 583-586

audioSpeed: voiceSpeed,
maxConversationTurns,
retentionRatio,
disableCompaction,
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Missing dependency in useCallback.

The disableCompaction prop is used inside handleStartVoiceSession but is missing from its dependency array (lines 537-550). This creates a stale closure that won't reflect updates to the disableCompaction value.

🔎 Proposed fix

Add disableCompaction to the dependency array:

  }, [
    audioOutput,
    baseConnectionOptions,
    hasMicPermission,
    isConnecting,
    isSessionActive,
    mainPromptAddition,
    selectedVoice,
    selectedVadMode,
    voiceSpeed,
    maxConversationTurns,
    retentionRatio,
+   disableCompaction,
    selectedLanguage,
  ]);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
disableCompaction,
}, [
audioOutput,
baseConnectionOptions,
hasMicPermission,
isConnecting,
isSessionActive,
mainPromptAddition,
selectedVoice,
selectedVadMode,
voiceSpeed,
maxConversationTurns,
retentionRatio,
disableCompaction,
selectedLanguage,
]);
🤖 Prompt for AI Agents
In @app/VoiceChat.tsx at line 418, The useCallback for handleStartVoiceSession
closes over the disableCompaction prop but disableCompaction is not included in
its dependency array, causing stale reads; update the dependency array for
handleStartVoiceSession to include disableCompaction so the callback re-creates
when the prop changes (locate the useCallback that defines
handleStartVoiceSession and add disableCompaction to its dependency list).

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

🤖 Fix all issues with AI Agents
In @components/ui/BottomSheet.tsx:
- Around line 118-123: The ScrollView isn't expanding because the scrollView
style uses flexGrow: 0; update the BottomSheet component's scrollView style (and
where ScrollView is rendered) to use flex: 1 instead of flexGrow: 0 so the
ScrollView fills remaining space and allows proper scrolling; keep scrollContent
as-is (flexGrow: 1) to let inner content size correctly.
- Around line 68-75: The ScrollView inside BottomSheet is using
styles.scrollView with flexGrow: 0 which prevents it from filling the available
space; change styles.scrollView to use flex: 1 and change styles.scrollContent
to use flexGrow: 1 so the ScrollView expands within the bottom sheet and content
can scroll correctly (update the style definitions referenced by ScrollView and
contentContainerStyle), and remove the redundant explicit boolean props
showsVerticalScrollIndicator={true} and bounces={true} from the ScrollView
element.
🧹 Nitpick comments (1)
components/ui/BottomSheet.tsx (1)

71-72: Consider removing redundant boolean props.

The showsVerticalScrollIndicator and bounces props are explicitly set to true, which are their default values on iOS. While harmless, omitting them would reduce visual noise.

🔎 Proposed refactor
  <ScrollView
    style={styles.scrollView}
    contentContainerStyle={styles.scrollContent}
-   showsVerticalScrollIndicator={true}
-   bounces={true}
  >
    {children}
  </ScrollView>
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f70bbde and cafa259.

📒 Files selected for processing (1)
  • components/ui/BottomSheet.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/ui/BottomSheet.tsx
⏰ 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 (2)
components/ui/BottomSheet.tsx (2)

63-67: LGTM - Clear conditional rendering.

The reformatted title rendering with explicit parentheses and null return improves code clarity without changing functionality.


97-97: LGTM - Appropriate maxHeight constraint.

Setting maxHeight to 85% of screen height is a good UX practice for bottom sheets, ensuring the backdrop remains partially visible and the modal context is clear.

Comment on lines +68 to +75
<ScrollView
style={styles.scrollView}
contentContainerStyle={styles.scrollContent}
showsVerticalScrollIndicator={true}
bounces={true}
>
{children}
</ScrollView>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's examine the BottomSheet.tsx file to see the actual implementation
cat -n components/ui/BottomSheet.tsx

Repository: vibemachine-labs/arty

Length of output: 3760


🏁 Script executed:

# Search for other ScrollView implementations to compare styling patterns
rg -n -A 5 -B 2 '<ScrollView' --type=tsx --type=ts -g '!node_modules' -g '!*.test.*'

Repository: vibemachine-labs/arty

Length of output: 92


🏁 Script executed:

# Search for ScrollView in React Native TypeScript files without type flag
rg -n -A 5 '<ScrollView' -g '*.tsx' -g '*.ts' | head -100

Repository: vibemachine-labs/arty

Length of output: 5312


🏁 Script executed:

# Also check if there are any Expo ScrollView imports or usages
rg 'ScrollView' -g '*.tsx' -g '*.ts' | grep -E '(import|from|expo)' | head -20

Repository: vibemachine-labs/arty

Length of output: 181


Consider using flex: 1 instead of flexGrow: 0 on the ScrollView.

The ScrollView styling uses flexGrow: 0, which prevents it from filling the available space in the bottom sheet container. This is unusual and could prevent proper scroll detection when content exceeds the maxHeight constraint.

The standard React Native pattern for a ScrollView in a constrained container is flex: 1:

Suggested fix
scrollView: {
  flex: 1,
},
scrollContent: {
  flexGrow: 1,
},

Additionally, the explicit boolean props showsVerticalScrollIndicator={true} and bounces={true} are redundant defaults and can be removed.

🤖 Prompt for AI Agents
In @components/ui/BottomSheet.tsx around lines 68 - 75, The ScrollView inside
BottomSheet is using styles.scrollView with flexGrow: 0 which prevents it from
filling the available space; change styles.scrollView to use flex: 1 and change
styles.scrollContent to use flexGrow: 1 so the ScrollView expands within the
bottom sheet and content can scroll correctly (update the style definitions
referenced by ScrollView and contentContainerStyle), and remove the redundant
explicit boolean props showsVerticalScrollIndicator={true} and bounces={true}
from the ScrollView element.

Comment on lines +118 to +123
scrollView: {
flexGrow: 0,
},
scrollContent: {
flexGrow: 1,
},
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Replace flexGrow: 0 with flex: 1 on the ScrollView style.

The scrollView style uses flexGrow: 0, which prevents the ScrollView from expanding to fill the available space in the bottom sheet. This contradicts the typical pattern for scrollable containers and may cause the scrolling functionality to fail.

🔎 Proposed fix
  scrollView: {
-   flexGrow: 0,
+   flex: 1,
  },
  scrollContent: {
    flexGrow: 1,
  },

This allows the ScrollView to fill the remaining space after the header and handle, enabling proper scroll detection when content overflows.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
scrollView: {
flexGrow: 0,
},
scrollContent: {
flexGrow: 1,
},
scrollView: {
flex: 1,
},
scrollContent: {
flexGrow: 1,
},
🤖 Prompt for AI Agents
In @components/ui/BottomSheet.tsx around lines 118 - 123, The ScrollView isn't
expanding because the scrollView style uses flexGrow: 0; update the BottomSheet
component's scrollView style (and where ScrollView is rendered) to use flex: 1
instead of flexGrow: 0 so the ScrollView fills remaining space and allows proper
scrolling; keep scrollContent as-is (flexGrow: 1) to let inner content size
correctly.

@tleyden tleyden merged commit c5e2cc6 into main Jan 6, 2026
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