Reusable Go library for building LLM agents
Find a file
Victor Vargas 8e887c8c78 fix(agent,llamacpp): recover turns killed by unparsed tool calls and reasoning spirals
Two failure modes seen live with Qwen3.6 on llama.cpp ended turns silently
mid-task:

- The model writes its tool call as plain text inside its reasoning, the
  server never parses it, and the round ends with nothing executed. The
  loop now detects the markers and nudges the model to re-issue the call
  for real (max 2 per turn).

- llama.cpp silently ignores the max_thinking_tokens field, so a model in
  a reasoning spiral ran until max_tokens (seen live: 25k+ tokens of
  nonstop thinking, ~20 min). The llamacpp client now enforces the budget
  client-side during Stream: once exceeded while the round is still pure
  reasoning, it cuts with FinishThinkingBudget and aborts the request
  (freeing the server slot); the loop answers with its own corrective
  nudge, on a separate counter.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 14:50:45 -07:00
.agents/skills/add-feature docs: add AGENTS.md guide and skill definitions for AI agents 2026-06-30 23:53:34 -07:00
docs feat(agent): add SubAgent runtime for nested, specialized agent loops 2026-07-09 12:08:32 -07:00
examples docs(i18n): translate all docs to English (with .es.md as Spanish alternative) 2026-06-30 13:40:37 -07:00
pkg fix(agent,llamacpp): recover turns killed by unparsed tool calls and reasoning spirals 2026-07-15 14:50:45 -07:00
.gitignore chore: initial scaffold with design docs 2026-06-28 16:03:57 -07:00
AGENTS.md feat(agent): add SubAgent runtime for nested, specialized agent loops 2026-07-09 12:08:32 -07:00
go.mod feat(rag): add SQLite+FTS5 backend, fix content/usage plumbing bugs 2026-07-06 00:05:30 -07:00
go.sum feat(rag): add SQLite+FTS5 backend, fix content/usage plumbing bugs 2026-07-06 00:05:30 -07:00
LICENSE chore: initial scaffold with design docs 2026-06-28 16:03:57 -07:00
README.es.md docs(i18n): translate all docs to English (with .es.md as Spanish alternative) 2026-06-30 13:40:37 -07:00
README.md docs(fix): fix go-llm-agent → rony-llm-agent 2026-06-30 14:43:00 -07:00

rony-llm-agent

🌐 Language: English | Español

🔑 Reusable core library for building LLM agents in Go.

This library is the heart of several Victor Vargas projects:

  • harness — AI agent harness for software development (TUI)
  • chat-bot — HTTP chatbot for portfolios and websites

It provides all the generic logic of an LLM agent:

Component Location Responsibility
Agent loop pkg/agent/ Iterative loop with guardrails
LLM clients pkg/llm/ Multi-provider abstraction (OpenAI, Anthropic, Ollama)
RAG / memory pkg/rag/ Short and long-term memory with semantic search
Persona system pkg/persona/ Configurable system prompts + AGENTS.md discovery
Tool registry pkg/tools/ JSON Schema + execution sandbox
Config loading pkg/config/ YAML loading with hierarchical precedence

🎯 Philosophy

  • Reusable, not opinionated. Does not force a UI type, deployment, or use case.
  • Pure Hexagonal. Ports & adapters — every external dependency is behind an interface.
  • Streaming-first. Uses iter.Seq2 from Go 1.23+ for natural streaming without callbacks.
  • Secure by default. Filesystem path sandbox with os.Root (Go 1.24+).
  • Zero magic. No reflection, no codegen, no DSLs. Idiomatic and explicit Go.
  • YAML configurable. Everything that affects behavior is declarative.

📦 Installation

go get github.com/VictorVargas/rony-llm-agent

🚀 Basic usage

package main

import (
    "context"
    "fmt"
    "github.com/VictorVargas/rony-llm-agent/pkg/agent"
    "github.com/VictorVargas/rony-llm-agent/pkg/llm"
    "github.com/VictorVargas/rony-llm-agent/pkg/persona"
)

func main() {
    // 1. Create LLM client
    llmClient, _ := llm.NewAnthropicClient(llm.AnthropicConfig{
        APIKey: os.Getenv("ANTHROPIC_API_KEY"),
        Model:  "claude-sonnet-4.5",
    })

    // 2. Load persona
    p := persona.Load("./persona.yaml")

    // 3. Create agent loop
    loop := agent.New(agent.Config{
        LLM:         llmClient,
        Persona:     p,
        MaxIters:    50,
        Sandbox:     agent.NewSandbox("./workspace"),
    })

    // 4. Run
    resp, err := loop.Run(context.Background(), "Refactor auth.go")
    if err != nil { panic(err) }

    fmt.Println(resp.Content)
}

🔌 Included adapters

LLM Providers (pkg/llm/providers/)

Provider Import Models
OpenAI providers/openai gpt-4o, gpt-4o-mini, gpt-4-turbo
Anthropic providers/anthropic claude-sonnet-4.5, claude-haiku-4
Ollama providers/ollama llama3.1, qwen2.5, mistral, etc.
llama.cpp providers/llamacpp Custom GGUF models

Vector DBs (pkg/rag/backends/)

Backend Status
ChromaDB embedded Stable
Qdrant embedded 🚧 In development
SQLite + sqlite-vec 📋 Planned

Embeddings (pkg/rag/embeddings/)

  • Ollama embeddings (nomic-embed-text, bge-m3, etc.)
  • Local sentence-transformers via ONNX

🧪 Testing

go test ./...
go test -race ./...
go test -bench=. ./pkg/agent/

Includes MockLLMClient for deterministic tests without burning API calls.

📐 Versions

  • Go minimum: 1.26 (uses os.Root, iter.Seq, unique.Handle, container-aware GOMAXPROCS)
  • Versioning policy: Strict semver. API breaking changes only on MAJOR.

📄 License

MIT — see LICENSE.

🔗 Projects that use this library

📚 Additional documentation