Package 

Class BaseVoiceTool

  • All Implemented Interfaces:
    se.cpacsystems.voiceassistcapabilities.voicetool.VoiceTool

    
    public abstract class BaseVoiceTool<T extends Object>
     implements VoiceTool<T>
                        

    Abstract base class for implementing voice assistant tools.

    Extend this class to create a new voice tool. The schema is automatically generated from paramsClass using Kotlin serialization.

    Create a @Serializable data class that represents the input parameters for your tool. This class will be populated by the voice assistant based on the user's request.

    @Serializable
    data class LoadStatusParams(
        @Description("A UUID representing the truck to query")
        val truckId: String,
        val includeHistory: Boolean? = null
    )

    Note: The @Description annotation can be added to any field. It is optional and can be used to provide additional context for each parameter, which may help the voice assistant understand how to populate the fields.

    Param classes may be nested. Example:

    @Serializable
    data class User(
        @Description("What the user prefers to be called (first name, nickname, etc.)")
        val firstName: String
        @Description("The user's last name, if available")
        val lastName: String? = null
    )
    @Serializable
    data class AddUsersParams(
       val users: List<User>
    )

    Note: A nullable field (e.g., lastName: String?), must also have a default value (e.g., = null) to be properly deserialized by the voice assistant.

    • val lastName: String? - WRONG, will throw an error when creating the tool schema

    • val lastName: String? = null - CORRECT, creates a parameter that may be null

    Extend BaseVoiceTool with your params type. Override name, description, paramsClass, toolSafetyProfile, postExecutionBehavior, precondition and execute.

    Define the tool safety profile depending on whether the tool is safe to use while driving or not and if it requires confirmation. See ToolSafetyProfile for the available options.

    You can define the post execution behavior depending on whether the tool should close the session, keep it open, or close with confirmation. See PostExecutionBehavior for the available options.

    class LoadStatusTool : BaseVoiceTool<LoadStatusParams>() {
        override val name = "get_load_status"
        override val description = "Gets the current load status for a truck"
        override val paramsClass = LoadStatusParams::class
        override val toolSafetyProfile = ToolSafetyProfile.SafeWhileDriving.NoConfirmation
        override val postExecutionBehavior = PostExecutionBehavior.KeepOpen
    
        override suspend fun execute(params: LoadStatusParams): VoiceToolResult {
            val status = loadRepository.getStatus(params.truckId, history = params.includeHistory ?: false)
            return VoiceToolResult.Success("Truck ${params.truckId} is ${status.state}")
        }
        override suspend fun precondition: VoiceToolResult {
             if (LicenceHandler.hasMyLicence) {
                 VoiceToolResult.Success("")
             } else {
                 VoiceToolResult.Error("You do not have the correct licence")
             }
         }
    }

    Bind your tool in a hilt module using multibinding:

    @Module
    @InstallIn(SingletonComponent::class)
        abstract class MyVoiceToolModule {
        @Binds
        @IntoSet
        abstract fun bindLoadStatusTool(tool: LoadStatusTool): VoiceTool<*>
    }

    Inject VoiceToolRegistry and register your tools at app startup:

    @Singleton
    class VoiceAssistManager @Inject constructor(
        private val allVoiceTools: Set<@JvmSuppressWildcards VoiceTool<*>>,
        private val toolRegistry: VoiceToolRegistry
    ) {
        fun initVoiceAssistManager() {
            toolRegistry.registerTools(allVoiceTools)
            toolRegistry.syncToolsToProvider()
        }
    }