Based on the git diff showing extensive package-lock.json changes and modifications to the agent system prompt and configuration, here's the commit message:
``` feat: add AI SDK dependencies and refine agent voice interaction config - Add @ai-sdk packages for enhanced AI capabilities - Install Deepgram SDK, livekit-client, and werift for voice/WebRTC - Expand agent system prompt with multi-tool workflows and Claude Code interaction patterns - Adjust VAD timing (1.2s silence threshold) and turn detection for better voice UX - Switch TTS to inworld/inworld-tts-1 with Olivia voice - Configure interruption timing (0.2s detection, no word requirement) - Add comprehensive guidelines for conversational responses vs structured output - Document plan mode triggers and Claude response type handling 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> ```
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
import { useEffect, useRef, useState, useCallback } from 'react';
|
||||
|
||||
interface WebSocketMessage {
|
||||
type: string;
|
||||
payload: unknown;
|
||||
}
|
||||
|
||||
type MessageHandler = (payload: unknown) => void;
|
||||
|
||||
export interface UseWebSocketReturn {
|
||||
isConnected: boolean;
|
||||
send: (message: WebSocketMessage) => void;
|
||||
on: (type: string, handler: MessageHandler) => () => void;
|
||||
sendPing: () => void;
|
||||
sendUserMessage: (message: string) => void;
|
||||
}
|
||||
|
||||
export function useWebSocket(url: string): UseWebSocketReturn {
|
||||
const [isConnected, setIsConnected] = useState(false);
|
||||
const wsRef = useRef<WebSocket | null>(null);
|
||||
const handlersRef = useRef<Map<string, Set<MessageHandler>>>(new Map());
|
||||
const reconnectTimeoutRef = useRef<number>();
|
||||
|
||||
const connect = useCallback(() => {
|
||||
if (wsRef.current?.readyState === WebSocket.OPEN) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const ws = new WebSocket(url);
|
||||
|
||||
ws.onopen = () => {
|
||||
console.log('[WS] Connected to server');
|
||||
setIsConnected(true);
|
||||
};
|
||||
|
||||
ws.onclose = () => {
|
||||
console.log('[WS] Disconnected from server');
|
||||
setIsConnected(false);
|
||||
|
||||
// Attempt to reconnect after 3 seconds
|
||||
reconnectTimeoutRef.current = window.setTimeout(() => {
|
||||
console.log('[WS] Attempting to reconnect...');
|
||||
connect();
|
||||
}, 3000);
|
||||
};
|
||||
|
||||
ws.onerror = (error) => {
|
||||
console.error('[WS] Error:', error);
|
||||
};
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
try {
|
||||
const message = JSON.parse(event.data) as WebSocketMessage;
|
||||
console.log(`[WS] Received message type: ${message.type}`, message.payload);
|
||||
|
||||
// Call all registered handlers for this message type
|
||||
const handlers = handlersRef.current.get(message.type);
|
||||
if (handlers) {
|
||||
handlers.forEach((handler) => {
|
||||
try {
|
||||
handler(message.payload);
|
||||
} catch (err) {
|
||||
console.error(`[WS] Error in handler for ${message.type}:`, err);
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('[WS] Failed to parse message:', err);
|
||||
}
|
||||
};
|
||||
|
||||
wsRef.current = ws;
|
||||
} catch (err) {
|
||||
console.error('[WS] Failed to create WebSocket:', err);
|
||||
}
|
||||
}, [url]);
|
||||
|
||||
useEffect(() => {
|
||||
connect();
|
||||
|
||||
return () => {
|
||||
if (reconnectTimeoutRef.current) {
|
||||
clearTimeout(reconnectTimeoutRef.current);
|
||||
}
|
||||
if (wsRef.current) {
|
||||
wsRef.current.close();
|
||||
}
|
||||
};
|
||||
}, [connect]);
|
||||
|
||||
const send = useCallback((message: WebSocketMessage) => {
|
||||
if (wsRef.current?.readyState === WebSocket.OPEN) {
|
||||
wsRef.current.send(JSON.stringify(message));
|
||||
} else {
|
||||
console.warn('[WS] Cannot send message - not connected');
|
||||
}
|
||||
}, []);
|
||||
|
||||
const on = useCallback((type: string, handler: MessageHandler) => {
|
||||
if (!handlersRef.current.has(type)) {
|
||||
handlersRef.current.set(type, new Set());
|
||||
}
|
||||
handlersRef.current.get(type)!.add(handler);
|
||||
|
||||
// Return cleanup function
|
||||
return () => {
|
||||
const handlers = handlersRef.current.get(type);
|
||||
if (handlers) {
|
||||
handlers.delete(handler);
|
||||
if (handlers.size === 0) {
|
||||
handlersRef.current.delete(type);
|
||||
}
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
const sendPing = useCallback(() => {
|
||||
send({ type: 'ping', payload: {} });
|
||||
}, [send]);
|
||||
|
||||
const sendUserMessage = useCallback(
|
||||
(message: string) => {
|
||||
send({ type: 'user_message', payload: { message } });
|
||||
},
|
||||
[send]
|
||||
);
|
||||
|
||||
return {
|
||||
isConnected,
|
||||
send,
|
||||
on,
|
||||
sendPing,
|
||||
sendUserMessage,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user