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,96 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/model"
|
||||
)
|
||||
|
||||
// Option bounds and defaults. These are compile-time constants so no magic
|
||||
// number appears in the runtime path.
|
||||
const (
|
||||
defaultMaxRounds = 8
|
||||
minTemperature = 0.0
|
||||
maxTemperature = 2.0
|
||||
)
|
||||
|
||||
// Options carries the config knobs for an Agent. Zero values fall back to a
|
||||
// provider default: temperature uses 0 to mean "provider default", and
|
||||
// MaxRounds/MaxTokens use 0 to mean "default"/"provider default" respectively.
|
||||
type Options struct {
|
||||
// Model is the requested model name. Empty lets the injected Router or the
|
||||
// adapter's own default decide.
|
||||
Model string
|
||||
// Temperature is the sampling temperature. A nonzero value is forwarded to
|
||||
// the model; zero means the provider default.
|
||||
Temperature float64
|
||||
// MaxRounds is the tool-loop upper bound. Zero is defaulted to 8.
|
||||
MaxRounds int
|
||||
// Purpose labels every CallRecord emitted for accounting ("chat", "agent").
|
||||
Purpose string
|
||||
// MaxTokens caps generated tokens. Zero means the provider default.
|
||||
MaxTokens int
|
||||
}
|
||||
|
||||
// Option configures an Agent at construction time. Options are applied in the
|
||||
// order they are passed to New.
|
||||
type Option func(*Agent)
|
||||
|
||||
// WithModel injects the LLM backend used by RunStep: a model.Adapter plus an
|
||||
// optional per-role Router. When router is non-nil it overrides the Request's
|
||||
// Model from the request contents — which is how vision requests are routed to
|
||||
// the vision model — otherwise the agent's configured Model or the adapter
|
||||
// default applies.
|
||||
func WithModel(adapter model.Adapter, router *model.Router) Option {
|
||||
return func(a *Agent) {
|
||||
a.adapter = adapter
|
||||
a.router = router
|
||||
}
|
||||
}
|
||||
|
||||
// WithOptions applies opts to the agent's config, merging over the defaults. A
|
||||
// zero Model, MaxRounds, Purpose or MaxTokens leaves the existing value
|
||||
// unchanged; Temperature is copied verbatim.
|
||||
func WithOptions(opts Options) Option {
|
||||
return func(a *Agent) {
|
||||
if opts.Model != "" {
|
||||
a.opts.Model = opts.Model
|
||||
}
|
||||
a.opts.Temperature = opts.Temperature
|
||||
if opts.MaxRounds != 0 {
|
||||
a.opts.MaxRounds = opts.MaxRounds
|
||||
}
|
||||
if opts.Purpose != "" {
|
||||
a.opts.Purpose = opts.Purpose
|
||||
}
|
||||
if opts.MaxTokens != 0 {
|
||||
a.opts.MaxTokens = opts.MaxTokens
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithRecorder wires a CallRecord sink. After each successful model call the
|
||||
// agent emits one CallRecord to the recorder.
|
||||
func WithRecorder(r model.Recorder) Option {
|
||||
return func(a *Agent) { a.recorder = r }
|
||||
}
|
||||
|
||||
// WithHandoff sets the agent's handoff-target placeholder (M3 orchestration).
|
||||
func WithHandoff(h *Handoff) Option {
|
||||
return func(a *Agent) { a.handoff = h }
|
||||
}
|
||||
|
||||
// validateOptions rejects out-of-range option values so bad config fails at
|
||||
// construction rather than at request time.
|
||||
func validateOptions(o Options) error {
|
||||
if o.Temperature < minTemperature || o.Temperature > maxTemperature {
|
||||
return fmt.Errorf("%w: temperature %v out of range [%v, %v]", ErrBadOptions, o.Temperature, minTemperature, maxTemperature)
|
||||
}
|
||||
if o.MaxRounds < 0 {
|
||||
return fmt.Errorf("%w: max rounds %d", ErrBadOptions, o.MaxRounds)
|
||||
}
|
||||
if o.MaxTokens < 0 {
|
||||
return fmt.Errorf("%w: max tokens %d", ErrBadOptions, o.MaxTokens)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in new issue
Block a user