Creating a New Command in Askimo
This guide explains how to implement a new command in the Askimo CLI. By following these steps, you can add custom functionality to the command-line interface.
Architecture Overview
Section titled “Architecture Overview”Askimo uses a simple command handling architecture with the following key components:
- CommandHandler: Interface that defines the contract for all command handlers
- Command implementations: Classes that implement the CommandHandler interface
- Command registration: Process of adding commands to the CLI application
Each command is identified by a keyword (starting with a colon) and has a description and handling logic.
Implementation Steps
Section titled “Implementation Steps”1. Create a New Command Handler
Section titled “1. Create a New Command Handler”First, create a new class that implements the CommandHandler interface. This class will handle your specific command:
// File: io.askimo.cli.commands.YourCommandHandler.kt
/** * Handles the command to [describe what your command does]. * * This class provides functionality to [explain the purpose and functionality of your command]. */class YourCommandHandler( private val session: Session, // Include any dependencies your command needs) : CommandHandler { override val keyword: String = ":yourcommand" // Command keyword (starts with colon) override val description: String = "Description of what your command does."
override fun handle(line: ParsedLine) { // Implement your command logic here
// Example: Access command arguments val args = line.words().drop(1) // Skip the command itself
// Example: Access the current session val provider = session.getActiveProvider() val modelName = session.params.getModel(provider)
// Example: Print output to the console println("✅ Your command executed successfully!") }}2. Register Your Command
Section titled “2. Register Your Command”To make your command available in the CLI, add it to the list of command handlers in the main function in ChatCli.kt:
// In ChatCli.kt
val commandHandlers: List<CommandHandler> = listOf( HelpCommandHandler(), ConfigCommand(session), ParamsCommandHandler(session), SetParamCommandHandler(session), ListProvidersCommandHandler(), SetProviderCommandHandler(session), ModelsCommandHandler(session), CopyCommandHandler(session), ClearMemoryCommandHandler(session), YourCommandHandler(session), // Add your command here )Don’t forget to add the import for your new command handler at the top of the file:
// Add this to the imports section at the top of ChatCli.ktimport io.askimo.cli.commands.YourCommandHandler3. Command Implementation Example
Section titled “3. Command Implementation Example”Let’s look at a real example: the ClearMemoryCommandHandler which clears the chat memory for the current provider and model:
// File: io.askimo.cli.commands.ClearMemoryCommandHandler.kt
/** * Handles the command to clear the chat memory. * * This class provides functionality to reset the conversation history for the current * provider and model combination. It allows users to start fresh conversations without * changing their model configuration. */class ClearMemoryCommandHandler( private val session: Session,) : CommandHandler { override val keyword: String = ":clear" override val description: String = "Clear the current chat memory for the active provider/model."
override fun handle(line: ParsedLine) { val provider = session.getActiveProvider() val modelName = session.params.getModel(provider)
session.removeMemory(provider, modelName)
println("🧹 Chat memory cleared for $provider / $modelName") }}This command:
- Gets the current provider and model from the session
- Calls the session’s
removeMemorymethod to clear the chat history - Prints a confirmation message to the user
4. Working with Command Arguments
Section titled “4. Working with Command Arguments”If your command needs to handle arguments, you can access them from the ParsedLine object:
override fun handle(line: ParsedLine) { val args = line.words().drop(1) // Skip the command itself
if (args.isEmpty()) { println("❌ This command requires arguments.") println("Usage: ${keyword} <argument1> <argument2>") return }
val arg1 = args[0] val arg2 = args.getOrNull(1) // Safely get optional arguments
// Process arguments...}5. Accessing Session Data
Section titled “5. Accessing Session Data”The Session object provides access to various aspects of the application state:
// Get the active providerval provider = session.getActiveProvider()
// Get the current model for a providerval modelName = session.params.getModel(provider)
// Get a parameter valueval paramValue = session.params.get(ParamKey.SYSTEM_PROMPT)
// Set a parameter valuesession.params.set(ParamKey.SYSTEM_PROMPT, "New value")
// Get the current chat modelval model = session.getChatModel()
// Store the last responsesession.lastResponse = "Response text"Best Practices
Section titled “Best Practices”Command Naming Conventions
Section titled “Command Naming Conventions”- Command keywords should start with a colon (
:) - Use lowercase for command names
- Use simple, descriptive names that clearly indicate the command’s purpose
Command Implementation
Section titled “Command Implementation”- Keep commands focused on a single responsibility
- Provide clear feedback to the user about what happened
- Handle errors gracefully with helpful error messages
- Use emojis for visual feedback (e.g., ✅, ❌, 🧹)
- Include detailed documentation in the class comment
Command Description
Section titled “Command Description”- Keep descriptions concise but informative
- Start with a verb (e.g., “Clear”, “Set”, “Show”)
- Make sure the description clearly explains what the command does
Testing Your Command
Section titled “Testing Your Command”After implementing your command, you can test it by:
- Building and running the Askimo CLI
- Using your command with the appropriate syntax:
askimo> :yourcommand [arguments]
- Verifying that the command produces the expected output and behavior
Conclusion
Section titled “Conclusion”By following these steps, you can extend the Askimo CLI with custom commands. The command handler architecture makes it easy to add new functionality while maintaining a consistent interface for users.
Remember to handle errors gracefully and provide clear feedback to users when something goes wrong with your command.