feat: skills — additive instruction+tool bundles, clock + calc examples
Phase 6: skill.New constructor satisfying the agent.Skill contract; instruction-only skills; ordered additive composition; skill/clock (injectable-clock time tools) and skill/calc (recursive-descent arithmetic evaluator) as ready-made examples with full test suites incl. an agent-loop round trip. ADR-0013; README skills section + matrix synced. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
// Package skill provides reusable capability bundles for agents: a named
|
||||
// set of instructions (appended to the agent's system prompt) plus optional
|
||||
// tools (joined into the agent's toolset). Skills attach to ANY agent, at
|
||||
// construction (agent.WithSkill) or on demand (Agent.AddSkill), and compose
|
||||
// additively in attachment order.
|
||||
//
|
||||
// The contract a skill satisfies is the agent.Skill interface; this package
|
||||
// is the standard way to build one without writing a type:
|
||||
//
|
||||
// research := skill.New("research",
|
||||
// skill.WithInstructions("Cite sources for every claim."),
|
||||
// skill.WithTools(searchTool, fetchTool),
|
||||
// )
|
||||
// a.AddSkill(research)
|
||||
//
|
||||
// Two ready-made example skills ship as subpackages: clock (time awareness)
|
||||
// and calc (exact arithmetic).
|
||||
package skill
|
||||
|
||||
import "gitea.stevedudenhoeffer.com/steve/majordomo/llm"
|
||||
|
||||
// Skill is a buildable instruction+tool bundle. The zero value is unusable;
|
||||
// construct with New.
|
||||
type Skill struct {
|
||||
name string
|
||||
instructions string
|
||||
toolbox *llm.Toolbox
|
||||
}
|
||||
|
||||
// Option configures a Skill under construction.
|
||||
type Option func(*Skill)
|
||||
|
||||
// WithInstructions sets the text appended to the agent's system prompt.
|
||||
func WithInstructions(s string) Option {
|
||||
return func(sk *Skill) { sk.instructions = s }
|
||||
}
|
||||
|
||||
// WithToolbox attaches the skill's tools as an existing toolbox.
|
||||
func WithToolbox(b *llm.Toolbox) Option {
|
||||
return func(sk *Skill) { sk.toolbox = b }
|
||||
}
|
||||
|
||||
// WithTools attaches loose tools (wrapped in a toolbox named after the
|
||||
// skill).
|
||||
func WithTools(tools ...llm.Tool) Option {
|
||||
return func(sk *Skill) { sk.toolbox = llm.NewToolbox(sk.name, tools...) }
|
||||
}
|
||||
|
||||
// New builds a skill.
|
||||
func New(name string, opts ...Option) *Skill {
|
||||
sk := &Skill{name: name}
|
||||
for _, opt := range opts {
|
||||
opt(sk)
|
||||
}
|
||||
return sk
|
||||
}
|
||||
|
||||
// Name identifies the skill (used in duplicate-tool diagnostics).
|
||||
func (s *Skill) Name() string { return s.name }
|
||||
|
||||
// Instructions returns the system-prompt extension; may be empty.
|
||||
func (s *Skill) Instructions() string { return s.instructions }
|
||||
|
||||
// Tools returns the skill's toolbox; may be nil for instruction-only
|
||||
// skills.
|
||||
func (s *Skill) Tools() *llm.Toolbox { return s.toolbox }
|
||||
Reference in New Issue
Block a user