import { createContext, useContext } from 'react'; import { PersonaProtocol, ProtocolStatus, AgentState } from '../types'; import { PersonaMessage } from '../types'; import { PersonaWebRTCProtocol } from '../protocol'; import { getFirstAvailableProtocolEndpoint } from './utils'; export type PersonaRuntimeContextType = { protocols: PersonaProtocol[]; protocolsStatus: Map; agentState: AgentState; getMessages: () => PersonaMessage[]; renameThread: (threadId: string, name: string) => void; steerAgent: (text: string) => Promise; }; export const PersonaRuntimeContext = createContext(undefined); /** * Hook to access the PersonaRuntime context */ export function usePersonaRuntime(): PersonaRuntimeContextType { const context = useContext(PersonaRuntimeContext); if (!context) { throw new Error('usePersonaRuntime must be used within a PersonaRuntimeProvider'); } return context; } /** * Retrieves a specific protocol instance from the PersonaRuntimeContext. * * @param protocol - The name of the protocol to use. * @returns {PersonaProtocol | null} - The protocol instance or null if not found. * @throws {Error} - If the hook is used outside of a PersonaRuntimeProvider. */ export function usePersonaRuntimeProtocol(protocol: string): PersonaProtocol | null { const context = useContext(PersonaRuntimeContext); if (!context) { throw new Error('usePersonaRuntimeProtocol must be used within a PersonaRuntimeProvider'); } const protocolInstance = context.protocols.find((p) => p.getName() === protocol); if (!protocolInstance) { return null; } const status = context.protocolsStatus.get(protocolInstance.getName()); return { ...protocolInstance, connect: protocolInstance.connect.bind(protocolInstance), disconnect: protocolInstance.disconnect.bind(protocolInstance), sendPacket: protocolInstance.sendPacket.bind(protocolInstance), setSession: protocolInstance.setSession.bind(protocolInstance), addStatusChangeListener: protocolInstance.addStatusChangeListener.bind(protocolInstance), addPacketListener: protocolInstance.addPacketListener.bind(protocolInstance), getName: protocolInstance.getName.bind(protocolInstance), getPriority: protocolInstance.getPriority.bind(protocolInstance), status: status || protocolInstance.status, }; } /** * Gets the endpoint URL of the first available protocol */ export function usePersonaRuntimeEndpoint(): string | null { const context = useContext(PersonaRuntimeContext); if (!context) { throw new Error('usePersonaRuntimeEndpoint must be used within a PersonaRuntimeProvider'); } return getFirstAvailableProtocolEndpoint(context.protocols); } /** * Gets the WebRTC protocol instance */ export function usePersonaRuntimeWebRTCProtocol(): PersonaWebRTCProtocol | null { return usePersonaRuntimeProtocol('webrtc') as PersonaWebRTCProtocol; } /** * Renames a thread by calling the Persona sessions API */ export function usePersonaRenameThread(): (threadId: string, name: string) => void { const context = useContext(PersonaRuntimeContext); if (!context) { throw new Error('usePersonaRenameThread must be used within a PersonaRuntimeProvider'); } return context.renameThread; } /** * Gets all messages from the current conversation */ export function usePersonaRuntimeMessages(): PersonaMessage[] { const context = useContext(PersonaRuntimeContext); if (!context) { throw new Error('usePersonaRuntimeMessages must be used within a PersonaRuntimeProvider'); } return context.getMessages(); } /** * Gets the current agent execution state */ export function useAgentState(): AgentState { const context = useContext(PersonaRuntimeContext); if (!context) { throw new Error('useAgentState must be used within a PersonaRuntimeProvider'); } return context.agentState; } /** * Returns a function to steer the currently running agent */ export function useSteerAgent(): (text: string) => Promise { const context = useContext(PersonaRuntimeContext); if (!context) { throw new Error('useSteerAgent must be used within a PersonaRuntimeProvider'); } return context.steerAgent; }