Files
majordomo/skill/skill.go
steve 76ecf0e49e 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>
2026-06-10 13:13:07 +02:00

67 lines
2.1 KiB
Go

// 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 }