feat(agent): Agent 实体(指令/工具/guardrail/handoff + 单步 RunStep,含多模态路由/调用记录)
This commit is contained in:
1 parent
b798e129c1
commit
be67d74822
6 files changed
+843
No files matched your search
@@ -0,0 +1,110 @@
|
||||
// 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 }
|
||||
Reference in new issue
Block a user