RTVI clients provide methods to alter the configuration of a bot at both startup and runtime. This workflow is fully supported by Daily Bots and is useful for changing the bot’s behavior without having to restart it.

So far, we have defined a config that is passed to the Daily Bots /start endpoint. This config is used to configure the bot’s behavior at startup. However, we can also change the configuration at runtime using the updateConfig method.

About configuration

Configuration is a JSON serializable array that defines the settings for each service that are used when running in the pipeline.

As we detailed in the client code, a configuration is defined as an array as the order of each service option is important.

While a client holds a stateful reference of the current configuration, it should not be considered the source of truth. RTVI clients hydrate their config whenever a change is made to the bot, which can occur:

  • When the bot is started, and the bot signals it is ready, see: onBotReady.
  • Whenever a client sends an updated configuration to the bot, see: onConfigUpdated.
  • Manually via the get-config action.

Describing available config

You can retrieve a list of configuration options a bot profile has available by calling a client’s describeConfig method:

const availableConfig = await voiceClient.describeConfig();
// > [ { service: "tts", options: [...]}, ... ]

Updating configuration

Clients can update the configuration via the updateConfig method both at startup (before voiceClient.start() is called) and during runtime.

The updateConfig method takes a configuration array as an argument and can be provided either a partial or a full configuration array.

Let’s take a look at some examples:

// Update the voice used by the TTS service
await voiceClient.updateConfig([
    { 
        service: "tts",
        options: [
            { name: "voice", value: "new_voice_id" }
        ]
    }
]);

// Update STT language and model
await voiceClient.updateConfig([
    {
        service: "stt",
        options: [
            { name: "model", value: "nova-2-general"},
            { name: "language", value: "es" }
        ]
    }
])

The above example demonstrate multiple consecutive calls updateConfig which is not recommended as it will be slower. Always send as many of your known changes at once. You can provide multiple service updates as part of your VoiceClientConfigOption array (see below for an example.)

By default, your bot will apply this new config once the pipeline has finished running, e.g. it has finished speaking.

You can override this behavior by setting the interrupt parameter to true, which will cause the new config to be applied immediately (interrupting the bot in the process).

// Update LLM model
await voiceClient.updateConfig([
    {
        service: "llm",
        options: [
            { name: "model", value:"meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo"}
        ]
    }
], true);  // or `false` to wait for your bot to finish the current pipeline turn

Async vs. sync

You can call updateConfig either asynchronously (via await) or synchronously.

Waiting for the promise to resolve will return the new config applied by the bot, although RTVI will hydrate the internal client state for you.

Config updates will trigger the following on a successful resolve…

  • onConfigUpdate callback
  • config-updated / VoiceEvent.ConfigUpdated event

… and the following on rejection:

  • onMessageError / MessageError

Calling this method using await allows you to try / catch the update, like so:

try{
    await voiceClient.updateConfig(...);
} catch e { 
    console.log(e); // instance of VoiceError
}

Config helper methods

In most use-cases, it’s likely you’ll want to update a subset of service options at the same time.

RTVI exposes methods that help you work with config, all of which are detailed here

These methods help you obtain values for a particular service in your local config, as well as update or set new values supported by your bot profile.

Let’s look at an example that changes the model and language of both stt and tts services:

// Create a new config object for Spanish TTS and STT
const newConfig = voiceClient.setConfigOptions([
  { service: "tts", options: [
    { name: "model", value: "sonic-multilingual" },
    { name: "language", value: "es" },
  ] },
  { service: "stt", options: [
    { name: "model", value: "nova-2-general" },
    { name: "language", value: "es" }
  ] },
]);

await voiceClient.updateConfig(newConfig);

Note that these methods do not mutate your internal client state, but return a new instance of your config with the changes applied.

Applying config changes will not alter the order of your client’s config array, unless you are adding an entirely new service not present in your initial configuration that is passed to the voice client constructor.

Updating LLM context

Another common use-case is to update the LLM context with a new system prompt or role and message.

RTVI defines a helper worklow when working with a LLM service as it reduces the complexity in the code-base for when an LLM service is not used.

You can register a LLM helper to your voice client like so:

import { LLMHelper } from "realtime-ai";

const voiceClient = new DailyVoiceClient({
    ...
});
const llmHelper = new LLMHelper({});
voiceClient.registerHelper("llm", llmHelper);

The llmHelper object exposes a series of methods for working with your LLM messages:

const llmHelper = voiceClient.getHelper("llm") as LLMHelper;
llmHelper.setContext({ 
    messages: {
        role: "system",
        content: "You are a assistant called NewContextBot. You can ask me anything.",
    }
}, true); // as with updateConfig, you can choose whether to interrupt the bot or not

By design, updates to your LLM context are not included in your bot config. If you need to obtain the current bot context, you can call the llmHelper.getContext() method.