refactor: rename conversation to voice conversation throughout stack

This commit is contained in:
Mohamed Boudra
2026-01-21 11:43:16 +07:00
parent ebb97a0184
commit ae9a98223f
21 changed files with 594 additions and 456 deletions
@@ -15,7 +15,7 @@ import AsyncStorage from "@react-native-async-storage/async-storage";
import { StyleSheet } from "react-native-unistyles";
import type { DaemonClientV2 } from "@server/client/daemon-client-v2";
const STORAGE_KEY = "@paseo:conversation-id";
const STORAGE_KEY = "@paseo:voice-conversation-id";
interface Conversation {
id: string;
@@ -24,14 +24,14 @@ interface Conversation {
}
interface ConversationSelectorProps {
currentConversationId: string | null;
onSelectConversation: (conversationId: string | null) => void;
currentVoiceConversationId: string | null;
onSelectVoiceConversation: (voiceConversationId: string | null) => void;
client: DaemonClientV2 | null;
}
export function ConversationSelector({
currentConversationId,
onSelectConversation,
currentVoiceConversationId,
onSelectVoiceConversation,
client,
}: ConversationSelectorProps) {
const [conversations, setConversations] = useState<Conversation[]>([]);
@@ -49,7 +49,7 @@ export function ConversationSelector({
try {
console.log("[ConversationSelector] Fetching conversations");
const response = await client.listConversations();
const response = await client.listVoiceConversations();
setConversations(response.conversations);
} catch (error) {
console.error(
@@ -88,10 +88,10 @@ export function ConversationSelector({
console.log("[ConversationSelector] Deleting conversation:", id);
void (async () => {
try {
const response = await client.deleteConversation(id);
const response = await client.deleteVoiceConversation(id);
if (response.success) {
await fetchConversations();
if (response.conversationId === currentConversationId) {
if (response.voiceConversationId === currentVoiceConversationId) {
await handleNewConversation();
}
} else {
@@ -113,7 +113,7 @@ export function ConversationSelector({
]
);
},
[currentConversationId, fetchConversations, handleNewConversation, client]
[currentVoiceConversationId, fetchConversations, handleNewConversation, client]
);
const handleClearAll = useCallback(() => {
@@ -136,7 +136,7 @@ export function ConversationSelector({
setIsLoading(true);
try {
for (const conv of conversations) {
await client.deleteConversation(conv.id);
await client.deleteVoiceConversation(conv.id);
}
setConversations([]);
await handleNewConversation();
@@ -161,7 +161,7 @@ export function ConversationSelector({
try {
// Save to AsyncStorage for persistence
await AsyncStorage.setItem(STORAGE_KEY, id);
onSelectConversation(id);
onSelectVoiceConversation(id);
setIsOpen(false);
} catch (error) {
console.error(
@@ -175,7 +175,7 @@ export function ConversationSelector({
try {
// Clear saved conversation ID
await AsyncStorage.removeItem(STORAGE_KEY);
onSelectConversation(null);
onSelectVoiceConversation(null);
setIsOpen(false);
} catch (error) {
console.error(
@@ -266,7 +266,7 @@ export function ConversationSelector({
key={conversation.id}
style={[
styles.conversationItem,
conversation.id === currentConversationId &&
conversation.id === currentVoiceConversationId &&
styles.conversationItemActive,
]}
>
+15 -2
View File
@@ -2,6 +2,10 @@ import { createContext, useContext, useState, ReactNode, useCallback, useEffect,
import { useSpeechmaticsAudio } from "@/hooks/use-speechmatics-audio";
import type { SessionState } from "@/stores/session-store";
import { useSessionStore } from "@/stores/session-store";
import AsyncStorage from "@react-native-async-storage/async-storage";
import { randomUUID } from "expo-crypto";
const VOICE_CONVERSATION_ID_STORAGE_KEY = "@paseo:voice-conversation-id";
interface RealtimeContextValue {
isRealtimeMode: boolean;
@@ -160,7 +164,16 @@ export function RealtimeProvider({ children }: RealtimeProviderProps) {
console.log("[Realtime] Mode enabled");
if (session?.client) {
await session.client.setRealtimeMode(true);
let voiceConversationId =
(await AsyncStorage.getItem(VOICE_CONVERSATION_ID_STORAGE_KEY)) ?? null;
if (!voiceConversationId) {
voiceConversationId = randomUUID();
await AsyncStorage.setItem(
VOICE_CONVERSATION_ID_STORAGE_KEY,
voiceConversationId
);
}
await session.client.setVoiceConversation(true, voiceConversationId);
} else {
console.warn("[Realtime] setRealtimeMode skipped: daemon unavailable");
}
@@ -183,7 +196,7 @@ export function RealtimeProvider({ children }: RealtimeProviderProps) {
console.log("[Realtime] Mode disabled");
if (session?.client) {
await session.client.setRealtimeMode(false);
await session.client.setVoiceConversation(false);
} else {
console.warn("[Realtime] setRealtimeMode skipped: daemon unavailable");
}
@@ -803,10 +803,7 @@ export function SessionProvider({
{ serverId }
);
void client
.loadConversation(client.currentConversationId ?? undefined)
.catch((error) => {
console.warn("[Session] session_state request failed:", error);
});
.requestSessionState();
if (sessionStateTimeoutRef.current) {
clearTimeout(sessionStateTimeoutRef.current);
@@ -2242,11 +2239,11 @@ export function SessionProvider({
console.warn("[Session] refreshSession skipped: daemon unavailable");
return;
}
void client
.loadConversation(client.currentConversationId ?? undefined)
.catch((error) => {
console.error("[Session] Failed to refresh session:", error);
});
try {
client.requestSessionState();
} catch (error: any) {
console.error("[Session] Failed to refresh session:", error);
}
}, [client, serverId]);
// Cleanup on unmount
+2 -3
View File
@@ -8,15 +8,14 @@ function runDaemonRequest(label: string, promise: Promise<unknown>): void {
});
}
export function useDaemonClient(url: string, conversationId?: string | null): DaemonClientV2 {
export function useDaemonClient(url: string): DaemonClientV2 {
const client = useMemo(
() =>
new DaemonClientV2({
url,
conversationId: conversationId ?? null,
suppressSendErrors: true,
}),
[url, conversationId]
[url]
);
useEffect(() => {