@navai/voice-frontend
v0.1.7
Published
Frontend helpers to build OpenAI Realtime voice agents
Readme
@navai/voice-frontend
Frontend package to build Navai voice agents in web applications.
It removes repeated boilerplate for:
- Realtime client secret requests.
- Route-aware navigation tools.
- Dynamic local function loading.
- Optional backend function bridging.
- React hook lifecycle for connect/disconnect.
Installation
npm install @navai/voice-frontend @openai/agents zod
npm install reactPackage Architecture
This package is intentionally split by concern:
src/backend.tsHTTP client for backend routes:
POST /navai/realtime/client-secretPOST /navai/speech/synthesizeGET /navai/functionsPOST /navai/functions/execute
src/runtime.tsRuntime resolver for:
- route module selection
- function module filtering by
NAVAI_FUNCTIONS_FOLDERS - agent discovery by
NAVAI_AGENTS_FOLDERS - optional model override
src/functions.tsLocal function loader:
- imports modules from generated loaders
- converts exports into normalized callable tool definitions
src/agent.tsAgent builder:
- creates primary
RealtimeAgent - injects built-in tools (
navigate_to,execute_app_function) - optionally adds direct alias tools for each allowed function
- creates specialist realtime agents and wires them as
handoffs
src/useWebVoiceAgent.tsReact lifecycle wrapper:
- builds runtime config
- requests client secret
- discovers backend functions
- builds agent
- opens/closes
RealtimeSession
src/routes.tsRoute matching helpers for natural language to path resolution.
End-to-End Runtime Flow
Hook-driven runtime flow (useWebVoiceAgent):
- Resolve runtime config from
moduleLoaders+defaultRoutes+ env/options. - Create backend client with
apiBaseUrlorNAVAI_API_URL. - On
start():
- request client secret.
- read
speech.providerfrom backend response. - fetch backend function list.
- build Navai agent with local + backend functions.
- connect
RealtimeSession.
- On
stop():
- close session and reset state.
State machine exposed by hook:
idleconnectingconnectederror
Agent voice state exposed by the hook:
agentVoiceState:idle | speakingisAgentSpeaking:boolean
agentVoiceState is driven by realtime events audio_start, audio_stopped, and audio_interrupted.
Public API
Main exports:
buildNavaiAgent(...)createNavaiBackendClient(...)resolveNavaiFrontendRuntimeConfig(...)loadNavaiFunctions(...)useWebVoiceAgent(...)resolveNavaiRoute(...)getNavaiRoutePromptLines(...)
Useful types:
NavaiRouteNavaiFunctionDefinitionNavaiFunctionsRegistryNavaiBackendFunctionDefinitionNavaiBackendSpeechConfigUseWebVoiceAgentOptions
Hybrid Speech Mode
When backend returns speech.provider: "elevenlabs":
useWebVoiceAgentupdates the Realtime session to useoutput_modalities: ["text"].- assistant final text is sent to
backendClient.synthesizeSpeech(...). - playback happens locally in the browser with the synthesized ElevenLabs audio.
Tool Model and Behavior
buildNavaiAgent always registers:
navigate_toexecute_app_function
When runtime agents are available:
- the first configured or explicit primary agent becomes the main realtime agent.
- other configured agents become specialist
RealtimeAgentinstances. - the main agent delegates with
handoffs, following the OpenAI Agents SDK multi-agent model.
Optional direct alias tools:
- for each allowed function name, a direct tool can be created.
- reserved names are never used as direct tools (
navigate_to,execute_app_function). - invalid tool ids are skipped (kept accessible via
execute_app_function).
Execution precedence:
- Try frontend/local function first.
- If missing, try backend function.
- If both exist with same name, frontend wins and backend is ignored with warning.
Dynamic Function Loading Internals
loadNavaiFunctions supports module export shapes:
- Exported function.
- Exported class (instance methods become functions).
- Exported object (callable members become functions).
Name normalization rules:
- snake_case lowercase.
- invalid chars removed.
- collisions are renamed with suffixes (
_2,_3, ...).
Argument mapping rules:
payload.argsorpayload.argumentsas direct args.- else
payload.valueas first arg. - else full payload as first arg.
- context appended when arity indicates one more argument.
For class methods:
- constructor args:
payload.constructorArgs. - method args:
payload.methodArgs.
Runtime Resolution and Env Precedence
resolveNavaiFrontendRuntimeConfig input priority:
- Explicit function args.
- Env object keys.
- Package defaults.
Keys used:
NAVAI_ROUTES_FILENAVAI_FUNCTIONS_FOLDERSNAVAI_AGENTS_FOLDERSNAVAI_REALTIME_MODEL
Defaults:
- routes file:
src/ai/routes.ts - functions folder:
src/ai/functions-modules
Multi-agent layout:
- agent root:
src/ai - agents env:
NAVAI_AGENTS_FOLDERS=main,support,sales,food - per-agent files live in
src/ai/<agent>/... - optional per-agent config file:
src/ai/<agent>/agent.config.ts - only the first level under
src/ai/defines the agent key - deeper folders are optional organization for that same agent
Multi-agent layout:
- agent root:
src/ai - agents env:
NAVAI_AGENTS_FOLDERS=main,support,sales - per-agent files live in
src/ai/<agent>/... - optional per-agent config file:
src/ai/<agent>/agent.config.ts
Example:
src/ai/
main/
agent.config.ts
session/logout.fn.ts
support/open-help.fn.ts
support/
agent.config.ts
system/ai-service.ts
sales/
agent.config.ts
utils/math.ts
food/
agent.config.ts
comida_rapida/hamburguesa.tsNotes:
src/ai/main/session/logout.fn.tsbelongs to themainagent.src/ai/main/support/open-help.fn.tsalso belongs to themainagent.- folders like
session,support,help, orutilsinside an agent are optional.
Path matcher formats:
- folder:
src/ai/functions-modules - recursive:
src/ai/functions-modules/... - wildcard:
src/features/*/voice-functions - explicit file:
src/ai/functions-modules/secret.ts - CSV list:
a,b,c
Fallback behavior:
- if configured folders match no modules, warning is emitted.
- resolver falls back to default functions folder.
When NAVAI_AGENTS_FOLDERS is present and NAVAI_FUNCTIONS_FOLDERS points to a folder root such as src/ai, the resolver only includes modules inside src/ai/<agent>/... for the configured agents.
For browser realtime multi-agent orchestration, buildNavaiAgent currently wires specialist agents with handoffs inside the shared RealtimeSession.
Backend Client Behavior
createNavaiBackendClient base URL priority:
apiBaseUrloption.env.NAVAI_API_URL.- fallback
http://localhost:3000.
Methods:
createClientSecret(input?)synthesizeSpeech({ text, ... })listFunctions()executeFunction({ functionName, payload })
Error handling:
- network/HTTP failures throw for create/execute.
- function listing returns warnings and empty list on failures.
createClientSecret()returns{ value, expires_at, speech }, wherespeech.providerisopenaiorelevenlabs.
Generated Module Loader CLI
This package ships:
navai-generate-web-loaders
Default command behavior:
- Reads
.envand process env. - Resolves
NAVAI_FUNCTIONS_FOLDERSandNAVAI_ROUTES_FILE. - Selects modules only from configured function paths.
- Optionally includes configured route module if it differs from default route module.
- Writes
src/ai/generated-module-loaders.ts.
Manual usage:
navai-generate-web-loadersUseful flags:
--project-root <path>--src-root <path>--output-file <path>--env-file <path>--default-functions-folder <path>--default-routes-file <path>--type-import <module>--export-name <identifier>
Auto Setup on npm Install
Postinstall script can auto-add missing scripts in consumer app:
generate:module-loaders->navai-generate-web-loaderspredev->npm run generate:module-loadersprebuild->npm run generate:module-loaderspretypecheck->npm run generate:module-loadersprelint->npm run generate:module-loaders
Rules:
- only missing scripts are added.
- existing scripts are never overwritten.
Disable auto setup:
NAVAI_SKIP_AUTO_SETUP=1- or
NAVAI_SKIP_FRONTEND_AUTO_SETUP=1
Manual setup runner:
npx navai-setup-voice-frontendIntegration Examples
Imperative integration:
import { RealtimeSession } from "@openai/agents/realtime";
import { buildNavaiAgent, createNavaiBackendClient } from "@navai/voice-frontend";
import { NAVAI_ROUTE_ITEMS } from "./ai/routes";
import { NAVAI_WEB_MODULE_LOADERS } from "./ai/generated-module-loaders";
const backend = createNavaiBackendClient({ apiBaseUrl: "http://localhost:3000" });
const secret = await backend.createClientSecret();
const backendList = await backend.listFunctions();
const { agent, warnings } = await buildNavaiAgent({
navigate: (path) => router.navigate(path),
routes: NAVAI_ROUTE_ITEMS,
functionModuleLoaders: NAVAI_WEB_MODULE_LOADERS,
backendFunctions: backendList.functions,
executeBackendFunction: backend.executeFunction
});
warnings.forEach((w) => console.warn(w));
const session = new RealtimeSession(agent);
await session.connect({ apiKey: secret.value });React hook integration:
import { useWebVoiceAgent } from "@navai/voice-frontend";
import { NAVAI_WEB_MODULE_LOADERS } from "./ai/generated-module-loaders";
import { NAVAI_ROUTE_ITEMS } from "./ai/routes";
const voice = useWebVoiceAgent({
navigate: (path) => router.navigate(path),
moduleLoaders: NAVAI_WEB_MODULE_LOADERS,
defaultRoutes: NAVAI_ROUTE_ITEMS,
env: import.meta.env as Record<string, string | undefined>
});Operational Notes
- warnings are emitted with
console.warnfrom runtime, backend list, and agent builder. - unknown function execution returns structured
ok: falsepayload. - if route module fails to load or has invalid shape, resolver falls back to default routes.
Related Docs
- Spanish version:
README.es.md - English version:
README.en.md - Backend package:
../voice-backend/README.md - Mobile package:
../voice-mobile/README.md - Playground Web:
../../apps/playground-web/README.md - Playground API:
../../apps/playground-api/README.md
