Skip to content

Tool Development Guide

SpdrByte edited this page Mar 4, 2026 · 1 revision

Tool Development Guide

Gemma CLI is built on a Modular Tool Architecture. To give Gemma a new capability, you simply need to create a single .ps1 file and drop it into the tools/ directory. The workstation will automatically discover, validate, and register it.


🏗️ The Anatomy of a Tool

Every tool must contain two parts:

  1. The Logic: A PowerShell function that performs the work.
  2. The Metadata: A $ToolMeta hashtable that teaches Gemma how and when to use it.

Required $ToolMeta Fields

Field Type Description
Name String The unique identifier the AI uses to call the tool (e.g., imagen).
Description String A high-level summary of what the tool does.
Parameters Hashtable Defines the expected inputs (type and description).
Example String A sample XML <tool_call> showing the tool in action.
FormatLabel ScriptBlock A UI helper that defines how the call appears in the CLI status box.
Execute ScriptBlock The bridge that maps AI parameters to your internal function.

🧠 Dynamic Tiered Guidance (NEW)

To ensure Gemma remains accurate regardless of model size, we use a tiered guidance system. You must define both in your $ToolMeta:

ToolUseGuidanceMajor

  • Target: Logic-heavy models (27B, 12B).
  • Focus: Nuanced instructions, edge cases, advanced parameter usage (wildcards, recursion), and complex error recovery.

ToolUseGuidanceMinor

  • Target: Tiny/Fast models (4B, 1B).
  • Focus: Basic "How-to", simplified purpose, and direct instructions. Keeps the system prompt lean.

🛠️ Example Template: get_weather.ps1

# ===============================================
# GemmaCLI Tool - get_weather.ps1 v1.0.0
# Responsibility: Return current weather in specified city.
# ===============================================

function Invoke-WeatherTool {
    param([string]$location)
    # Your logic (e.g., API call) here...
    return "The weather in $location is currently 72°F and Sunny."
}

# ── Self-registration block ──────────────────────────────────────────────────

$ToolMeta = @{
    Name        = "get_weather"
    Description = "Fetches current weather for a specific city."
    Parameters  = @{
        location = "string - city name (e.g., 'London', 'Tokyo')"
    }
    Example     = '<tool_call>{ "name": "get_weather", "parameters": { "location": "London" } }</tool_call>'
    FormatLabel = { param($p) "🌤️ Weather -> $($p.location)" }
    Execute     = { param($p) Invoke-WeatherTool @p }
    
    ToolUseGuidanceMajor = @"
        - When to use: Only when the user explicitly asks about current conditions or travel planning.
        - Parameters: Ensure the city name is specific. If multiple cities share a name, ask for clarification.
        - Error Handling: If the API is unreachable, suggest the user check their connection.
"@
    ToolUseGuidanceMinor = @"
        - Purpose: Get the weather.
        - Basic use: Provide the city name in the 'location' parameter.
"@
}

✅ Best Practices

  1. Return Strings: The Execute block should ideally return a string. If you return an object, the CLI will attempt to convert it to JSON for the AI.
  2. Safety First: If your tool performs destructive actions (like shell), add a safety filter or explicit user confirmation warnings in the guidance.
  3. UTF-8 Encoding: Save your .ps1 files with UTF-8 with BOM to ensure emojis in FormatLabel render correctly in the console.
  4. Testing: Create a companion test file in tests/ (e.g., your_tool.Tests.ps1) and run Invoke-Pester to verify your logic.

Next Steps: Check the System Architecture to see how tools are loaded via lib/ToolLoader.ps1.

Clone this wiki locally