loop

package module
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: Mar 15, 2026 License: MIT Imports: 7 Imported by: 3

README

axon-loop

Primitives · Part of the lamina workspace

Provider-agnostic conversation loop for LLM-powered agents. Handles message exchange, tool call dispatch, and streaming with no HTTP, persistence, or UI concerns. Bring your own LLMClient implementation (e.g. Ollama, OpenAI, Anthropic) and axon-loop drives the send-stream-tool-repeat cycle.

Getting started

go get github.com/benaskins/axon-loop@latest

Requires Go 1.24+.

result, err := loop.Run(ctx, client, &loop.Request{
    Model:    "llama3",
    Messages: []loop.Message{{Role: "user", Content: "Hello"}},
    Stream:   true,
}, tools, nil, loop.Callbacks{
    OnToken: func(t string) { fmt.Print(t) },
})

See example/main.go for a runnable sketch.

Key types

  • LLMClient — interface for communicating with any LLM backend
  • Request / Response — provider-agnostic request and streamed response chunk
  • Message — a single message in a conversation
  • ToolCall — an LLM's decision to invoke a tool
  • Run() — executes the conversation loop with tool dispatch and streaming callbacks
  • Callbacks — optional hooks for tokens, thinking, tool use, and completion

License

MIT — see LICENSE.

Documentation

Overview

Package loop provides a provider-agnostic conversation loop for LLM-powered agents. It handles message exchange, tool call dispatch, and streaming — with no HTTP, persistence, or UI concerns.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Stream added in v0.4.0

func Stream(ctx context.Context, client LLMClient, req *Request, tools map[string]tool.ToolDef, toolCtx *tool.ToolContext) <-chan Event

Stream executes a conversation loop and returns a channel of Events. The channel is closed when the loop completes or fails. The caller reads events without building a callback-to-channel bridge.

tools and toolCtx may be nil for simple chat without tool support.

Types

type Callbacks

type Callbacks struct {
	OnToken    func(token string)
	OnThinking func(token string)
	OnToolUse  func(name string, args map[string]any)
	OnDone     func(durationMs int64)
}

Callbacks receives streaming events from the conversation loop. All fields are optional — nil callbacks are skipped.

type DoneEvent added in v0.4.0

type DoneEvent struct {
	Content    string
	Thinking   string
	DurationMs int64
}

DoneEvent is emitted when the loop completes successfully.

type Event added in v0.4.0

type Event struct {
	// Exactly one of these is set per event.
	Token    string        // incremental content token
	Thinking string        // incremental thinking token
	ToolUse  *ToolUseEvent // a tool was invoked
	Done     *DoneEvent    // the loop completed
	Err      error         // the loop failed
}

Event is a streaming event emitted by Stream. Consumers receive these on a channel instead of registering callbacks.

type LLMClient added in v0.2.0

type LLMClient interface {
	Chat(ctx context.Context, req *Request, fn func(Response) error) error
}

LLMClient abstracts communication with an LLM backend. Implementations translate to/from provider-specific APIs (e.g. Ollama, OpenAI, Anthropic).

type Message

type Message struct {
	Role      string
	Content   string
	Thinking  string
	ToolCalls []ToolCall
}

Message represents a single message in a conversation.

type Request added in v0.3.0

type Request struct {
	Model         string
	Messages      []Message
	Tools         []tool.ToolDef
	Stream        bool
	Think         *bool
	Options       map[string]any
	MaxIterations int // Maximum tool-call loop iterations. Defaults to 20 if 0.
}

Request is a provider-agnostic request to an LLM.

type Response added in v0.3.0

type Response struct {
	Content   string
	Thinking  string
	Done      bool
	ToolCalls []ToolCall
}

Response is a provider-agnostic streamed response chunk from an LLM.

type Result

type Result struct {
	Content  string
	Thinking string
}

Result is the final output of a conversation loop run.

func Run

func Run(ctx context.Context, client LLMClient, req *Request, tools map[string]tool.ToolDef, toolCtx *tool.ToolContext, cb Callbacks) (*Result, error)

Run executes a conversation loop: sends messages to the LLM, streams the response, executes tool calls, and repeats until no more tool calls are made.

tools and toolCtx may be nil for simple chat without tool support.

type ToolCall

type ToolCall struct {
	Name      string
	Arguments map[string]any
}

ToolCall represents an LLM's decision to invoke a tool.

type ToolUseEvent added in v0.4.0

type ToolUseEvent struct {
	Name string
	Args map[string]any
}

ToolUseEvent is emitted when the LLM invokes a tool.

Jump to

Keyboard shortcuts

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