111 lines
4.4 KiB
Go
111 lines
4.4 KiB
Go
// Package agent implements the Agent entity of the Cyrene v2 runtime
|
|
// (DevDocs/design/04-运行时.md §1). An Agent is an instruction string plus an
|
|
// optional set of tools, an optional guardrail pipeline and an optional
|
|
// handoff, wired to a model Adapter (and an optional per-role Router). It
|
|
// executes a single step of the agent loop — assemble a request, run input and
|
|
// output guardrails, call the model and decode any tool calls — without owning
|
|
// the loop itself, which lives in internal/runtime/loop (M2).
|
|
package agent
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
|
|
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/guardrail"
|
|
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/model"
|
|
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/tool"
|
|
)
|
|
|
|
// Sentinel errors returned by the Agent. Use errors.Is to test for them; they
|
|
// are returned directly or wrapped with %w so the underlying cause stays
|
|
// available.
|
|
var (
|
|
// ErrEmptyInstructions is returned by New when instructions is empty.
|
|
ErrEmptyInstructions = errors.New("agent: empty instructions")
|
|
// ErrBadOptions is returned by New when an option value is out of range.
|
|
ErrBadOptions = errors.New("agent: invalid options")
|
|
// ErrNoAdapter is returned by RunStep when no model Adapter was injected.
|
|
ErrNoAdapter = errors.New("agent: no model adapter")
|
|
)
|
|
|
|
// Agent is a single, self-contained runtime entity: an instruction string, an
|
|
// optional tool Dispatcher, an optional guardrail Pipeline, the model backend
|
|
// and an optional handoff placeholder. It is safe for concurrent use as long as
|
|
// its fields are not mutated after construction; RunStep builds a local Request
|
|
// and delegates to the (concurrency-safe) adapter, dispatcher and guardrail.
|
|
type Agent struct {
|
|
instructions string
|
|
tools *tool.Dispatcher
|
|
guards *guardrail.Pipeline
|
|
adapter model.Adapter
|
|
router *model.Router
|
|
recorder model.Recorder
|
|
handoff *Handoff
|
|
opts Options
|
|
}
|
|
|
|
// New builds an Agent from an instruction string, an optional tool Dispatcher,
|
|
// an optional guardrail Pipeline and zero or more options applied in order over
|
|
// the defaults (default MaxRounds is 8). It returns ErrEmptyInstructions when
|
|
// instructions is blank and ErrBadOptions when an option value is out of range.
|
|
//
|
|
// The concrete adapter/router used by RunStep are injected through the options
|
|
// (see WithModel); tools and guardrails may be nil to run a bare step, and the
|
|
// agent still works as long as an adapter is supplied before RunStep.
|
|
func New(instructions string, tools *tool.Dispatcher, guards *guardrail.Pipeline, opts ...Option) (*Agent, error) {
|
|
a := &Agent{
|
|
instructions: instructions,
|
|
tools: tools,
|
|
guards: guards,
|
|
opts: Options{MaxRounds: defaultMaxRounds},
|
|
}
|
|
if a.instructions == "" {
|
|
return nil, ErrEmptyInstructions
|
|
}
|
|
for _, o := range opts {
|
|
if o != nil {
|
|
o(a)
|
|
}
|
|
}
|
|
if err := validateOptions(a.opts); err != nil {
|
|
return nil, fmt.Errorf("agent: new: %w", err)
|
|
}
|
|
return a, nil
|
|
}
|
|
|
|
// Instructions returns the agent's instruction/system prompt.
|
|
func (a *Agent) Instructions() string { return a.instructions }
|
|
|
|
// Tools returns the agent's tool dispatcher, or nil when none was configured.
|
|
func (a *Agent) Tools() *tool.Dispatcher { return a.tools }
|
|
|
|
// Guardrails returns the agent's guardrail pipeline, or nil when none was
|
|
// configured.
|
|
func (a *Agent) Guardrails() *guardrail.Pipeline { return a.guards }
|
|
|
|
// Adapter returns the injected model adapter.
|
|
func (a *Agent) Adapter() model.Adapter { return a.adapter }
|
|
|
|
// Router returns the injected per-role router, or nil.
|
|
func (a *Agent) Router() *model.Router { return a.router }
|
|
|
|
// Model returns the configured model name. Empty means the injected Router or
|
|
// the adapter's own default decides.
|
|
func (a *Agent) Model() string { return a.opts.Model }
|
|
|
|
// Temperature returns the configured sampling temperature.
|
|
func (a *Agent) Temperature() float64 { return a.opts.Temperature }
|
|
|
|
// MaxRounds returns the tool-loop upper bound consumed by the loop (M2,
|
|
// external to this package).
|
|
func (a *Agent) MaxRounds() int { return a.opts.MaxRounds }
|
|
|
|
// Purpose returns the call-purpose label recorded on each CallRecord.
|
|
func (a *Agent) Purpose() string { return a.purpose() }
|
|
|
|
// MaxTokens returns the token cap passed to the model.
|
|
func (a *Agent) MaxTokens() int { return a.opts.MaxTokens }
|
|
|
|
// Options returns a copy of the agent's current config options.
|
|
func (a *Agent) Options() Options { return a.opts }
|