Help us shape the future of Go! Take the 2026 Go Developer Survey

loop

package
v0.2.1 Latest Latest
Warning

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

Go to latest
Published: Oct 11, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package loop runs one employee wake on a CloudWeGo Eino chat model.

A wake is: take the Host's frozen messages -> ask the model -> validate the native tool batch -> let the Host execute every call -> stop on a terminal decision or ask again within the budget. The Host owns context assembly, permissions, receipts and effects; the loop owns ordering, validation, budgets and the rule that nothing counts as done without a Host receipt.

out, err := loop.New(cfg, model, host).Run(ctx, loop.Wake{Identity: id, Messages: msgs})

Index

Constants

View Source
const ExtraParameters = "employee_loop.parameters"

ExtraParameters is the ToolInfo.Extra key carrying the original JSON Schema map, so a model adapter can send it without a lossy round trip.

View Source
const FinalTextOrigin = "host_final_text"

FinalTextOrigin marks the tool outcome of an accepted final text.

Variables

View Source
var (
	ErrModelBudget            = errors.New("employee loop: model budget exhausted")
	ErrConsecutiveModelErrors = errors.New("employee loop: consecutive model errors exhausted")
	ErrModelResponseBudget    = errors.New("employee loop: valid model response budget exhausted")
	ErrPhysicalModelBudget    = errors.New("employee loop: provider attempt budget exhausted")
	ErrMissingReceipt         = errors.New("employee loop: effect has no host receipt")
	ErrTerminalConflict       = errors.New("employee loop: conflicting terminal tool results")
	// ErrToolRefused marks a Host refusal made before any effect (for example
	// an argument that names no known source). The model may correct the call
	// within the budget; it is not a batch failure.
	ErrToolRefused = errors.New("employee loop: tool call refused before any effect")
)

Errors returned by Run. Budget errors are joined with ErrModelBudget.

Functions

func Locales

func Locales() []string

Locales lists the built-in locales.

func ToolInfos

func ToolInfos(tools []Tool) ([]*schema.ToolInfo, error)

ToolInfos converts tools to Eino tool infos, in the given order.

func ValidateArguments

func ValidateArguments(schemaMap map[string]any, args map[string]any) []string

ValidateArguments checks arguments against the portable subset of JSON Schema used by tool contracts: type, required, additionalProperties=false, properties, enum, minLength, maxLength, minItems, maxItems and items. Hosts with a full validator add it through Config.ValidateBatch.

Types

type Budget

type Budget struct {
	MaxModelResponses    int
	MaxConsecutiveErrors int
	MaxPhysicalAttempts  int
}

Budget bounds one wake. Successful tool progress resets the consecutive error count.

func DefaultBudget

func DefaultBudget() Budget

DefaultBudget allows three of each.

type BudgetUsage

type BudgetUsage struct {
	ModelResponses    int
	ConsecutiveErrors int
}

BudgetUsage counts accepted responses and the current error streak.

type Config

type Config struct {
	Tools  []Tool
	Budget Budget
	// RequireTerminalTool makes plain assistant text private: only a
	// Host-accepted terminal decision ends the wake (see AcceptFinalText).
	RequireTerminalTool bool
	// RequireNativeToolCall asks the provider for a tool call without
	// choosing which one (tool_choice "required").
	RequireNativeToolCall bool
	// AcceptFinalText lets a FinalTextHost accept a first plain answer of up
	// to FinalTextLimit bytes (default 8000) when RequireTerminalTool is set.
	AcceptFinalText bool
	FinalTextLimit  int
	// TurnTools narrows the tools offered to the next model call (call
	// counts from 1) given the outcomes so far; nil offers every tool. Calls
	// to a tool that was not offered are rejected like unknown tools.
	TurnTools func(call int, outcomes []ToolOutcome) []string
	// Locale selects the built-in repair texts (en, zh-CN).
	Locale string
	// RepairText replaces the built-in instruction appended after a rejected
	// response or provider error.
	RepairText func(err error) string
	// ValidateBatch and ValidateText add Host rules to the built-in batch
	// validation (unknown tools, exclusivity, terminal conflicts, argument
	// schemas) and to public text (plain replies and "reply" arguments).
	ValidateBatch func([]ToolCall) error
	ValidateText  func(string) error
	// Permanent classifies provider errors that end the wake at once.
	Permanent func(error) bool
	// Hooks observe the wake; they never change it and must not block.
	OnModelCall     func(context.Context, ModelCall)
	OnToolCall      func(context.Context, ToolCall, ToolResult, error, time.Duration)
	OnBatchRejected func([]ToolCall, error)
	OnModelFailure  func(error)
}

Config configures a loop. Everything Host-specific is injected here.

type Decision

type Decision struct {
	Kind  Disposition
	Reply string
}

Decision is a Host-accepted terminal disposition, or a plain text reply when the wake does not require a terminal tool. Reply may accompany Dispatched and Waiting.

type Disposition

type Disposition string

Disposition is how a wake ended.

const (
	Reply      Disposition = "reply"
	Quiet      Disposition = "quiet"
	Dispatched Disposition = "dispatched"
	Waiting    Disposition = "waiting"
)

type FinalTextHost

type FinalTextHost interface {
	AcceptFinalText(context.Context, Identity, string) (ToolResult, error)
}

FinalTextHost accepts a first plain answer as the public reply of a wake that otherwise requires a terminal tool (Config.AcceptFinalText).

type Host

type Host interface {
	Execute(context.Context, Identity, ToolCall) (ToolResult, error)
}

Host owns reads, permissions, durable state and effects. Execute honours ctx and deduplicates effects by identity plus NativeToolCallID; a committed effect returns its receipt even when ctx was cancelled after the commit. The loop never invents a receipt.

type HostFunc

type HostFunc func(context.Context, Identity, ToolCall) (ToolResult, error)

HostFunc adapts a function to Host.

func (HostFunc) Execute

func (f HostFunc) Execute(ctx context.Context, id Identity, call ToolCall) (ToolResult, error)

Execute implements Host.

type Identity

type Identity struct {
	Tenant   string
	Employee string
	Scene    string
	Receipt  string
}

Identity is supplied by the Host from trusted admission data and passed back to every Host call. The loop never reads or changes it.

type Loop

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

Loop runs wakes with one configuration. It holds no state between runs.

func New

func New(cfg Config, m model.ToolCallingChatModel, host Host) *Loop

New returns a loop over an Eino tool-calling model and a Host.

func (*Loop) Run

func (l *Loop) Run(ctx context.Context, w Wake) (Outcome, error)

Run executes one wake.

type ModelCall

type ModelCall struct {
	Attempt  int
	Request  []*schema.Message
	Response *schema.Message
	Err      error
	Elapsed  time.Duration
}

ModelCall describes one provider request for observers.

type Outcome

type Outcome struct {
	Decision
	// ModelCalls counts provider requests (physical attempts).
	ModelCalls   int
	Receipts     []Receipt
	ToolOutcomes []ToolOutcome
	BudgetUsage  BudgetUsage
	Usage        Usage
	// Transcript is the accepted conversation: the wake's messages, accepted
	// responses and their tool results. Rejected output is never kept.
	Transcript []*schema.Message
}

Outcome is the result of one wake. Callers check Run's error as well: ToolOutcomes may hold committed effects of a failed wake.

type Receipt

type Receipt struct {
	NativeToolCallID string
	ToolName         string
	ID               string
}

Receipt is the durable proof of one effect.

type Tool

type Tool struct {
	Name        string
	Description string
	// Schema is the JSON Schema of the arguments, sent to the model and used
	// for validation before any call runs.
	Schema map[string]any
	// Effect tools change the world; a successful call must return a Host
	// receipt.
	Effect bool
	// Terminal declares the disposition the tool always ends with, so a
	// batch mixing dispositions is rejected before any effect.
	Terminal Disposition
	// Exclusive tools must be the only call of their batch.
	Exclusive bool
	// Timeout bounds one call; zero leaves it to the wake context.
	Timeout time.Duration
}

Tool is a capability supplied by the Host.

type ToolCall

type ToolCall struct {
	// Origin marks calls the loop made on the Host's behalf (FinalTextOrigin).
	Origin           string         `json:"origin,omitempty"`
	NativeToolCallID string         `json:"native_tool_call_id"`
	Name             string         `json:"name"`
	Arguments        map[string]any `json:"arguments"`
}

ToolCall is one native call of a model response.

type ToolOutcome

type ToolOutcome struct {
	Origin           string
	NativeToolCallID string
	ToolName         string
	Result           ToolResult
	Error            string
}

ToolOutcome is one Host result in call order, including committed effects returned with an error. It does not claim the batch completed.

type ToolResult

type ToolResult struct {
	Content  string
	Receipt  string
	Terminal *Decision
}

ToolResult is the Host's answer to a call. Content is what the model sees.

type Usage

type Usage struct {
	PromptTokens     int
	CompletionTokens int
}

Usage sums the provider-reported tokens of the wake.

type Wake

type Wake struct {
	Identity Identity
	Messages []*schema.Message
}

Wake is the frozen input of one wake: the identity and the messages the Host assembled (system prompt first, then context and the current window).

Directories

Path Synopsis
Package looptest provides a scripted Eino chat model for tests of Hosts that embed the loop.
Package looptest provides a scripted Eino chat model for tests of Hosts that embed the loop.

Jump to

Keyboard shortcuts

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