robby

package module
v0.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 22, 2025 License: MIT Imports: 9 Imported by: 0

README

Robby 🤖

Lightweight Go library for building AI Agents with Docker Model Runner and Docker MCP Toolkit

Go Version License Docker

Robby is a lightweight Go library that provides design patterns and utilities for building AI Agents using the OpenAI Go SDK with Docker Model Runner and Docker MCP Toolkit.

Rather than hiding the OpenAI SDK, Robby enhances your development experience with convenient patterns while preserving full access to the underlying SDK functionality.

✨ Features

  • 🚀 Simple Agent Creation - Minimal boilerplate with powerful configuration options
  • 💬 Streaming & Non-Streaming Chat - Real-time responses with callback support
  • 🧠 Conversational Memory - Built-in patterns for maintaining conversation context
  • 🔧 Tool Integration - Easy function calling with custom tool implementations
  • 🐳 MCP Protocol Support - Seamless integration with Model Context Protocol services
  • 📋 Structured Output - JSON schema validation for reliable data extraction
  • ⚡ Docker Model Runner - Local LLM execution without external API dependencies
  • 🛠️ Developer Friendly - Comprehensive examples and clear documentation

🚀 Quick Start

Prerequisites
  1. Docker Model Runner - Installation Guide
  2. Go 1.24+ - Download Go
  3. Compatible Model - Any model supported by Docker Model Runner
Installation
go get github.com/sea-monkeys/robby@v0.0.1
Basic Usage
package main

import (
    "context"
    "fmt"

    "github.com/openai/openai-go"
    "github.com/sea-monkeys/robby"
)

func main() {
    // Create an AI agent
    bob, err := robby.NewAgent(
        robby.WithDMRClient(
            context.Background(),
            "http://model-runner.docker.internal/engines/llama.cpp/v1/",
        ),
        robby.WithParams(
            openai.ChatCompletionNewParams{
                Model: "ai/qwen2.5:latest",
                Messages: []openai.ChatCompletionMessageParamUnion{
                    openai.SystemMessage("You are a helpful assistant"),
                    openai.UserMessage("What is the capital of France?"),
                },
                Temperature: openai.Opt(0.7),
            },
        ),
    )
    if err != nil {
        panic(err)
    }

    // Get a response
    response, err := bob.ChatCompletion()
    if err != nil {
        panic(err)
    }

    fmt.Println("Assistant:", response)
}

📚 Examples & Recipes

Explore comprehensive examples in the recipes/ directory:

Recipe Description Key Features
01 - Simple Chat Basic chat completion Agent creation, single response
02 - Streaming Chat Real-time streaming responses Live content delivery, callbacks
03 - Memory Management Conversation context handling Multi-turn conversations, history
04 - JSON Output Structured data extraction Schema validation, data parsing
05 - Tool Calls Custom function execution Function calling, parallel execution
06 - MCP Integration External service integration Web fetching, API calls, file operations

🔧 Core Concepts

Agent Configuration

Robby uses a functional options pattern for clean, flexible configuration:

agent, err := robby.NewAgent(
    // Docker Model Runner client
    robby.WithDMRClient(ctx, "http://model-runner.docker.internal/engines/llama.cpp/v1/"),
    
    // Chat parameters
    robby.WithParams(openai.ChatCompletionNewParams{
        Model: "ai/qwen2.5:latest",
        Messages: messages,
        Temperature: openai.Opt(0.7),
    }),
    
    // Custom tools
    robby.WithTools(customTools),
    
    // MCP integration
    robby.WithMCPClient(robby.WithDockerMCPToolkit()),
    robby.WithMCPTools([]string{"fetch", "brave_web_search"}),
)
Streaming Responses

Enhance user experience with real-time content delivery:

response, err := agent.ChatCompletionStream(func(self *robby.Agent, content string, err error) error {
    if err != nil {
        return err
    }
    fmt.Print(content) // Display content as it arrives
    return nil
})
Function Calling

Enable your agent to execute custom functions:

// Define tools
calculatorTool := openai.ChatCompletionToolParam{
    Function: openai.FunctionDefinitionParam{
        Name: "calculate",
        Description: openai.String("Perform mathematical calculations"),
        Parameters: openai.FunctionParameters{
            "type": "object",
            "properties": map[string]interface{}{
                "expression": map[string]string{
                    "type": "string",
                    "description": "Math expression to evaluate",
                },
            },
            "required": []string{"expression"},
        },
    },
}

// Create agent with tools
agent, _ := robby.NewAgent(
    robby.WithDMRClient(ctx, baseURL),
    robby.WithParams(params),
    robby.WithTools([]openai.ChatCompletionToolParam{calculatorTool}),
)

// Detect tool calls
toolCalls, err := agent.ToolsCompletion()

// Execute tools
results, err := agent.ExecuteToolCalls(map[string]func(any) (any, error){
    "calculate": func(args any) (any, error) {
        expression := args.(map[string]any)["expression"].(string)
        // Implement calculation logic
        return evaluateExpression(expression), nil
    },
})
MCP Integration

Connect to external services through Model Context Protocol:

agent, _ := robby.NewAgent(
    robby.WithDMRClient(ctx, baseURL),
    robby.WithParams(params),
    robby.WithMCPClient(robby.WithDockerMCPToolkit()),
    robby.WithMCPTools([]string{"fetch", "brave_web_search"}),
)

// Agent can now use web search and HTTP fetching
toolCalls, _ := agent.ToolsCompletion()
results, _ := agent.ExecuteMCPToolCalls()

🛠️ Advanced Features

Conversation Memory

Maintain context across multiple exchanges:

// Add assistant response to conversation history
agent.Params.Messages = append(agent.Params.Messages, openai.AssistantMessage(response))

// Continue the conversation
agent.Params.Messages = append(agent.Params.Messages, openai.UserMessage("Tell me more about that"))
Structured Output

Extract structured data using JSON schemas:

schema := map[string]any{
    "type": "object",
    "properties": map[string]any{
        "name": map[string]any{"type": "string"},
        "age": map[string]any{"type": "number"},
        "skills": map[string]any{
            "type": "array",
            "items": map[string]any{"type": "string"},
        },
    },
}

params := openai.ChatCompletionNewParams{
    Model: "ai/qwen2.5:latest",
    Messages: messages,
    ResponseFormat: openai.ChatCompletionNewParamsResponseFormatUnion{
        OfJSONSchema: &openai.ResponseFormatJSONSchemaParam{
            JSONSchema: schemaParam,
        },
    },
}
Tool Call Debugging

Monitor and debug tool interactions:

toolCalls, _ := agent.ToolsCompletion()

// Convert to JSON for inspection
toolCallsJSON, _ := agent.ToolCallsToJSON()
fmt.Println("Tool Calls:", toolCallsJSON)

// Or use the standalone function
jsonStr, _ := robby.ToolCallsToJSONString(toolCalls)

🐳 Docker Integration

Docker Model Runner Connection

The connection URL depends on where your application is running:

🐳 Application running in a container (DevContainer, Docker, etc.):

robby.WithDMRClient(
    context.Background(),
    "http://model-runner.docker.internal/engines/llama.cpp/v1/",
)

💻 Application running directly on your machine:

robby.WithDMRClient(
    context.Background(),
    "http://localhost:12434/engines/v1",
)
Docker MCP Toolkit Connection

Robby provides two methods to connect to Docker MCP Toolkit:

Uses Docker container with Alpine/socat to establish the connection:

agent, _ := robby.NewAgent(
    robby.WithDMRClient(ctx, baseURL),
    robby.WithParams(params),
    robby.WithMCPClient(robby.WithDockerMCPToolkit()), // Uses Docker container
    robby.WithMCPTools([]string{"fetch", "brave_web_search"}),
)

Advantages:

  • No local dependencies required
  • Works in any Docker environment
  • Self-contained solution

Requirements:

  • Docker must be available
  • Docker MCP Toolkit running on host.docker.internal:8811
Option 2: WithSocatMCPToolkit()

Uses local socat command for direct connection:

agent, _ := robby.NewAgent(
    robby.WithDMRClient(ctx, baseURL),
    robby.WithParams(params),
    robby.WithMCPClient(robby.WithSocatMCPToolkit()), // Uses local socat
    robby.WithMCPTools([]string{"fetch", "brave_web_search"}),
)

Advantages:

  • Faster connection (no Docker overhead)
  • Direct system integration
  • Ideal for dockerizing your agent application (avoids Docker-in-Docker complexity)

Requirements:

  • socat must be installed on your system
  • Docker MCP Toolkit running on host.docker.internal:8811

Installing socat:

# macOS
brew install socat

# Ubuntu/Debian
sudo apt-get install socat

# Alpine Linux
apk add socat

📖 API Documentation

Core Types
  • Agent - Main agent structure with context, client, and configuration
  • AgentOption - Functional option for agent configuration
  • STDIOCommandOption - Command configuration for MCP integration
Key Methods
  • NewAgent(options ...AgentOption) - Create configured agent instance
  • ChatCompletion() - Single response completion
  • ChatCompletionStream(callback) - Streaming response with callbacks
  • ToolsCompletion() - Detect tool calls from model response
  • ExecuteToolCalls(implementations) - Execute custom tool functions
  • ExecuteMCPToolCalls() - Execute MCP protocol tools

For complete API documentation, see our detailed function reference.

🧪 Testing

Run the test suite:

# Basic functionality tests
./simple.tools.tests.sh

# Chat functionality tests  
./chat.tests.sh

# MCP integration tests
./agent.mcp.tests.sh

# Tool call JSON formatting tests
./tool.call.json.test.sh

🎯 Use Cases

Robby is perfect for:

  • Chatbots & Virtual Assistants - Build conversational AI with memory and tools
  • Content Generation - Create articles, summaries, and structured content
  • Data Processing - Extract and transform unstructured data into JSON
  • API Integration - Connect AI agents to external services and databases
  • Workflow Automation - Automate complex multi-step processes
  • Research Assistants - Web search, data analysis, and report generation

🚧 Development Status

Robby is currently in v0.0.1 - early development phase. The API may change as we gather feedback and add features.

Planned Features:

  • Enhanced error handling and recovery
  • Built-in RAG (Retrieval Augmented Generation) support
  • Advanced conversation management
  • More MCP integrations

🤝 Contributing

We welcome contributions! Here's how you can help:

  1. 🐛 Bug Reports - Create detailed issues with reproduction steps
  2. ✨ Feature Requests - Suggest new capabilities and improvements
  3. 📖 Documentation - Improve examples, guides, and API docs
  4. 🧪 Testing - Add test cases and improve coverage
  5. 💡 Examples - Contribute new recipes and use cases
Development Setup
  1. Clone the repository:

    git clone https://github.com/sea-monkeys/robby.git
    cd robby
    
  2. Start development environment:

    # Using DevContainer (recommended)
    code . # Open in VS Code with DevContainer
    
    # Or manually
    go mod download
    
  3. Run tests:

    go test ./...
    

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🙏 Acknowledgments

  • OpenAI - For the excellent Go SDK that powers our chat completions
  • Docker - For Docker Model Runner and MCP Toolkit that enable local AI execution
  • Community - For feedback, contributions, and real-world testing

📬 Support & Community

  • Documentation - Explore the recipes/ directory for examples
  • Issues - Report bugs and request features on GitHub Issues
  • Discussions - Join community discussions and get help
  • Examples - Check out real-world implementations in our recipe collection

Built with ❤️ by the Sea Monkeys team

Robby: Making AI agent development simple, powerful, and fun!

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ToolCallsToJSONString

func ToolCallsToJSONString(tools []openai.ChatCompletionMessageToolCall) (string, error)

Types

type Agent

type Agent struct {
	Params openai.ChatCompletionNewParams

	Tools     []openai.ChatCompletionToolParam
	ToolCalls []openai.ChatCompletionMessageToolCall
	// contains filtered or unexported fields
}

func NewAgent

func NewAgent(options ...AgentOption) (*Agent, error)

func (*Agent) ChatCompletion

func (agent *Agent) ChatCompletion() (string, error)

func (*Agent) ChatCompletionStream

func (agent *Agent) ChatCompletionStream(callBack func(self *Agent, content string, err error) error) (string, error)

func (*Agent) ExecuteMCPToolCalls

func (agent *Agent) ExecuteMCPToolCalls() ([]string, error)

func (*Agent) ExecuteToolCalls

func (agent *Agent) ExecuteToolCalls(toolsImpl map[string]func(any) (any, error)) ([]string, error)

func (*Agent) ToolCallsToJSON added in v0.0.1

func (agent *Agent) ToolCallsToJSON() (string, error)

func (*Agent) ToolsCompletion

func (agent *Agent) ToolsCompletion() ([]openai.ChatCompletionMessageToolCall, error)

type AgentOption

type AgentOption func(*Agent)

func WithDMRClient

func WithDMRClient(ctx context.Context, baseURL string) AgentOption

func WithMCPClient

func WithMCPClient(command STDIOCommandOption) AgentOption

func WithMCPTools

func WithMCPTools(tools []string) AgentOption

func WithParams

func WithParams(params openai.ChatCompletionNewParams) AgentOption

func WithTools

func WithTools(tools []openai.ChatCompletionToolParam) AgentOption

type STDIOCommandOption

type STDIOCommandOption []string

func WithDockerMCPToolkit

func WithDockerMCPToolkit() STDIOCommandOption

func WithSocatMCPToolkit

func WithSocatMCPToolkit() STDIOCommandOption

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL