arboreal

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Sep 23, 2025 License: BSD-3-Clause-Clear Imports: 34 Imported by: 0

README

Arboreal

Arboreal is a Go framework for building agentic AI systems using behavior trees and LLM integration. It provides a structured way to create complex AI workflows with planning, execution, and state management capabilities.

Features

  • Behavior Trees: Define complex AI behaviors using composable behavior trees
  • LLM Integration: Built-in support for OpenAI, Anthropic, and Ollama models
  • Planning & Execution: TodoListExecutive for autonomous task planning and execution
  • State Management: Persistent state handling with snapshots and memory
  • Vector Search: SQLite-vec integration for semantic search and retrieval
  • Lua Scripting: Extensible runtime with Lua scripting support
  • Annotation System: Rich message annotation and templating

Quick Start

Installation
go get github.com/zenful-ai/arboreal
Basic Example
package main

import "github.com/zenful-ai/arboreal"

func main() {
    // Create a behavior tree for a chat bot
    chatBehavior := arboreal.CreateBehaviorTree(
        "chat_behavior",
        "A conversational bot",
        "<insert user's input here>",
    )

    // Define states
    chatState := arboreal.LLMCompletionState(arboreal.LLMCompletionOptions{})
    pauseState := arboreal.PauseState("Let user respond")

    // Add transitions
    chatBehavior.AddTransition(&chatState, &pauseState)

    // Create executive
    exec := arboreal.CreateTodoListExecutive(
        "Chat Bot",
        "Simple chat bot",
        &chatBehavior,
    )

    // Run the bot
    err := exec.RunLoop(arboreal.TerminalChannel{})
    if err != nil {
        panic(err)
    }
}

Core Concepts

Behavior Trees

Behavior trees define the logic flow of your AI agent. They consist of states and transitions:

behavior := arboreal.CreateBehaviorTree("name", "description", "example")

// Add states
state1 := arboreal.LLMCompletionState(arboreal.LLMCompletionOptions{
    System: "You are a helpful assistant",
})
state2 := arboreal.PauseState("Wait for user input")

// Connect states
behavior.AddTransition(&state1, &state2)
TodoListExecutive

The TodoListExecutive provides autonomous planning and execution capabilities:

exec := arboreal.CreateTodoListExecutive("Agent Name", "Description", behaviors...)
exec.MaxPlanDepth = 5  // Configure planning depth
exec.Preamble = "You are a helpful AI assistant"
LLM Integration

Arboreal supports multiple LLM providers through environment variables:

export OPENAI_TOKEN=your_openai_key
export ANTHROPIC_TOKEN=your_anthropic_key
export OLLAMA_SERVICE_URL=http://localhost:11434

Advanced Features

Memory and Persistence
// Save agent state
snapshot := arboreal.CreateSnapshot(behaviors...)
data := snapshot.Serialize()

// Restore agent state
snapshot, err := arboreal.DeserializeSnapshot(data)
Vector Search and RAG
// Semantic chunking and storage
chunks := arboreal.SemanticChunk(content, maxTokens)
// Store in vector database for retrieval
Custom Channels

Implement custom communication channels:

type CustomChannel struct {
    // Your implementation
}

func (c CustomChannel) Send(message string) error {
    // Send message through your channel
    return nil
}

func (c CustomChannel) Receive() (string, error) {
    // Receive message from your channel
    return "", nil
}

Configuration

Environment Variables
Variable Description Required
OPENAI_TOKEN OpenAI API key For OpenAI models
ANTHROPIC_TOKEN Anthropic API key For Claude models
OLLAMA_SERVICE_URL Ollama service URL For local models
TWILIO_ACCOUNT_SID Twilio account SID For SMS channel
TWILIO_AUTH_TOKEN Twilio auth token For SMS channel
Model Configuration
// Configure LLM options
options := arboreal.LLMCompletionOptions{
    Model:       llm.GPT4o,  // or llm.Claude3Sonnet, etc.
    Temperature: 0.7,
    MaxTokens:   1000,
    System:      "System prompt",
}

Examples

The examples/ directory contains various use cases:

  • Chat Bot (examples/test/) - Basic conversational agent
  • CRM Assistant (examples/crm/) - Customer relationship management

Contributing

We welcome contributions! Please see our Contributing Guidelines for details.

Project Structure
├── README.md           # This file
├── go.mod             # Go module definition
├── *.go               # Core framework files
├── llm/               # LLM provider integrations
├── examples/          # Example applications
├── engine/            # Lua scripting engine (see engine/README.md)
└── util/              # Utility functions

License

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

Roadmap

  • Vector store re-implementation
  • More LLM provider integrations
  • Enhanced debugging tools
  • Better documentation
  • Enhanced testing coverage
  • Performance optimizations

Support

Documentation

Index

Constants

View Source
const (
	ProfileTypeEmulator = "emulator"
	ProfileTypeChat     = "chat"
	ProfileTypeEmbedded = "embedded"
)
View Source
const (
	MCPServerTypeSSE     = "sse"
	MCPServerTypeMemory  = "mem"
	MCPServerTypeCommand = "cmd"
)
View Source
const (
	StateErrorTypeUnknown       = "unknown"
	StateErrorTypeRetryable     = "retryable"
	StateErrorTypeUnrecoverable = "unrecoverable"
	StateErrorTypeLuaSyntax     = "lua_syntax"
)
View Source
const (
	TraceMessageTypeLuaSource = "lua_source"
	TraceMessageTypeCallBegin = "begin_call"
	TraceMessageTypeCallEnd   = "end_call"
)
View Source
const (
	DefaultMaxPlanDepth = 3
)

Variables

This section is empty.

Functions

func CosineSimilarity

func CosineSimilarity(vec1, vec2 []float32) float64

func GenerateStringIdentifier

func GenerateStringIdentifier(prefix string, length int) (string, error)

GenerateStringIdentifier generates a random string of a given length and prefix.

func MonotonicIdGenerator

func MonotonicIdGenerator(prefix string) func() string

Types

type AnnotatedMessage

type AnnotatedMessage struct {
	llm.ChatCompletionMessage
	Annotations map[string]Annotation
}

type AnnotatedMessages

type AnnotatedMessages []AnnotatedMessage

func AppendToMessages

func AppendToMessages(messages AnnotatedMessages, message llm.ChatCompletionMessage) AnnotatedMessages

func (AnnotatedMessages) AddTraceInformation

func (a AnnotatedMessages) AddTraceInformation(name string)

func (AnnotatedMessages) ChatCompletionMessages

func (a AnnotatedMessages) ChatCompletionMessages() (m []llm.ChatCompletionMessage)

func (AnnotatedMessages) FlattenedAnnotations

func (a AnnotatedMessages) FlattenedAnnotations() map[string]Annotation

func (AnnotatedMessages) GetAnnotation

func (a AnnotatedMessages) GetAnnotation(name string) *Annotation

func (AnnotatedMessages) LastMessage

func (a AnnotatedMessages) LastMessage() *AnnotatedMessage

type Annotation

type Annotation struct {
	Name        string `json:"name"`
	Data        any    `json:"data"`
	Explanation string `json:"explanation"`
}

type AnnotationTemplate

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

func (*AnnotationTemplate) Execute

func (a *AnnotationTemplate) Execute(wr io.Writer, messages AnnotatedMessages) error

func (*AnnotationTemplate) Parse

type Behavior

type Behavior interface {
	Hashable
	Name() string
	Description() string
	Call(ctx context.Context, messages AnnotatedMessages) (AnnotatedMessages, Signal)
	Copy() Behavior
}

type BehaviorRef

type BehaviorRef string

type BehaviorState

type BehaviorState struct {
	StateName        string
	StateDescription string
	HashId           string
	ClientID         string
	Lambda           func(ctx context.Context, history AnnotatedMessages) (AnnotatedMessages, Signal)
}

func CannedResponseState

func CannedResponseState(message string) *BehaviorState

func LLMCompletionState

func LLMCompletionState(options LLMCompletionOptions) BehaviorState

func PauseState

func PauseState(reason string) BehaviorState

func (*BehaviorState) Call

func (*BehaviorState) Copy

func (b *BehaviorState) Copy() Behavior

func (*BehaviorState) Description

func (b *BehaviorState) Description() string

func (*BehaviorState) Hash

func (b *BehaviorState) Hash() string

func (*BehaviorState) Name

func (b *BehaviorState) Name() string

type BehaviorTree

type BehaviorTree struct {
	BehaviorName        string          `json:"name"`
	BehaviorDescription string          `json:"description"`
	Example             string          `json:"example"`
	Graph               Graph[Behavior] `json:"graph"`
	State               Stack[Behavior] `json:"state"`
	Traversed           map[string]bool `json:"traversed"`
	ClientID            string          `json:"client_id"`
	// contains filtered or unexported fields
}

func CreateBehaviorTree

func CreateBehaviorTree(name, description, example string) BehaviorTree

func CreateBehaviorTreeWithId

func CreateBehaviorTreeWithId(name, description, example, id string) BehaviorTree

func (*BehaviorTree) AddState

func (b *BehaviorTree) AddState(s Behavior)

func (*BehaviorTree) AddTransition

func (b *BehaviorTree) AddTransition(from, to Behavior)

func (*BehaviorTree) Call

func (*BehaviorTree) Copy

func (b *BehaviorTree) Copy() Behavior

func (*BehaviorTree) Description

func (b *BehaviorTree) Description() string

func (*BehaviorTree) Hash

func (b *BehaviorTree) Hash() string

func (*BehaviorTree) Name

func (b *BehaviorTree) Name() string

type Channel

type Channel interface {
	AllocateID() string
	Send(*ChannelMessage) error
	Receive() (*ChannelMessage, error)
}

type ChannelMessage

type ChannelMessage struct {
	Id      string `json:"id"`
	Content string `json:"content"`
}

type Chunk

type Chunk struct {
	Start     int
	End       int
	Text      string
	Embedding string
}

type ChunkingStrategy

type ChunkingStrategy interface {
	Chunk(s string) ([]string, error)
}

type CollectUserInputSignal

type CollectUserInputSignal struct {
	Reason string
}

CollectUserInputSignal signals that we must pause the current execution context, gather user input, and then resume.

func (CollectUserInputSignal) Description

func (c CollectUserInputSignal) Description() string

type ErrorSignal

type ErrorSignal struct {
	ErrorMessage string
	ErrorType    string
}

An ErrorSignal signals that an error occurred. This will bubble out all the way up the call stack, and aborts any further behavior execution

func (ErrorSignal) Description

func (e ErrorSignal) Description() string

func (ErrorSignal) Error

func (e ErrorSignal) Error() string

func (ErrorSignal) Type

func (e ErrorSignal) Type() string

type ExecGeneratedStep

type ExecGeneratedStep struct {
	Behavior        Behavior
	Messages        AnnotatedMessages
	ReplanTombstone bool
}

type ExecGeneratedStepSkeleton

type ExecGeneratedStepSkeleton struct {
	Ref             string            `json:"ref"`
	Snapshot        Snapshot          `json:"snapshot"`
	Messages        AnnotatedMessages `json:"messages"`
	ReplanTombstone bool              `json:"replan_tombstone"`
}

type Graph

type Graph[T Hashable] struct {
	Transitions [][]int `json:"transitions"`
	Nodes       []T     `json:"nodes"`
	// contains filtered or unexported fields
}

func (*Graph[T]) AddNode

func (g *Graph[T]) AddNode(n T) int

func (*Graph[T]) AddTransition

func (g *Graph[T]) AddTransition(from, to T)

func (*Graph[T]) Children

func (g *Graph[T]) Children(of T) []T

func (*Graph[T]) Initial

func (g *Graph[T]) Initial() T

type Hashable

type Hashable interface {
	Hash() string
}

type LLMCompletionOptions

type LLMCompletionOptions struct {
	Name         string
	Description  string
	ClientID     string
	Id           string
	System       string
	Model        string
	ExtraContext []string
	Annotation   string
	Terminal     bool
	AllowTools   bool
}

type MCPClientMux

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

func NewMCPClientMux

func NewMCPClientMux() *MCPClientMux

func (*MCPClientMux) AddInMemoryServer

func (m *MCPClientMux) AddInMemoryServer(ctx context.Context, transport mcp.Transport) error

func (*MCPClientMux) AddProfilesOfType

func (m *MCPClientMux) AddProfilesOfType(t string, profiles []MCPProfile) error

func (*MCPClientMux) AddSSEServer

func (m *MCPClientMux) AddSSEServer(ctx context.Context, baseURL string) error

func (*MCPClientMux) CallTool

func (m *MCPClientMux) CallTool(ctx context.Context, params *mcp.CallToolParams) (*mcp.CallToolResult, error)

func (*MCPClientMux) Close

func (m *MCPClientMux) Close() error

func (*MCPClientMux) Tools

func (m *MCPClientMux) Tools() []llm.ChatTool

type MCPProfile

type MCPProfile struct {
	Type    string      `json:"type"`
	Servers []MCPServer `json:"servers"`
}

func ProfilesForArtifact

func ProfilesForArtifact(artifact []byte) ([]MCPProfile, error)

type MCPServer

type MCPServer struct {
	Type     string `json:"type"`
	Location string `json:"location"`
}

type MemoryChunk

type MemoryChunk struct {
	Distance  float64       `json:"distance"`
	Text      string        `json:"text"`
	Embedding llm.Embedding `json:"-"`
	Metadata  string        `json:"metadata"`
}

type MemoryStore

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

func CreateMemoryStore

func CreateMemoryStore(db *sqlite3.Conn, provider llm.ModelProvider) *MemoryStore

func (*MemoryStore) CreateMemoryBankIfNotExists

func (m *MemoryStore) CreateMemoryBankIfNotExists(name string) error

func (*MemoryStore) Recall

func (m *MemoryStore) Recall(ctx context.Context, bank, query, prefix string) ([]MemoryChunk, error)

func (*MemoryStore) Store

func (m *MemoryStore) Store(ctx context.Context, bank string, chunk string, metadata string) error

func (*MemoryStore) StoreBatch

func (m *MemoryStore) StoreBatch(ctx context.Context, bank string, chunks []string, metadatas []string) error

type PlanResult

type PlanResult struct {
	Messages AnnotatedMessages  `json:"messages"`
	Step     *ExecGeneratedStep `json:"step"`
	Signal   Signal             `json:"signal"`
}

type SemanticChunker

type SemanticChunker struct {
	Threshold float64
	// contains filtered or unexported fields
}

func NewSemanticChunker

func NewSemanticChunker(m llm.ModelProvider) *SemanticChunker

func (*SemanticChunker) Chunk

func (s *SemanticChunker) Chunk(c string) ([]Chunk, error)

type Signal

type Signal interface {
	Description() string
}

The Signal interface is Arboreal's method of controlling execution flow.

type SkipSignal

type SkipSignal struct {
	Reason string
}

SkipSignal is only relevant to executing a BehaviorTree, and signals that the current branch should be skipped and execution should proceed to the next branch.

func (SkipSignal) Description

func (c SkipSignal) Description() string

type Snapshot

type Snapshot map[string]snapshotvalue

func TakeSnapshot

func TakeSnapshot(root Behavior) (Snapshot, error)

func (Snapshot) Restore

func (snap Snapshot) Restore(root Behavior) error

type Stack

type Stack[T any] struct {
	Items []T `json:"items"`
}

func (*Stack[T]) IsEmpty

func (s *Stack[T]) IsEmpty() bool

func (*Stack[T]) Pop

func (s *Stack[T]) Pop() T

func (*Stack[T]) Push

func (s *Stack[T]) Push(b T)

type TerminalChannel

type TerminalChannel struct{}

func (TerminalChannel) AllocateID

func (TerminalChannel) AllocateID() string

func (TerminalChannel) Receive

func (TerminalChannel) Receive() (*ChannelMessage, error)

func (TerminalChannel) Send

type TerminalSignal

type TerminalSignal struct {
	Reason string
}

TerminalSignal signals that the current execution context should be terminated. Execution will flow back out to the parent.

func (*TerminalSignal) Description

func (c *TerminalSignal) Description() string

type TodoListExecutive

type TodoListExecutive struct {
	ExecName           string
	ExecDescription    string
	Preamble           string
	Behaviors          []Behavior
	OutOfBoundsHandler Behavior
	MaxPlanDepth       int
	History            AnnotatedMessages
	ClientID           string

	// FIXME: This shouldn't work this way
	Output string
	// contains filtered or unexported fields
}

func CreateTodoListExecutive

func CreateTodoListExecutive(name, description string, behaviors ...Behavior) *TodoListExecutive

func CreateTodoListExecutiveWithId

func CreateTodoListExecutiveWithId(name, description, id string, behaviors ...Behavior) *TodoListExecutive

func (*TodoListExecutive) Call

func (*TodoListExecutive) Copy

func (e *TodoListExecutive) Copy() Behavior

func (*TodoListExecutive) Description

func (e *TodoListExecutive) Description() string

func (*TodoListExecutive) Execute

func (e *TodoListExecutive) Execute(ctx context.Context, messages AnnotatedMessages)

func (*TodoListExecutive) Hash

func (e *TodoListExecutive) Hash() string

func (*TodoListExecutive) Name

func (e *TodoListExecutive) Name() string

func (*TodoListExecutive) Plan

func (e *TodoListExecutive) Plan(messages AnnotatedMessages)

func (*TodoListExecutive) RunLoop

func (e *TodoListExecutive) RunLoop(c Channel) error

type Trace

type Trace chan *TraceMessage

func (Trace) Send

func (t Trace) Send(msg *TraceMessage)

type TraceHistoryOperation

type TraceHistoryOperation struct {
	Type       string                     `json:"type"`
	Action     string                     `json:"action"`
	Annotation *Annotation                `json:"annotation,omitempty"`
	Message    *llm.ChatCompletionMessage `json:"message,omitempty"`
}

type TraceMessage

type TraceMessage struct {
	Type       string                   `json:"type"`
	ID         string                   `json:"id"`
	ClientID   string                   `json:"client_id,omitempty"`
	Name       string                   `json:"name"`
	Message    string                   `json:"message"`
	Error      error                    `json:"error,omitempty"`
	Telemetry  *TraceTelemetry          `json:"telemetry,omitempty"`
	Operations []*TraceHistoryOperation `json:"operations,omitempty"`
	Signal     *TraceSignal             `json:"signal,omitempty"`
}

type TraceSignal

type TraceSignal struct {
	Type   string `json:"type"`
	Reason string `json:"reason"`
}

func TraceForSignal

func TraceForSignal(sig Signal) *TraceSignal

type TraceTelemetry

type TraceTelemetry struct {
	Start time.Time  `json:"start"`
	End   *time.Time `json:"end"`
}

type TwilioSMSChannel

type TwilioSMSChannel struct {
	AllowList []string
	// contains filtered or unexported fields
}

func CreateTwilioSMSChannel

func CreateTwilioSMSChannel() *TwilioSMSChannel

func (*TwilioSMSChannel) AllocateID

func (c *TwilioSMSChannel) AllocateID() string

func (*TwilioSMSChannel) Receive

func (c *TwilioSMSChannel) Receive() (*ChannelMessage, error)

func (*TwilioSMSChannel) Send

Directories

Path Synopsis
test command
examples
crm command
semchunks command
test command
tools command

Jump to

Keyboard shortcuts

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