Files
executus/skillpack/activator.go
T
steve 8ecdadf8b8
executus CI / test (push) Successful in 3m21s
feat: first-class skill packs on agents + ship gifsmith builtin
Lifts the 'an agent uses a SKILL.md pack' concept out of a host and into the
harness:
- run.Ports.SkillPacks (SkillPackActivator) — nil-safe port; the executor folds
  a loaded agent's pack catalog into the system prompt and adds a skill_use
  loader tool to the toolbox (uses the existing ra.SystemPrompt + toolbox seams)
- run.RunnableAgent.SkillPacks + persona.Agent.SkillPacks (+ skill_packs YAML,
  extends-inherit, ToRunnable) — the Agent noun is now pack-aware
- skillpack.Activator — the battery's default port impl (resolve names → packs →
  catalog + skill_use), with a per-run BundleStager factory the host plumbs;
  satisfies the port structurally (no import of run)
- agentbuiltins: ships gifsmith, a portable focused GIF/MP4 render agent that
  uses the gif pack — references tool/tier/pack NAMES only, no host coupling

A host now wires run.Ports.SkillPacks instead of carrying its own activation
glue. Tests: Activator resolution + gifsmith loads through persona→RunnableAgent.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 01:05:58 -04:00

59 lines
1.8 KiB
Go

package skillpack
import (
"context"
"errors"
"gitea.stevedudenhoeffer.com/steve/majordomo/llm"
)
// Activator adapts the battery to executus/run's SkillPackActivator port: given
// an agent's subscribed pack names, it resolves them to their pinned packs and
// returns the catalog instructions + the skill_use tool the run injects. It
// satisfies run.SkillPackActivator structurally — no import of run — so the
// battery stays run-agnostic (the same inversion as the other batteries).
//
// StagerFor, when set, builds the per-run BundleStager (a host plumbs bundled
// files into its own run-scoped storage from the run + subject ids); nil means
// skill_use lists a pack's bundled filenames without staging them.
type Activator struct {
Cache PackCache
Subs Store
StagerFor func(runID, subjectID string) BundleStager
}
// ActivateSkillPacks implements run.SkillPackActivator. Unknown or disabled pack
// names are skipped; it returns "" + nil when nothing resolves.
func (a *Activator) ActivateSkillPacks(ctx context.Context, names []string, runID, subjectID string) (string, []llm.Tool, error) {
if a == nil || a.Subs == nil || a.Cache == nil || len(names) == 0 {
return "", nil, nil
}
chosen := make([]Subscription, 0, len(names))
for _, n := range names {
sub, err := a.Subs.GetByName(ctx, n)
if errors.Is(err, ErrNotFound) {
continue
}
if err != nil {
return "", nil, err
}
if !sub.Enabled {
continue
}
chosen = append(chosen, *sub)
}
packs, err := Resolve(ctx, a.Cache, chosen)
if err != nil {
return "", nil, err
}
var stager BundleStager
if a.StagerFor != nil {
stager = a.StagerFor(runID, subjectID)
}
sk := Activate(packs, stager)
if sk == nil {
return "", nil, nil
}
return sk.Instructions(), sk.Tools().Tools(), nil
}