feat: first-class skill packs on agents + ship gifsmith builtin
executus CI / test (push) Successful in 3m21s
executus CI / test (push) Successful in 3m21s
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>
This commit is contained in:
@@ -44,6 +44,11 @@ type RunnableAgent struct {
|
||||
LowLevelTools []string
|
||||
SkillPalette []string
|
||||
SubAgentPalette []string
|
||||
// SkillPacks names SKILL.md skill-pack subscriptions activated for the run
|
||||
// via Ports.SkillPacks: each pack's name+description joins a catalog folded
|
||||
// into the system prompt, and a skill_use tool loads a pack's body on demand
|
||||
// (progressive disclosure). nil Ports.SkillPacks => inert.
|
||||
SkillPacks []string
|
||||
|
||||
// Phases optionally model a multi-step pipeline (each phase its own prompt
|
||||
// + tier + tools). An empty slice is a single-phase run — the common case.
|
||||
|
||||
@@ -275,6 +275,32 @@ func (e *Executor) Run(ctx context.Context, ra RunnableAgent, inv tool.Invocatio
|
||||
postRun = st.PostRun
|
||||
}
|
||||
|
||||
// Skill packs: resolve the agent's subscribed packs into a catalog (folded
|
||||
// into the system prompt) + a skill_use loader tool added to the toolbox.
|
||||
// nil-safe; activation failures are non-fatal — the run proceeds without
|
||||
// packs rather than dying on a fetch/cache miss.
|
||||
if len(ra.SkillPacks) > 0 && e.cfg.Ports.SkillPacks != nil {
|
||||
instr, packTools, aerr := e.cfg.Ports.SkillPacks.ActivateSkillPacks(ctx, ra.SkillPacks, inv.RunID, ra.ID)
|
||||
if aerr != nil {
|
||||
slog.Warn("run: skill-pack activation failed; continuing without packs", "run_id", inv.RunID, "error", aerr)
|
||||
} else {
|
||||
for _, t := range packTools {
|
||||
if err := toolbox.Add(t); err != nil {
|
||||
res.Err = fmt.Errorf("add skill-pack tool: %w", err)
|
||||
e.finishAudit(ctx, rec, "error", res, started, res.Err)
|
||||
return res
|
||||
}
|
||||
}
|
||||
if instr != "" {
|
||||
if ra.SystemPrompt != "" {
|
||||
ra.SystemPrompt += "\n\n" + instr
|
||||
} else {
|
||||
ra.SystemPrompt = instr
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Run context: detached from the caller's deadline so a lane/queue wait doesn't
|
||||
// eat the run budget (mort's V10 lesson). Caller cancellation still propagates
|
||||
// via MergeCancellation. Created BEFORE the step observer so the observer
|
||||
|
||||
@@ -49,6 +49,22 @@ type Ports struct {
|
||||
// are silently ignored (the run still proceeds, text-only). The bytes are
|
||||
// never inlined into the model context — the LLM can't read raw audio/binary.
|
||||
InputFiles InputFileStager
|
||||
// SkillPacks activates a RunnableAgent.SkillPacks (SKILL.md subscriptions)
|
||||
// for the run: it folds a catalog into the system prompt and adds a skill_use
|
||||
// loader tool. nil = SkillPacks are inert. The executus/skillpack battery
|
||||
// ships a default impl (skillpack.Activator).
|
||||
SkillPacks SkillPackActivator
|
||||
}
|
||||
|
||||
// SkillPackActivator resolves an agent's subscribed skill-pack names for a run
|
||||
// into system-prompt instructions (a catalog of what's available on demand) and
|
||||
// the tools that back them (a single skill_use loader). It receives the run +
|
||||
// subject ids so the impl can scope any per-run file staging. It returns "" +
|
||||
// nil when nothing resolves; activation errors are non-fatal to the run. Defined
|
||||
// here (the consumer) so the battery satisfies it structurally without importing
|
||||
// run — the same inversion as the other ports.
|
||||
type SkillPackActivator interface {
|
||||
ActivateSkillPacks(ctx context.Context, names []string, runID, subjectID string) (instructions string, tools []llm.Tool, err error)
|
||||
}
|
||||
|
||||
// InputFileStager persists a single non-image input attachment into a host file
|
||||
|
||||
Reference in New Issue
Block a user