swarmlet

package module
v0.0.1 Latest Latest
Warning

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

Go to latest
Published: Jul 26, 2025 License: MIT Imports: 9 Imported by: 0

README

🐝 Swarmlet

Swarmlet is a lightweight Go framework for building and orchestrating intelligent, multi-agent systems. Inspired by swarm intelligence, it enables agents to think, communicate, use tools, and coordinate workflows — all in a composable and scalable way.

Whether you're building autonomous assistants, workflow managers, or AI-powered backend services, Swarmlet gives you the foundation to define agents, assign tools, plug in memory or LLMs, and orchestrate complex multi-step plans with ease.

✨ Key Features

  • Composable Agent Architecture: Create agents with custom behavior, memory, and tool access using a node-based system.

  • LLM Integration: Seamlessly plug in Large Language Models (LLMs) for reasoning and language-based action. Currently supports OpenAI, with plans for expansion.

  • Powerful Tool System: Define custom tools with structured inputs and outputs, then assign them to agents for real-world interaction and data fetching.

  • Augmented LLM Node: An advanced node that allows LLMs to iteratively call tools based on their reasoning, mimicking autonomous agent behavior.

  • Flexible Workflows (Pipelines): Chain different nodes together to create sophisticated multi-step agentic workflows.

  • Memory & Context Management: Built-in support for managing conversation history and context within a run.

  • Extensible Design: Designed with interfaces (LLM, Memory, WorkflowNode) for easy integration of custom components and future capabilities.

🚀 Getting Started

To start experimenting with Swarmlet, just grab the module:

go get github.com/luisya22/swarmlet@v0.0.1

Prerequisites

  • Go 1.22+
  • OpenAI API Key: For running examples that interact with OpenAI models. Set is as an environment variable: LLM_API_KEY.
export LLM_API_KEY="your-openai-api-key-here"

💡 Usage Examples

Swarmlet's power comes from chaining different types of nodes. Here are a few examples to get you started. You cand find the full code for these in the ./examples directory.

  1. Simple LLM Call Run a single LLM request.
// examples/simple_call/main.go
package main

import (
	"log"
	"os"

	"github.com/luisya22/swarmlet"
)

func main() {
	// An OutputNode makes the result visible
	output := swarmlet.NewOutputNode("output", "1", true)
	
	// Define a simple LLMCallNode
	node1 := swarmlet.NewLLmCallNode(
		swarmlet.WithID("1"),
		swarmlet.WithChildren(output),
		swarmlet.WithSystemPrompt("You are a helpful assistant."),
	)

	// Set up your LLM and memory (dummy for now)
	apiKey := os.Getenv("LLM_API_KEY")
	llm := swarmlet.NewOpenAILLM(apiKey, "gpt-4o-mini")
	memory := swarmlet.NewDummyMemory()

	// Create and run the pipeline
	pipeline := swarmlet.NewPipeline("SimplePipeline", node1, llm, memory)
	_, err := pipeline.Run(context.Background(), "Tell me a fun fact about Go programming language.", "run-id-123", os.Stdout)
	if err != nil {
		log.Fatal(err)
	}
}
  1. Chained LLM Calls (Simple Workflow) Connect multiple LLM nodes where the output of one becomes the input for the next.
// examples/chained_call/main.go (Simplified for brevity in README)
// ...
func main() {
	output := swarmlet.NewOutputNode("output", "2", true) // Output from Node 2
	
	node1 := swarmlet.NewLLmCallNode(
		swarmlet.WithID("1"),
		swarmlet.WithChildren(output), // Node 1 passes its output to the OutputNode
		swarmlet.WithSystemPrompt("You are a temperature expert. I will give you a temperature in Celsius and you will return it in Fahrenheit. Return just a simple string with the temperature."),
	)
	node2 := swarmlet.NewLLmCallNode(
		swarmlet.WithID("2"),
		swarmlet.WithChildren(node1), // Node 2 passes its output to Node 1
		swarmlet.WithSystemPrompt("You are a temperature expert. Give me a plain string of the average temperature in this city in Celsius."),
	)
	node3 := swarmlet.NewLLmCallNode(
		swarmlet.WithID("3"),
		swarmlet.WithChildren(node2), // Node 3 passes its output to Node 2
		swarmlet.WithSystemPrompt("You are a reverser agent. Return a plain message string of the reversed input"),
	)
	// ... (LLM, Memory, Pipeline setup similar to simple_call)
	// Input: "RP, nauJ naS" (Reversed "San Juan, PR")
	_, err := pipeline.Run("RP, nauJ naS", "102", stdWriter)
	// ...
}
  1. Augmented LLM With Tools Showcases the AugmentedLLMNode where the LLM Can dynamically call user-defined tools.
// examples/tool_call/main.go (Simplified for brevity in README)
// ...
func main() {
	tools := []swarmlet.LLMTool{
		{
			Name:        "get_temperature",
			Description: "Get temperature from any country or city.",
			Params: map[string]swarmlet.LLMToolFieldProperty{
				"location": { // Renamed 'name' to 'location' for clarity
					Type:        "string",
					Description: "The name of the country or city to get the temperature for.",
				},
			},
			Executor: func(args map[string]any) (string, error) {
				// In a real scenario, this would call an external API
				location := args["location"].(string)
				log.Printf("Executing tool 'get_temperature' for: %s", location)
				if location == "Nebraska" {
					return "Current temperature in Nebraska is 75 degrees Fahrenheit.", nil
				}
				return "Temperature data not available for " + location, nil
			},
		},
	}

	output := swarmlet.NewOutputNode("output", "1", true)

	node1 := swarmlet.NewAugmentedLLMNode(
		swarmlet.WithAugmentedID("1"),
		swarmlet.WithAugmentedChildren(output),
		swarmlet.WithAugmentedTools(tools...),
	)

	// ... (LLM, Memory, Pipeline setup similar to simple_call)
	_, err := pipeline.Run(context.Background(), "What is the temperature in Nebraska?", "102", os.Stdout)
	// ...
}

🗺️ Roadmap & Future Plans

Swarmlet is currently in its early stages (v0.0.1), and there's a lot more planned to make it a robust and versatile framework for agentic AI:

  • Memory Management: Implementing more sophisticated memory systems beyond basic context (e.g, vector databases for RAG).
  • Data Retrieval: Enhanced capabilities for agents to retrieve and process information from various sources.
  • Routing Nodes: Nodes that intelligently route inputs different workflows or agents based on content.
  • Orchestrators: Higher-level components for dynaimc, complex multi-agent coordination and task planning.
  • Concurrent LLM Calls: Support for running multiple LLM interactions in parallel for efficiency.
  • More LLM Integrations: Expanding beyond OpenAI to include other popular LLM providers.

🤝 Contributing

Swarmlet is an open-source project, and contributions are welcome! Feel free to open issues, submit pull requests, or suggest new features.

📄 License

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

Documentation

Index

Constants

View Source
const DefaultAugmentedSystemPrompt = `` /* 1674-byte string literal not displayed */

Variables

This section is empty.

Functions

func NewOpenAILLM

func NewOpenAILLM(apiKey string, model string) *openAILLM

Types

type AgentContext

type AgentContext struct {
	LLM    LLM
	Memory Memory
}

type AgenticLLMNode

type AgenticLLMNode struct {
	InitialPropmtTemplate string
	MaxIterations         int
}

type AugmentedLLMNode

type AugmentedLLMNode struct {
	BaseNode

	LLMOptions LLMOptions

	Children []WorkflowNode
	// contains filtered or unexported fields
}

func NewAugmentedLLMNode

func NewAugmentedLLMNode(opts ...AugmentedLLMNodeOption) *AugmentedLLMNode

func (*AugmentedLLMNode) Execute

func (e *AugmentedLLMNode) Execute(ctx context.Context, agentContext AgentContext, runCtx *RunContext, nodeInput ...string) (string, error)

type AugmentedLLMNodeOption

type AugmentedLLMNodeOption func(*AugmentedLLMNode)

func WithAugmentedChildren

func WithAugmentedChildren(children ...WorkflowNode) AugmentedLLMNodeOption

func WithAugmentedID

func WithAugmentedID(id string) AugmentedLLMNodeOption

func WithAugmentedLLMOptions

func WithAugmentedLLMOptions(opts LLMOptions) AugmentedLLMNodeOption

func WithAugmentedPromptTemplate

func WithAugmentedPromptTemplate(template string) AugmentedLLMNodeOption

func WithAugmentedSystemPrompt

func WithAugmentedSystemPrompt(prompt string) AugmentedLLMNodeOption

func WithAugmentedTools

func WithAugmentedTools(tools ...LLMTool) AugmentedLLMNodeOption

type BaseNode

type BaseNode struct {
	// contains filtered or unexported fields
}

func (*BaseNode) ID

func (b *BaseNode) ID() string

func (*BaseNode) Type

func (b *BaseNode) Type() string

type DummyLLM

type DummyLLM struct{}

func (*DummyLLM) Generate

func (d *DummyLLM) Generate(propmt string, options LLMOptions) (string, error)

type DummyMemory

type DummyMemory struct {
	// contains filtered or unexported fields
}

func NewDummyMemory

func NewDummyMemory() *DummyMemory

func (*DummyMemory) Append

func (d *DummyMemory) Append(key string, value any) error

func (*DummyMemory) Get

func (d *DummyMemory) Get(key string) (any, error)

func (*DummyMemory) Set

func (d *DummyMemory) Set(key string, value any) error

type LLM

type LLM interface {
	Generate(ctx context.Context, options LLMOptions, tools []LLMTool, prompt string, messages ...LLMMessage) (LLMMessage, error)
}

type LLMCallNode

type LLMCallNode struct {
	BaseNode
	SystemPrompt   string
	PromptTemplate string
	LLMOptions     LLMOptions
	LLMTools       []LLMTool
	Children       []WorkflowNode
}

func NewLLmCallNode

func NewLLmCallNode(opts ...LLMCallOption) *LLMCallNode

func (*LLMCallNode) Execute

func (e *LLMCallNode) Execute(ctx context.Context, agentContext AgentContext, runContext *RunContext, nodeInput ...string) (string, error)

type LLMCallOption

type LLMCallOption func(*LLMCallNode)

func WithChildren

func WithChildren(children ...WorkflowNode) LLMCallOption

func WithID

func WithID(id string) LLMCallOption

func WithLLMOptions

func WithLLMOptions(opts LLMOptions) LLMCallOption

func WithPropmtTemplate

func WithPropmtTemplate(prompt string) LLMCallOption

func WithSystemPrompt

func WithSystemPrompt(prompt string) LLMCallOption

type LLMFunctionCall

type LLMFunctionCall struct {
	// contains filtered or unexported fields
}

type LLMMessage

type LLMMessage struct {
	// contains filtered or unexported fields
}

type LLMOptions

type LLMOptions struct {
	Model       string
	MaxTokens   int
	Temperature float32
}

type LLMTool

type LLMTool struct {
	Name        string
	Description string
	Params      map[string]LLMToolFieldProperty
	Executor    func(map[string]any) (string, error)
}

TODO: API to pass tools to LLM, each node could have an individual LLM Need to pass the model to the llm

type LLMToolCall

type LLMToolCall struct {
	// contains filtered or unexported fields
}

type LLMToolFieldProperty

type LLMToolFieldProperty struct {
	Type        string
	Description string
	Enum        []string
}

type Memory

type Memory interface {
	Get(key string) (any, error)
	Set(key string, value any) error
	Append(keys string, value any) error
}

type MemoryAndStreamingConfig

type MemoryAndStreamingConfig struct {
	UseMemory          bool
	MemoryKey          string
	Streaming          bool
	MaxHistoryMessages int
}

type NodeType

type NodeType int
const (
	LLM_CALL NodeType = iota
	GATE
	ROUTER
	ORCHESTRATOR
	EVALUATOR
)

type OutputNode

type OutputNode struct {
	BaseNode
	FromNode string
	Visible  bool
}

func NewOutputNode

func NewOutputNode(id string, fromNode string, visible bool) *OutputNode

func (*OutputNode) Execute

func (n *OutputNode) Execute(ctx context.Context, agentContext AgentContext, runContext *RunContext, input ...string) (string, error)

type Pipeline

type Pipeline struct {
	Name   string
	Root   WorkflowNode
	LLM    LLM
	Memory Memory
}

Holds and executes all the pipeline components

func NewPipeline

func NewPipeline(name string, rootNode WorkflowNode, llm LLM, memory Memory) *Pipeline

func (*Pipeline) Run

func (p *Pipeline) Run(ctx context.Context, initialInput string, runID string, w io.Writer) (finalOutput string, err error)

type ReverseLLM

type ReverseLLM struct{}

func (*ReverseLLM) Generate

func (d *ReverseLLM) Generate(options LLMOptions, tools []LLMTool, systemPrompt string, messages ...LLMMessage) (string, error)

type RunContext

type RunContext struct {
	RunID          string
	NodeInputs     map[string]string
	NodeOutputs    map[string]string
	NodeErrors     map[string]error
	StreamWriter   io.Writer
	MessageHistory map[string][]LLMMessage
	// contains filtered or unexported fields
}

func NewRunContext

func NewRunContext(runID string, w io.Writer) *RunContext

func (*RunContext) AddError

func (rc *RunContext) AddError(key string, err error)

func (*RunContext) AddInput

func (rc *RunContext) AddInput(key string, value string)

func (*RunContext) AddMessage

func (rc *RunContext) AddMessage(key string, value LLMMessage)

func (*RunContext) AddOutput

func (rc *RunContext) AddOutput(key string, value string)

func (*RunContext) GetError

func (rc *RunContext) GetError(key string) (error, bool)

func (*RunContext) GetInput

func (rc *RunContext) GetInput(key string) (string, bool)

func (*RunContext) GetMessages

func (rc *RunContext) GetMessages(key string) ([]LLMMessage, bool)

func (*RunContext) GetOutput

func (rc *RunContext) GetOutput(key string) (string, bool)

type WorkflowNode

type WorkflowNode interface {
	ID() string
	Execute(ctx context.Context, agentContext AgentContext, runContext *RunContext, input ...string) (string, error)
}

Directories

Path Synopsis
examples
chained_call command
simple_call command
tool_call command

Jump to

Keyboard shortcuts

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