robby

package module
v0.0.2 Latest Latest
Warning

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

Go to latest
Published: May 25, 2025 License: MIT Imports: 12 Imported by: 0

README

Robby 🤖

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

Go Version License Docker

Robby is a lightweight Go library[pattern] 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 MCP External service integration MCP tool calls
07 - MCP Integration MCP External service integration MCP tool calls with MCP Server sample
08 - RAG in memory Retrieval Augmented Generation Embeddings and Similarity search

🔧 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)

ToolCallsToJSONString converts a slice of openai.ChatCompletionMessageToolCall to a JSON string. It extracts the tool call ID and function arguments, converting them to a generic interface for JSON marshaling. The resulting JSON string is formatted with indentation for readability. If the tool calls are empty, it returns an empty JSON array. If any error occurs during the conversion, it returns an error. The function is useful for logging or storing tool calls in a structured format. It returns a JSON string representation of the tool calls.

Types

type Agent

type Agent struct {
	Params          openai.ChatCompletionNewParams
	EmbeddingParams openai.EmbeddingNewParams

	Tools     []openai.ChatCompletionToolParam
	ToolCalls []openai.ChatCompletionMessageToolCall

	Resources []Resource
	Prompts   []Prompt

	Store MemoryVectorStore
	// contains filtered or unexported fields
}

func NewAgent

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

NewAgent creates a new Agent instance with the provided options. It applies all the options to the Agent and returns it. If any option sets an error, it returns the error instead of the Agent. The Agent can be configured with various options such as DMR client, parameters, tools, and memory.

func (*Agent) ChatCompletion

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

ChatCompletion handles the chat completion request using the DMR client. It sends the parameters set in the Agent and returns the response content or an error. It is a synchronous operation that waits for the completion to finish.

func (*Agent) ChatCompletionStream

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

ChatCompletionStream handles the chat completion request using the DMR client in a streaming manner. It takes a callback function that is called for each chunk of content received. The callback function receives the Agent instance, the content of the chunk, and any error that occurred. It returns the accumulated response content and any error that occurred during the streaming process. The callback function should return an error if it wants to stop the streaming process.

func (*Agent) ExecuteMCPToolCalls

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

ExecuteMCPToolCalls executes the tool calls detected by the Agent using the MCP client. It takes no additional parameters as it uses the Agent's context and MCP client. It returns a slice of responses from the executed tools or an error if any tool call fails. It also appends the tool responses to the Agent's messages for further processing. This function is specifically designed to work with the MCP toolkit, which allows for tool calls to be executed in a remote environment using the MCP protocol. It assumes that the Agent has been initialized with an MCP client and the necessary context. The function iterates over the Agent's ToolCalls, unmarshals the arguments for each tool call, and then calls the tool using the MCP client. The responses are collected and returned. If no tool responses are found, it returns an error. It is important to ensure that the MCP client is properly configured and connected to the MCP server before calling this function, as it relies on the MCP protocol for executing tool calls. It is a synchronous operation that waits for the completion of each tool call.

func (*Agent) ExecuteToolCalls

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

ExecuteToolCalls executes the tool calls detected by the Agent. It takes a map of tool implementations where the key is the tool name and the value is a function that implements the tool. Each tool function should accept a map of arguments and return a response or an error. The function returns a slice of responses from the executed tools or an error if any tool call fails. It also appends the tool responses to the Agent's messages for further processing

func (*Agent) GetPrompt added in v0.0.2

func (agent *Agent) GetPrompt(name string, args any) (Prompt, error)

GetPrompt retrieves a prompt by its name and arguments from the MCP client. It constructs a Prompt object with the name, description, and messages. The messages are converted from the MCP format to the internal Message format. If the prompt is not found or an error occurs, it returns an error. If the prompt is found, it returns the Prompt object. It requires the MCP server to be running and accessible at the specified address.

func (*Agent) RAGMemorySearchSimilaritiesWith added in v0.0.2

func (agent *Agent) RAGMemorySearchSimilaritiesWith(embedding openai.EmbeddingNewParamsInputUnion, limit float64) ([]string, error)

RAGMemorySearchSimilaritiesWith searches for similar records in the RAG memory using the provided embedding. It creates an embedding from the input and searches for records with cosine similarity above the specified limit. It returns a slice of strings containing the prompts of the similar records and an error if any occurred. If no similar records are found, it returns an empty slice. It requires the DMR client to be initialized and the embedding parameters to be set in the Agent. The limit parameter specifies the minimum cosine similarity score for a record to be considered similar. It returns an error if the embedding creation fails or if the search operation fails.

func (*Agent) RAGMemorySearchSimilaritiesWithText added in v0.0.2

func (agent *Agent) RAGMemorySearchSimilaritiesWithText(text string, limit float64) ([]string, error)

RAGMemorySearchSimilaritiesWithText searches for similar records in the RAG memory using the provided text. It creates an embedding from the text and searches for records with cosine similarity above the specified limit. It returns a slice of strings containing the prompts of the similar records and an error if any occurred. If no similar records are found, it returns an empty slice. It requires the DMR client to be initialized and the embedding parameters to be set in the Agent. The limit parameter specifies the minimum cosine similarity score for a record to be considered similar. It returns an error if the embedding creation fails or if the search operation fails.

func (*Agent) ReadResource added in v0.0.2

func (agent *Agent) ReadResource(uri string) (Resource, error)

ReadResource retrieves a resource by its URI from the MCP client. It constructs a Resource object with the URI, MIME type, and text content. The resource name and description are searched in the agent's resources. If the resource is not found or an error occurs, it returns an error. If the resource is found, it returns the Resource object. It requires the MCP server to be running and accessible at the specified address. The resources are expected to be in the format defined by the MCP server.

func (*Agent) ReadResourceByName added in v0.0.2

func (agent *Agent) ReadResourceByName(name string) (Resource, error)

func (*Agent) ToolCallsToJSON added in v0.0.1

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

ToolCallsToJSON converts the Agent's tool calls to a JSON string. If there are no tool calls, it returns an empty JSON array. It uses the ToolCallsToJSONString function to convert the tool calls to a JSON string format.

func (*Agent) ToolsCompletion

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

ToolsCompletion handles the tool calls completion request using the DMR client. It sends the parameters set in the Agent and returns the detected tool calls or an error. It is a synchronous operation that waits for the completion to finish.

type AgentOption

type AgentOption func(*Agent)

func WithDMRClient

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

WithDMRClient initializes the Agent with a DMR client using the provided context and base URL.

func WithEmbeddingParams added in v0.0.2

func WithEmbeddingParams(embeddingParams openai.EmbeddingNewParams) AgentOption

WithEmbeddingParams sets the parameters for the Agent's embedding requests.

func WithMCPClient

func WithMCPClient(command STDIOCommandOption) AgentOption

WithMCPClient initializes the Agent with an MCP client using the provided command. It runs the command to connect to the MCP server and sets up the client transport. The command should be a valid command that can be executed in the environment where the agent runs. It returns an AgentOption that can be used to configure the agent.

func WithMCPPrompts added in v0.0.2

func WithMCPPrompts(prompts []string) AgentOption

WithMCPPrompts fetches the prompts from the MCP server and sets them in the agent. It filters the prompts based on the provided names and converts them to a Prompt format. It requires the MCP server to be running and accessible at the specified address. The prompts are expected to be in the format defined by the MCP server. It returns an AgentOption that can be used to configure the agent.

func WithMCPResources added in v0.0.2

func WithMCPResources(resources []string) AgentOption

WithMCPResources fetches the resources from the MCP server and sets them in the agent. It filters the resources based on the provided names and converts them to a Resource format. It requires the MCP server to be running and accessible at the specified address. The resources are expected to be in the format defined by the MCP server. It returns an AgentOption that can be used to configure the agent.

func WithMCPTools

func WithMCPTools(tools []string) AgentOption

WithMCPTools fetches the tools from the MCP server and sets them in the agent. It filters the tools based on the provided names and converts them to OpenAI format. It requires the MCP server to be running and accessible at the specified address. The tools are expected to be in the format defined by the MCP server. It returns an AgentOption that can be used to configure the agent. The tools are fetched using the MCP client and converted to OpenAI format.

func WithParams

func WithParams(params openai.ChatCompletionNewParams) AgentOption

WithParams sets the parameters for the Agent's chat completion requests.

func WithRAGMemory added in v0.0.2

func WithRAGMemory(chunks []string) AgentOption

WithRAGMemory initializes the Agent with a RAG memory using the provided chunks. It creates a MemoryVectorStore and saves the embeddings of the chunks into it. The chunks should be pre-processed text data that will be used for retrieval-augmented generation (RAG). It returns an AgentOption that can be used to configure the agent.

func WithTools

func WithTools(tools []openai.ChatCompletionToolParam) AgentOption

WithTools sets the tools for the Agent's chat completion requests. It allows the Agent to use specific tools during the chat completion process.

type Content added in v0.0.2

type Content struct {
	Type string `json:"type"`
	Text string `json:"text"`
}

type MemoryVectorStore added in v0.0.2

type MemoryVectorStore struct {
	Records map[string]VectorRecord
}

func (*MemoryVectorStore) GetAll added in v0.0.2

func (mvs *MemoryVectorStore) GetAll() ([]VectorRecord, error)

func (*MemoryVectorStore) Save added in v0.0.2

func (mvs *MemoryVectorStore) Save(vectorRecord VectorRecord) (VectorRecord, error)

Save saves a vector record to the MemoryVectorStore. If the record does not have an ID, it generates a new UUID for it. It returns the saved vector record and an error if any occurred during the save operation. If the record already exists, it will be overwritten.

func (*MemoryVectorStore) SearchSimilarities added in v0.0.2

func (mvs *MemoryVectorStore) SearchSimilarities(embeddingFromQuestion VectorRecord, limit float64) ([]VectorRecord, error)

SearchSimilarities searches for vector records in the MemoryVectorStore that have a cosine distance similarity greater than or equal to the given limit.

Parameters:

  • embeddingFromQuestion: the vector record to compare similarities with.
  • limit: the minimum cosine distance similarity threshold.

Returns:

  • []llm.VectorRecord: a slice of vector records that have a cosine distance similarity greater than or equal to the limit.
  • error: an error if any occurred during the search.

func (*MemoryVectorStore) SearchTopNSimilarities added in v0.0.2

func (mvs *MemoryVectorStore) SearchTopNSimilarities(embeddingFromQuestion VectorRecord, limit float64, max int) ([]VectorRecord, error)

SearchTopNSimilarities searches for the top N similar vector records based on the given embedding from a question. It returns a slice of vector records and an error if any. The limit parameter specifies the minimum similarity score for a record to be considered similar. The max parameter specifies the maximum number of vector records to return.

type Message added in v0.0.2

type Message struct {
	Role    string  `json:"role"`
	Content Content `json:"content"`
}

type Prompt added in v0.0.2

type Prompt struct {
	Name        string           `json:"name"`
	Description string           `json:"description,omitempty"`
	Arguments   []map[string]any `json:"arguments"`
	Messages    []Message        `json:"messages,omitempty"` // Optional, for storing messages related to the prompt
}

type Resource added in v0.0.2

type Resource struct {
	URI         string `json:"uri"`
	Name        string `json:"name"`
	Description string `json:"description,omitempty"`
	MimeType    string `json:"mimeType,omitempty"`
	Text        string `json:"text,omitempty"`
	Blob        string `json:"blob,omitempty"`
}

type STDIOCommandOption

type STDIOCommandOption []string

func WithDockerMCPToolkit

func WithDockerMCPToolkit() STDIOCommandOption

WithDockerMCPToolkit returns a STDIOCommandOption that runs the MCP toolkit using Docker. It uses the Alpine image with Socat to connect to the MCP server running on host.docker.internal:8811.

func WithSocatMCPToolkit

func WithSocatMCPToolkit() STDIOCommandOption

WithSocatMCPToolkit returns a STDIOCommandOption that runs the MCP toolkit using Socat. It connects to the MCP server running on host.docker.internal:8811.

type VectorRecord added in v0.0.2

type VectorRecord struct {
	Id               string    `json:"id"`
	Prompt           string    `json:"prompt"`
	Embedding        []float64 `json:"embedding"`
	CosineSimilarity float64
}

Jump to

Keyboard shortcuts

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