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, precondition and execute.

    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 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()
        }
    }