SwarmGo

repository·master·Indexed 18 days ago

https://github.com/prathyushnallamothu/swarmgo

A lightweight Go framework for building AI agent systems inspired by OpenAI's Swarm. SwarmGo focuses on agent coordination through Agents and Handoffs to create scalable multi-agent workflows. It supports multiple LLM providers including OpenAI and Gemini, and provides orchestration patterns such as Supervisor, Hierarchical, and Collaborative workflows. Key features include concurrent agent execution, dynamic instructions via InstructionsFunc, a memory system for conversation management, and a builder pattern for agent configuration.

Tokens
14.3K
Snippets
54
Records
57
Agent score
62%

What's inside swarmgo

  1. Use the Hierarchical Workflow for complex task decomposition

    master

    The HierarchicalWorkflow uses a tree-like structure where tasks flow from top to bottom through multiple levels of specialized agents. This is ideal for sequential processing pipelines, clear reporting structures, and decomposing complex tasks into smaller, specialized roles.

    workflow := swarmgo.NewWorkflow(apiKey, llm.OpenAI, swarmgo.HierarchicalWorkflow)
    
    // Add agents to teams
    workflow.AddAgentToTeam(managerAgent, swarmgo.SupervisorTeam)
    workflow.AddAgentToTeam(researchAgent, swarmgo.ResearchTeam)
    workflow.AddAgentToTeam(analysisAgent, swarmgo.AnalysisTeam)
    
    // Connect agents in hierarchy
    workflow.ConnectAgents(managerAgent.Name, researchAgent.Name)
    workflow.ConnectAgents(researchAgent.Name, analysisAgent.Name)
  2. How Agents work in SwarmGo

    master

    An Agent is a core abstraction representing an AI assistant. It is defined by three primary fields:

    • Name: A unique identifier (no spaces or special characters).
    • Instructions: The system prompt that guides the agent's behavior.
    • Model: The specific LLM model to use (e.g., gpt-4o).

    Agents can also be extended with Functions (tools) and InstructionsFunc for dynamic prompting.

    agent := &swarmgo.Agent{
    	Name:         "Agent",
    	Instructions: "You are a helpful assistant.",
    	Model:        "gpt-4o",
    }
  3. How workflows coordinate multiple agents

    master

    Workflows in SwarmGo act as an orchestration layer to organize and coordinate multiple agents. They define communication paths, establish hierarchies, and manage how agents collaborate to accomplish complex tasks.

    Workflows provide several key capabilities:

    • Team Management: Organizing agents into functional teams.
    • Leadership Roles: Designating specific agents as leaders for coordination.
    • Flexible Routing: Enabling dynamic task routing between agents.
    • Cycle Detection: Built-in mechanisms to detect and handle circular agent communications.
    • State Management: Sharing state across different agents within the workflow.
    • Error Handling: Robust recovery and error management during agent interactions.
  4. Implement Agent Handoffs

    master

    Handoffs allow one agent to delegate a conversation to another agent. To implement a handoff, define a function that returns a swarmgo.Result containing the target Agent and a descriptive Value message.

    func transferToAnotherAgent(args map[string]interface{}, contextVariables map[string]interface{}) swarmgo.Result {
    	anotherAgent := &swarmgo.Agent{
    		Name:         "AnotherAgent",
    		Instructions: "You are another agent.",
    		Model:        "gpt-3.5-turbo",
    	}
    	return swarmgo.Result{
    		Agent: anotherAgent,
    		Value: "Transferring to AnotherAgent.",
    	}
    }
    
    // Register the handoff function
    agent.Functions = append(agent.Functions, swarmgo.AgentFunction{
    	Name:        "transferToAnotherAgent",
    	Description: "Transfer the conversation to AnotherAgent.",
    	Parameters: map[string]interface{}{
    		"type":       "object",
    		"properties": map[string]interface{}{},
    	},
    	Function: transferToAnotherAgent,
    })
  5. Use the Collaborative Workflow for peer-based problem solving

    master

    The CollaborativeWorkflow is a peer-based pattern where agents work together as equals, passing tasks between one another. This pattern is best suited for parallel processing, iterative refinement, and dynamic task sharing within a team.

    workflow := swarmgo.NewWorkflow(apiKey, llm.OpenAI, swarmgo.CollaborativeWorkflow)
    
    // Add agents to document team
    workflow.AddAgentToTeam(editor, swarmgo.DocumentTeam)
    workflow.AddAgentToTeam(reviewer, swarmgo.DocumentTeam)
    workflow.AddAgentToTeam(writer, swarmgo.DocumentTeam)
    
    // Connect agents in collaborative pattern
    workflow.ConnectAgents(editor.Name, reviewer.Name)
    workflow.ConnectAgents(reviewer.Name, writer.Name)
    workflow.ConnectAgents(writer.Name, editor.Name)
  6. Manage Agent Memory

    master

    SwarmGo provides a memory system for storing and retrieving information. It supports automatic management of conversations and tool calls, as well as explicit memory storage with importance scoring and type categorization.

    // Explicitly store a memory
    memory := swarmgo.Memory{
        Content:    "User prefers dark mode",
        Type:       "preference",
        Context:    map[string]interface{}{"setting": "ui"},
        Timestamp:  time.Now(),
        Importance: 0.8,
    }
    agent.Memory.AddMemory(memory)
    
    // Retrieve memories
    recentMemories := agent.Memory.GetRecentMemories(5)
    preferences := agent.Memory.SearchMemories("preference", nil)
  7. Use the Supervisor Workflow for task delegation

    master

    The SupervisorWorkflow is a hierarchical pattern where a single supervisor agent oversees and coordinates tasks among worker agents. Use this pattern for centralized decision making, quality control, resource allocation, and monitoring worker tasks.

    To implement this, use swarmgo.SupervisorWorkflow when creating the workflow, assign agents to swarmgo.SupervisorTeam and swarmgo.WorkerTeam, and use SetTeamLeader to designate the supervisor.

    workflow := swarmgo.NewWorkflow(apiKey, llm.OpenAI, swarmgo.SupervisorWorkflow)
    
    // Add agents to teams
    workflow.AddAgentToTeam(supervisorAgent, swarmgo.SupervisorTeam)
    workflow.AddAgentToTeam(workerAgent1, swarmgo.WorkerTeam)
    workflow.AddAgentToTeam(workerAgent2, swarmgo.WorkerTeam)
    
    // Set supervisor as team leader
    workflow.SetTeamLeader(supervisorAgent.Name, swarmgo.SupervisorTeam)
    
    // Connect agents
    workflow.ConnectAgents(supervisorAgent.Name, workerAgent1.Name)
    workflow.ConnectAgents(supervisorAgent.Name, workerAgent2.Name)
  8. Quick Start with SwarmGo

    master

    This example demonstrates how to initialize a Swarm client using OpenAI, create a basic agent, and run a single conversation turn.

    package main
    
    import (
    	"context"
    	"fmt"
    	"log"
    
    	swarmgo "github.com/prathyushnallamothu/swarmgo"
    	openai "github.com/sashabaranov/go-openai"
    	llm "github.com/prathyushnallamothu/swarmgo/llm"
    )
    
    func main() {
    	client := swarmgo.NewSwarm("YOUR_OPENAI_API_KEY", llm.OpenAI)
    
    	agent := &swarmgo.Agent{
    		Name:         "Agent",
    		Instructions: "You are a helpful assistant.",
    		Model:        "gpt-3.5-turbo",
    	}
    
    	messages := []openai.ChatCompletionMessage{
    		{Role: "user", Content: "Hello!"},
    	}
    
    	ctx := context.Background()
    	response, err := client.Run(ctx, agent, messages, nil, "", false, false, 5, true)
    	if err != nil {
    		log.Fatalf("Error: %v", err)
    	}
    
    	fmt.Println(response.Messages[len(response.Messages)-1].Content)
    }
  9. Define and add Functions (Tools) to an Agent

    master

    Agents can perform tasks by executing functions. To add a tool, you must define a function that matches the swarmgo.Result return type and then register it in the agent's Functions slice using an AgentFunction struct.

    // 1. Define the function logic
    func getWeather(args map[string]interface{}, contextVariables map[string]interface{}) swarmgo.Result {
    	location := args["location"].(string)
    	return swarmgo.Result{
    		Value: fmt.Sprintf(`{"temp": 67, "unit": "F", "location": "%s"}`, location),
    	}
    }
    
    // 2. Add the function to the agent
    agent.Functions = []swarmgo.AgentFunction{
    	{
    		Name:        "getWeather",
    		Description: "Get the current weather in a given location.",
    		Parameters: map[string]interface{}{
    			"type": "object",
    			"properties": map[string]interface{}{
    				"location": map[string]interface{}{
    					"type":        "string",
    					"description": "The city to get the weather for.",
    				},
    			},
    			"required": []interface{}{"location"},
    		},
    		Function: getWeather,
    	},
    }
  10. How StreamHandler works with StreamingResponse

    master

    The StreamHandler is the primary way to consume the output of a StreamingResponse. Because StreamingResponse manages the loop of receiving tokens and handling tool calls, the handler acts as a callback mechanism.

    When an agent decides to use a tool:

    1. StreamingResponse accumulates the tool arguments.
    2. Once the JSON arguments are complete, the function is executed.
    3. OnToolCall is triggered with the completed llm.ToolCall.
    4. A new stream is created to process the LLM's response to the tool's output.

    This ensures that your UI or consumer can show text as it arrives and react immediately when a tool is invoked.

  11. Manage workflow state with GraphState

    master

    The GraphState type is a map used to carry data through the workflow graph. It allows nodes to read and update shared information.

    Key capabilities:

    • Cloning: Use .Clone() to create a deep copy of the state, which is essential when branching or running parallel processes to avoid side effects.
    • Updating: Use .UpdateState(updates GraphState) to merge new values into the existing state.
    • Type-safe retrieval: Use .GetString(key) and .GetBool(key) for common types, or .Get(key) for generic interface retrieval.

    By default, the key messages (of type MessageKey) is used to store the conversation history ([]llm.Message).

    // Example of state manipulation
    state := swarmgo.GraphState{
        swarmgo.MessageKey: []llm.Message{...},
        "user_id": "12345",
    }
    
    // Retrieve values
    userID, ok := state.GetString("user_id")
    
    // Update state
    newState := state.Clone()
    newState.UpdateState(swarmgo.GraphState{"status": "processing"})