Gopilot Logo
Development Status Go Version

⚠️ Note: This project is under active development and currently supports only the Gemini LLM.

GoPilot

GoPilot is an intelligent automation library that enables natural language interaction with your Go functions. It automatically routes user queries to appropriate functions, manages parameter mapping, and manages execution flow - all through simple speech inputs.

🌟 Key Features

Natural Language Processing

Process user queries in natural language

Automatic Function Routing

Map queries to the most appropriate function

Type-Safe Parameter Mapping

Convert dynamic inputs to strongly-typed parameters

Validation Built-in

Automatic validation of required parameters

Easy Integration

Simple API for registering and executing functions

Flexible Response Handling

Support for various response types and formats

��️ How It Works

Imagine an application with a complex settings menu. Instead of navigating multiple layers to adjust a setting, a user can simply say, "Set the app's font size to 15." If a GoPilot module is configured for this task, it analyzes the input, identifies the relevant agent or API, sets the necessary parameters, and executes the command as if the user had manually made the change. The result is a streamlined, intuitive experience that feels like having a personal assistant.

🔧 Installation

Follow these steps to integrate GoPilot into your Go project:

  1. Ensure you have Go >=1.23 installed.
  2. Add GoPilot to your project:
    go get github.com/SadikSunbul/gopilot@latest

💡 Example Usage

Below is an example of how to use GoPilot to register and execute a function, such as fetching weather information for a city:

package main

import (
    "context"
    "fmt"
    "log"
    
    "github.com/SadikSunbul/gopilot"
    "github.com/SadikSunbul/gopilot/clients"
    "github.com/SadikSunbul/gopilot/pkg/generator"
)

// Define your function parameters
type WeatherParams struct {
    City string `json:"city" description:"The name of the city to get weather information for" required:"true"`
}

// Define your function response
type WeatherResponse struct {
    City      string `json:"city"`
    Temp      int    `json:"temp"`
    Condition string `json:"condition"`
}

// Implement your function logic
func GetWeather(params WeatherParams) (WeatherResponse, error) {
    if params.City == "" {
        return WeatherResponse{}, fmt.Errorf("city cannot be empty")
    }
    
    // Your weather API integration here
    return WeatherResponse{
        City:      params.City,
        Temp:      25,
        Condition: "sunny",
    }, nil
}

func main() {
    // Initialize Gemini client
    client, err := clients.NewGeminiClient(context.Background(), "your-api-key", "gemini-2.0-flash")
    if err != nil {
        log.Fatal(err)
    }
    defer client.Close()

    // Create GoPilot instance
    gp, err := gopilot.NewGopilot(client)
    if err != nil {
        log.Fatal("failed to initialize gopilot:", err)
    }

    // Register your function
    weatherFn := &gopilot.Function[WeatherParams, WeatherResponse]{
        Name:        "weather-agent",
        Description: "Gets weather information for a specified city",
        Parameters:  generator.GenerateParameterSchema(WeatherParams{}),
        Execute:     GetWeather,
    }
    
    if err := gp.FunctionRegister(weatherFn); err != nil {
        log.Fatal(err)
    }

    // Set system prompt (required)
    gp.SetSystemPrompt(nil)

    // Process user query
    input := "What's the weather like in Istanbul?"
    
    // Option 1: Generate and Execute separately
    response, err := gp.Generate(input)
    if err != nil {
        log.Fatal(err)
    }
    
    result, err := gp.FunctionExecute(response.Agent, response.Parameters)
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("Result: %+v\n", result)

    // Option 2: Generate and Execute in one step
    result, err = gp.GenerateAndExecute(input)
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("Result: %+v\n", result)
}

Steps:

  1. Import the GoPilot package into your Go project.
  2. Initialize a client for your chosen LLM (currently only Gemini is supported).
  3. Create and register functions or agents with defined parameters and execution logic.
  4. Use Generate and FunctionExecute or the combined GenerateAndExecute to process user inputs.

🔧 Core Functions and Types

Function[T, R]

Generic type that represents a registered function with type-safe parameters (T) and response (R).


type Function[T any, R any] struct {
    Name        string
    Description string
    Parameters  map[string]ParameterSchema
    Execute     func(T) (R, error)
}

NewGopilot(client)

Initializes a new GoPilot instance with the specified LLM client (currently supports Gemini).


client, err := clients.NewGeminiClient(context.Background(), "your-api-key", "gemini-2.0-flash")
gp, err := gopilot.NewGopilot(client)

FunctionRegister[T, R](function)

Registers a new type-safe function with GoPilot. Uses Go generics for compile-time type safety.


weatherFn := &gopilot.Function[WeatherParams, WeatherResponse]{
    Name:        "weather-agent",
    Description: "Gets weather information for a specified city",
    Parameters:  generator.GenerateParameterSchema(WeatherParams{}),
    Execute:     GetWeather,
}
err := gp.FunctionRegister(weatherFn)

Generate(input)

Processes natural language input and determines the appropriate function and parameters.

response, err := gp.Generate("What's the weather like in Istanbul?")

FunctionExecute(agent, parameters)

Executes a registered function with the provided parameters, maintaining type safety.

result, err := gp.FunctionExecute(response.Agent, response.Parameters)

GenerateAndExecute(input)

Combines Generate and FunctionExecute into a single operation for simplified usage.

result, err := gp.GenerateAndExecute("What's the weather like in Istanbul?")

SetSystemPrompt(customPrompt)

Configures the system prompt for the LLM. Can use default or custom prompt.

gp.SetSystemPrompt(nil) // Use default prompt
// or
gp.SetSystemPrompt(&custom.SystemPrompt) // Use custom prompt

🚀 Advanced Usage Examples

Complex Parameter Types


type TranslateParams struct {
    Text string `json:"text" description:"The text to translate" required:"true"`
    Path struct {
        From    string `json:"from" description:"Source language code" required:"true"`
        To      string `json:"to" description:"Target language code" required:"true"`
        Options struct {
            Style string `json:"style" description:"Translation style"`
        } `json:"options" description:"Additional options"`
    } `json:"path" description:"Translation configuration" required:"true"`
}

type TranslateResponse struct {
    Original   string `json:"original"`
    Translated string `json:"translated"`
    From       string `json:"from"`
    To         string `json:"to"`
    Style      string `json:"style,omitempty"`
}

func Translate(params TranslateParams) (TranslateResponse, error) {
    // Translation logic here
    return TranslateResponse{}, nil
}

// Register with type safety
translateFn := &gopilot.Function[TranslateParams, TranslateResponse]{
    Name:        "translate-agent",
    Description: "Translates text between languages",
    Parameters:  generator.GenerateParameterSchema(TranslateParams{}),
    Execute:     Translate,
}

Interactive CLI Application


func main() {
    // Initialize client and GoPilot
    client, _ := clients.NewGeminiClient(context.Background(), "your-api-key", "gemini-2.0-flash")
    gp, _ := gopilot.NewGopilot(client)
    defer client.Close()

    // Register functions...

    reader := bufio.NewReader(os.Stdin)
    fmt.Println("Welcome! Type 'exit' to quit.")

    for {
        fmt.Print("\nQuestion: ")
        input, _ := reader.ReadString('\n')
        input = strings.TrimSpace(input)
        
        if input == "exit" {
            break
        }

        result, err := gp.GenerateAndExecute(input)
        if err != nil {
            fmt.Printf("Error: %v\n", err)
            continue
        }

        fmt.Printf("Result: %+v\n", result)
    }
}

�� Best Practices

Type Safety

Leverage Go's generic system for compile-time type checking and validation.

Parameter Validation

Use struct tags for documentation and validation requirements.

Error Handling

Implement comprehensive error handling with descriptive messages.

Documentation

Provide clear descriptions for functions and parameters.

🤝 Contributing

We welcome contributions to GoPilot! To get started:

  1. Fork the repository.
  2. Create a new branch (git checkout -b feature/your-feature).
  3. Make your changes and commit (git commit -m "Add your feature").
  4. Push to your branch (git push origin feature/your-feature).
  5. Open a Pull Request.

Please read our CONTRIBUTING.md for more details.

🔮 Roadmap

⚠️ Known Limitations

📜 License

This project is licensed under the MIT License. See LICENSE for details.

📬 Contact

For questions, suggestions, or issues, please: