How Voice Commands Are Dispatched in God's Eye View: Architecture and Available Tools
Voice commands in God's Eye View are dispatched through an event-driven pipeline where OpenAI Realtime function calls trigger the GEV action runner, which executes 15+ built-in tools ranging from camera control to radio management.
The voice control subsystem in the bilawalsidhu/gods-eye-view repository converts natural speech into precise map interactions using a flexible tool-dispatch architecture. When users speak, the system processes their intent through a pipeline that bridges speech-to-text AI with concrete application actions. Understanding how voice commands are dispatched and which tools are available is essential for developers extending the platform or debugging voice interactions.
Voice Command Architecture Overview
The voice subsystem resides under src/voice/ and follows a three-stage pattern: capture, dispatch, and execute. According to the gods-eye-view source code, the entry point initGevVoiceCommands in gevRealtime.js initializes the voice UI and registers event listeners, while createGevActionRunner in gevActions.js manufactures the dispatcher that routes tool requests to their implementations. A third module, voiceCost.js, manages tiering and cost limits to govern API usage.
The Dispatch Pipeline: From Speech to Action
Bootstrapping the Voice Interface
The initGevVoiceCommands function sets up the voice control environment and establishes the bridge to the OpenAI Realtime API. It accepts dependencies including the viewer, styleManager, dataManager, and optional sceneDirector and annotations managers, then registers a listener for model function-call events.
export function initGevVoiceCommands({viewer, styleManager, dataManager, sceneDirector = null, annotations = null}) {
// … UI setup …
// Listen for function-call events from the LLM
window.addEventListener('response.function_call_arguments.done', event => {
const calls = extractFunctionCalls(event);
// Each call is turned into a GEV action
calls.forEach(call => runGevAction(call.name, call.arguments));
});
}
Source: src/voice/gevRealtime.js at line 196
Handling Function Call Events
When the LLM decides to invoke a tool, it emits a response.function_call_arguments.done event. The bootstrapper extracts these calls using extractFunctionCalls and forwards each to runGevAction. This design decouples the speech-to-text provider from the business logic, allowing the dispatcher to handle multiple concurrent tool calls in a single utterance.
The Action Runner Factory
The createGevActionRunner function returns the dispatcher that executes tools. Implemented in src/voice/gevActions.js at line 286, this factory closures over the application state and returns an async runGevAction function that normalizes arguments and routes them to the appropriate handler.
export function createGevActionRunner({viewer, styleManager, dataManager, sceneDirector = null, annotations = null}) {
return async function runGevAction(name, rawArgs = {}, runOptions = {}) {
// Normalise arguments, call the appropriate implementation
// and return a structured result {ok, action, …}
};
}
Available Voice Tools and Capabilities
The dispatcher recognizes a fixed catalog of tools defined in src/voice/gevActions.js. Each entry follows the pattern action: '<tool_name>'. The most important available tools include:
| Tool (action name) | Purpose | Example arguments |
|---|---|---|
adjust_camera_zoom |
Zoom the camera in/out | {direction:'in', amount:0.5} |
set_layer_visibility |
Show/hide a map layer | {layerId:'cctv', enabled:true} |
set_visual_style |
Switch visual preset (e.g., night, satellite) | {style:'satellite'} |
set_panel_open |
Open/close a UI panel | {panelId:'radar', open:true} |
control_cockpit |
Change cockpit mode (e.g., “weather”) | {action:'weather'} |
control_cctv |
Enable/disable CCTV layer or focus a camera | {action:'focus', cameraQuery:'austin'} |
control_scene |
Play, pause or stop a scripted scene | {action:'play', sceneId:'demo'} |
control_radio |
Play, pause, change volume or select a station | {action:'play', locationQuery:'Austin'} |
track_entity |
Follow a moving entity (e.g., aircraft) | {query:'flight123'} |
annotate_map / clear_annotations |
Add or remove map annotations | {type:'polygon', points:[…]} |
set_hud |
Show/hide heads-up-display elements | {hudId:'altitude', enabled:true} |
set_detection |
Toggle detection layers (e.g., fire) | {layerId:'firms', enabled:true} |
set_map_stack |
Switch between map stacks (different data sources) | {requested:'satellite'} |
set_context_mode |
Change UI context mode (e.g., “data”) | {mode:'data'} |
The complete list can be found by searching for action: in src/voice/gevActions.js.
Execution Flow and Return Values
The dispatcher normalizes arguments, executes the appropriate handler, and returns a structured result object. This result flows back to the LLM as a function_call_output payload, enabling conversational continuity.
For example, when a user says "Play the local news," the LLM generates:
{
"action": "control_radio",
"arguments": {
"action": "play",
"locationQuery": "Austin",
"category": "news"
}
}
The runGevAction dispatcher executes the Radio controller and returns:
{
"ok": true,
"action": "control_radio",
"changed": true,
"summary": "Playing news near Austin"
}
Manual Tool Invocation for Development
Developers can trigger tools programmatically using the action runner for debugging or automation scripts. First instantiate the runner with the required dependencies, then call runGevAction with the tool name and arguments.
// Assuming the action runner has been created elsewhere:
const runGevAction = createGevActionRunner({viewer, styleManager, dataManager});
// Play a Radio station near Austin
await runGevAction('control_radio', {
action: 'play',
locationQuery: 'Austin',
category: 'news'
});
// Zoom the camera out by 30%
await runGevAction('adjust_camera_zoom', {
direction: 'out',
amount: 0.3
});
Core Files and Module Organization
These three modules constitute the core of the voice-command pipeline:
src/voice/gevRealtime.js– Sets up voice UI, listens for LLM function-call events, extracts calls withextractFunctionCalls, and forwards them to the dispatcher.src/voice/gevActions.js– Defines the full catalog of tools (action:entries) and implements each one through thecreateGevActionRunnerfactory.src/voice/voiceCost.js– Handles voice-model tiering and cost limits; used bygevRealtime.jsto decide whether to accept new tool calls based on budget constraints.
Summary
- Voice commands enter via OpenAI Realtime function calls captured in
src/voice/gevRealtime.js - The
initGevVoiceCommandsfunction bootstraps the UI and registers theresponse.function_call_arguments.doneevent listener createGevActionRunnerinsrc/voice/gevActions.jsdispatches calls to 15+ specialized tools covering camera control, layer visibility, UI panels, radio, CCTV, annotations, and scene management- Each tool execution returns a structured result that flows back to the LLM as a
function_call_outputpayload for conversational continuity - The complete tool catalog is searchable via the
action:pattern ingevActions.js
Frequently Asked Questions
What triggers a voice command dispatch in God's Eye View?
The response.function_call_arguments.done event from the OpenAI Realtime API triggers the dispatch. This browser event carries function call payloads that gevRealtime.js extracts using extractFunctionCalls and forwards to the runGevAction dispatcher returned by createGevActionRunner.
How can I add a new voice tool to the system?
Register the new tool by adding an action: entry in src/voice/gevActions.js and implementing the corresponding handler within the createGevActionRunner dispatcher logic. The tool becomes available immediately to the LLM function-calling interface without requiring changes to the bootstrap code in gevRealtime.js.
What is the difference between control_radio and control_cctv tools?
The control_radio tool manages audio playback, volume, and station selection using location-based queries like locationQuery: 'Austin', while control_cctv toggles the CCTV layer visibility and focuses specific camera feeds using camera query strings such as cameraQuery: 'austin'.
How does the system handle voice command failures?
The runGevAction dispatcher returns a structured result object with an ok boolean and error details. These results are formatted as function_call_output payloads and sent back to the LLM, allowing the model to apologize or suggest alternatives conversationally without crashing the application.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →