ADR-001: Migrate from @11labs/client to @elevenlabs/react
Status
Accepted
Date: 2025-11-20 (Approximate date of migration)
Context
The Mind Measure mobile application uses ElevenLabs' conversational AI for baseline assessments and check-ins. The original implementation used the @11labs/client SDK, which required manual session management and event handling.
Problems with the old SDK:
- Required manual
Conversation.startSession()calls - Event handlers (
onConnect,onMessage, etc.) needed to be wired manually - Session management was error-prone
- SDK was deprecated by ElevenLabs
- No React integration - had to manage state manually
- Difficult to handle cleanup and disconnection properly
Business requirements:
- Reliable real-time conversation with Jodie (AI agent)
- Clean state management
- Proper React lifecycle integration
- Support for future ElevenLabs features
Decision
We will migrate all ElevenLabs integrations to use @elevenlabs/react with the useConversation hook.
Key changes:
- Replace
@11labs/clientdependency with@elevenlabs/react - Replace manual
Conversation.startSession()withuseConversationhook - Use React hook patterns for event handling
- Leverage automatic cleanup and connection management
Code pattern:
// OLD (❌ Don't use)
import { Conversation } from '@11labs/client';
const conversation = await Conversation.startSession({
agentId: 'agent_xxx',
onConnect: () => setConnected(true),
onMessage: (msg) => setMessages(prev => [...prev, msg])
});
// NEW (✅ Use this)
import { useConversation } from '@elevenlabs/react';
const conversation = useConversation({
onConnect: () => console.log('Connected'),
onMessage: (msg) => setMessages(prev => [...prev, msg])
});
// Start session
const sessionId = await conversation.startSession({
agentId: 'agent_xxx'
});Consequences
Positive Consequences
- Better React integration: Hooks work naturally with React lifecycle
- Automatic cleanup: Hook handles disconnection when component unmounts
- Simpler code: Less manual state management
- Type safety: Better TypeScript definitions
- Future-proof: Active SDK with ongoing support
- Easier testing: Hooks can be mocked more easily
Negative Consequences
- Breaking change: Cannot mix old and new SDKs in the same project
- Migration effort: All files using old SDK must be updated simultaneously
- Different API: Developers familiar with old SDK need to learn new patterns
- Rollback difficulty: Cannot easily revert individual files
Neutral Consequences
- Same functionality, different implementation
- Bundle size remains similar
- No performance impact (positive or negative)
Alternatives Considered
Alternative 1: Keep @11labs/client
- Pros: No migration needed, developers already familiar
- Cons: Deprecated SDK, no React integration, manual state management
- Why not chosen: SDK is deprecated and lacks modern React patterns
Alternative 2: Use raw WebSocket connection
- Pros: Maximum control, no third-party dependency changes
- Cons: Have to implement entire protocol, no support, high maintenance
- Why not chosen: Extremely high engineering cost, reinventing the wheel
Alternative 3: Wait for ElevenLabs v2 API
- Pros: Might have even better features
- Cons: Unknown timeline, blocking current development
- Why not chosen: Can't wait indefinitely, current SDK is production-ready
Files Affected
Primary Files:
src/components/mobile/BaselineAssessmentSDK.tsx- Main baseline conversationsrc/components/mobile/CheckinAssessment.tsx- Check-in conversationpackage.json- Dependency change
Configuration Files:
- None (no environment variable changes)
Test Files:
- Any mocks for ElevenLabs conversations need updating
Rollback Safety
⚠️ CRITICAL: This is a breaking change that cannot be partially reverted.
If this decision needs to be reverted:
-
First, check if
@11labs/clientis still installed:npm list @11labs/client -
If not, reinstall it:
npm install @11labs/client npm uninstall @elevenlabs/react -
For each file using the new SDK:
- Find all
import { useConversation } from '@elevenlabs/react' - Replace with
import { Conversation } from '@11labs/client' - Replace hook usage with manual session management
- Add refs to store conversation instance
- Manually handle cleanup in useEffect
- Find all
-
Verify the rollback:
npm run build npm run check-layout # Should fail - update this check!
Critical checks before reverting:
- Confirm all files have been converted (use grep:
rg "useConversation") - Test build completes without errors
- Test conversation starts and messages flow
- Verify cleanup happens on unmount
- Update
scripts/check-layout.jsto check for old SDK
Breaking changes introduced:
Conversation.startSession()→conversation.startSession()- Event handlers in constructor → Hook parameters
- Manual cleanup → Automatic via hook
- Ref storage → Hook provides conversation object
Implementation Notes
Key patterns to follow:
-
Always use the hook at component level:
function MyComponent() { const conversation = useConversation({ ... }); // ... } -
Store session ID in state:
const [sessionId, setSessionId] = useState<string | null>(null); const startConversation = async () => { const sid = await conversation.startSession({ agentId: 'xxx' }); setSessionId(sid); }; -
Always end session on cleanup:
const handleFinish = async () => { await conversation.endSession(); }; -
Check conversation status:
if (conversation.status === 'connected') { // Show active UI }
Common pitfalls to avoid:
- ❌ Don't try to use
Conversation.startSession()- it doesn't exist in new SDK - ❌ Don't store conversation in a ref - use the hook's returned object
- ❌ Don't mix old and new SDK imports
- ❌ Don't forget to await
startSession()andendSession()
Testing requirements:
- Verify conversation starts successfully
- Check messages are received and displayed
- Confirm session ends cleanly
- Test error handling (network failures, etc.)
- Verify cleanup on component unmount
Documentation to update:
- Component README files (if any)
- Onboarding docs for new developers
DEVELOPMENT_SAFEGUARDS.md- reference this ADR
References
- ElevenLabs React SDK Documentation (opens in a new tab)
- GitHub PR for migration (opens in a new tab) (TODO: Add actual PR)
- Old SDK deprecation notice (opens in a new tab)
- Related: ADR-002: Baseline Component Split
Review History
- 2025-11-20: Implemented by development team
- 2025-12-08: Documented after rollback incident revealed need for ADRs
- 2025-12-08: Added to
scripts/check-layout.jsverification