pith

module
v0.0.0-...-8a574d8 Latest Latest
Warning

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

Go to latest
Published: Jun 5, 2026 License: MIT

README

Pith

Go SDK for building LLM agent applications. Four layers — protocol types, LLM gateway, agent loop, stateful agent — each with a strict dependency boundary and no runtime assumptions.

The built-in OpenAICompatProvider covers any /v1/chat/completions API (OpenAI, Groq, Together, DeepSeek, OpenRouter, Ollama, etc.). Custom providers (e.g., Anthropic Messages API) are built using the ProviderPort interface — see example 11.

Build agents quickly → pith-sdk

Multi-module repo. Import a layer directly: agent · gateway · loop · protocol

Installation

Import the layer you need. The agent module pulls in gateway, loop, and protocol:

go get github.com/chinudotdev/pith/agent@v0.1.4
go get github.com/chinudotdev/pith/gateway@v0.1.4
go get github.com/chinudotdev/pith/loop@v0.1.4
go get github.com/chinudotdev/pith/protocol@v0.1.4

Requires Go 1.24+.

Examples

# File Description
01 01-minimal/ Simplest usage — stream a response via the gateway
02 02-basic-agent/ Agent lifecycle, event bus, transcript inspection
03 03-agent-with-tools/ Tool definition, tool execution, transcript with tool calls
04 04-multi-turn/ Multi-turn conversation across Prompt() calls
05 05-compaction/ EstimateTokens, ShouldCompact, CompactMessages, Agent.Compact()
06 06-steering-followup/ Steering queue (mid-loop injection) & follow-up queue
07 07-middleware/ Custom middleware, RetryPolicy, HeaderInjector, logging
08 08-custom-messages/ MessageRegistry, MessagePipeline, sealed interface limitation
09 09-abort/ Context cancellation, Agent.Abort(), WaitForIdle()
10 10-capability-negotiation/ Capability negotiation, tool execution policies, tool hooks
11 11-custom-provider/ Build a custom ProviderPort (Anthropic Messages API) and wire it through the gateway and agent

Examples are standalone programs (not listed in go.work). Copy one into a new module and run it — see examples/README.md:

mkdir my-agent && cd my-agent
go mod init my-agent
cp /path/to/pith/examples/01-minimal/main.go .
go get github.com/chinudotdev/pith/gateway@v0.1.4
OPENAI_API_KEY="sk-..." go run main.go

Quick Reference

import (
    "context"
    "os"

    "github.com/chinudotdev/pith/agent"
    "github.com/chinudotdev/pith/gateway"
    "github.com/chinudotdev/pith/gateway/providers"
    "github.com/chinudotdev/pith/protocol"
)

// --- L1: Gateway ---

gw := gateway.NewLLMGateway()
gw.Providers.Register(providers.NewOpenAICompatProvider(providers.OpenAICompatConfig{
    BaseURL: "https://api.openai.com",
}))
gw.Credentials = gateway.CredentialProviderFunc(func(pid protocol.ProviderId) (protocol.Credential, error) {
    return protocol.ApiKey{Key: os.Getenv("OPENAI_API_KEY")}, nil
})
gw.Catalog.Register("openai", protocol.ModelDescriptor{
    ID: "gpt-4o-mini", API: protocol.ApiOpenAICompletions, Provider: "openai",
    BaseURL: "https://api.openai.com", ContextWindow: 128000, MaxTokens: 4096,
})

model, _ := gw.Catalog.Get("openai", "gpt-4o-mini")

stream, _ := gw.Stream(ctx, model, protocol.Context{
    SystemPrompt: "You are helpful.",
}, opts)
for event := range stream {
    if event.Type == protocol.EventTextDelta {
        fmt.Print(event.Delta)
    }
}

// --- L3: Agent ---

ag := agent.NewAgent(agent.AgentConfig{
    InitialState: &agent.AgentState{
        Model:        model,
        SystemPrompt: "You are helpful.",
        Tools:        myTools,
    },
    StreamFn: func(ctx context.Context, m protocol.ModelDescriptor, pctx protocol.Context, opts protocol.StreamOptions) (<-chan protocol.StreamEvent, error) {
        return gw.Stream(ctx, m, pctx, opts)
    },
})

ag.EventBus().Subscribe(func(e agent.AgentEvent) {
    if e.LoopEvent != nil && e.LoopEvent.Type == "messageUpdate" {
        if e.LoopEvent.StreamEvent != nil && e.LoopEvent.StreamEvent.Type == protocol.EventTextDelta {
            fmt.Print(e.LoopEvent.StreamEvent.Delta)
        }
    }
})

ag.Prompt(ctx, "Hello!")

// --- Compaction ---

if agent.ShouldCompact(ag.State().Messages, agent.CompactionSettings{Enabled: true}, model) {
    tokens := agent.EstimateTokens(ag.State().Messages)
    ag.Compact("Summary of conversation", 2, tokens, nil)
}

// --- Steering & Follow-Up ---

ag.FollowUp(protocol.UserMessage{Role: "user", Content: []protocol.Content{protocol.TextContent{Type: "text", Text: "Now explain that."}}, Timestamp: protocol.Now()})
ag.Prompt(ctx, "What is Go?")

ag.Steer(protocol.UserMessage{Role: "user", Content: []protocol.Content{protocol.TextContent{Type: "text", Text: "Be more concise."}}, Timestamp: protocol.Now()})

// --- Abort ---

go ag.Prompt(ctx, "Long running task...")
time.Sleep(100 * time.Millisecond)
ag.Abort()
ag.WaitForIdle()

API Primitives

Primitive Layer Purpose
protocol.* L0 Pure types: messages, content, stream events, model descriptors, errors
LLMGateway.Stream / Complete L1 Compose providers + catalog + credentials + middleware
OpenAICompatProvider L1 Provider for any /v1/chat/completions API (OpenAI, Groq, Together, etc.)
ProviderRegistry L1 Instance-based provider registration
ModelCatalog L1 Programmatic model registration and cost calculation
CredentialProvider L1 Interface for API key resolution (no default)
Middleware L1 Composable pipeline: RetryPolicy, HeaderInjector
AgentLoop L2 Stateless turn executor (takes StreamFn, not L1 directly)
Agent.Prompt / Continue / Abort L3 Stateful in-memory agent
EventBus L3 Typed subscribe/unsubscribe event dispatch
MessageQueue L3 Steering + follow-up queues
MessageRegistry L3 Runtime message type conversion
EstimateTokens / ShouldCompact / CompactMessages L3 Compaction primitives (no policy)

Directories

Path Synopsis
agent module
examples
01-minimal command
Example 01: Minimal — one-shot prompt with an OpenAI-compatible provider.
Example 01: Minimal — one-shot prompt with an OpenAI-compatible provider.
02-basic-agent command
Example 02: Basic Agent — create an agent, subscribe to events, send a prompt.
Example 02: Basic Agent — create an agent, subscribe to events, send a prompt.
03-agent-with-tools command
Example 03: Agent with Tools — define tools, the model calls them, the agent executes them.
Example 03: Agent with Tools — define tools, the model calls them, the agent executes them.
04-multi-turn command
Example 04: Multi-Turn — conversation across multiple Prompt() calls.
Example 04: Multi-Turn — conversation across multiple Prompt() calls.
05-compaction command
Example 05: Compaction — EstimateTokens, ShouldCompact, CompactMessages, Agent.Compact().
Example 05: Compaction — EstimateTokens, ShouldCompact, CompactMessages, Agent.Compact().
06-steering-followup command
Example 06: Steering & Follow-Up Queues — inject messages mid-loop and after a turn.
Example 06: Steering & Follow-Up Queues — inject messages mid-loop and after a turn.
07-middleware command
Example 07: Middleware Pipeline — logging, timing, RetryPolicy, HeaderInjector.
Example 07: Middleware Pipeline — logging, timing, RetryPolicy, HeaderInjector.
08-custom-messages command
Example 08: Custom Messages & MessageRegistry — sealed interface, converters, pipeline.
Example 08: Custom Messages & MessageRegistry — sealed interface, converters, pipeline.
09-abort command
Example 09: Agent Abort — context cancellation, Agent.Abort(), WaitForIdle().
Example 09: Agent Abort — context cancellation, Agent.Abort(), WaitForIdle().
10-capability-negotiation command
Example 10: Capability Negotiation & Tool Execution Policies.
Example 10: Capability Negotiation & Tool Execution Policies.
11-custom-provider command
Example 11: Custom Provider — build your own ProviderPort for an API the SDK doesn't ship with.
Example 11: Custom Provider — build your own ProviderPort for an API the SDK doesn't ship with.
gateway module
loop module
protocol module

Jump to

Keyboard shortcuts

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