feat(capability/skills): 可复用工作流技能(Skill 模型 + Store + YAML Loader + Runner 展开 + 注册)
This commit is contained in:
1 parent
d947ec41a9
commit
915aa8a100
10 files changed
+1235
No files matched your search
@@ -0,0 +1,86 @@
|
||||
package skills
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"strings"
|
||||
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/capability/registry"
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/pkg/plugins/sdk"
|
||||
)
|
||||
|
||||
// Workflow is a Skill expanded into its executable form: the base system prompt
|
||||
// plus the ordered steps, references, and guardrails, ready to be handed to the
|
||||
// loop/agent executor (M2). The Runner only assembles workflows; it does not
|
||||
// execute commands.
|
||||
type Workflow struct {
|
||||
Name string
|
||||
Description string
|
||||
Prompt string
|
||||
Steps []sdk.Step
|
||||
Refs []sdk.Ref
|
||||
Guardrails []sdk.Guardrail
|
||||
}
|
||||
|
||||
// Runner expands skills into workflows. It is the M5 placeholder for the
|
||||
// skill-execution wrapper: expansion (the real deliverable) is wired now, while
|
||||
// Run awaits M12/loop integration.
|
||||
type Runner struct {
|
||||
reg *registry.Registry
|
||||
log *slog.Logger
|
||||
}
|
||||
|
||||
// NewRunner builds a Runner over the given registry, used by ExpandByName to
|
||||
// look up registered skills. log may be nil.
|
||||
func NewRunner(reg *registry.Registry, log *slog.Logger) *Runner {
|
||||
return &Runner{reg: reg, log: sourcedLog(log)}
|
||||
}
|
||||
|
||||
// Expand converts s into a Workflow, copying the step, ref, and guardrail slices
|
||||
// so the caller owns the result. It returns ErrInvalidSkill when s is nil or has
|
||||
// a blank name.
|
||||
func (r *Runner) Expand(ctx context.Context, s sdk.Skill) (Workflow, error) {
|
||||
if err := ctx.Err(); err != nil {
|
||||
return Workflow{}, fmt.Errorf("skills: runner: expand: %w", err)
|
||||
}
|
||||
if s == nil || strings.TrimSpace(s.Name()) == "" {
|
||||
return Workflow{}, fmt.Errorf("skills: runner: expand: %w", ErrInvalidSkill)
|
||||
}
|
||||
wf := Workflow{
|
||||
Name: s.Name(),
|
||||
Description: s.Description(),
|
||||
Prompt: s.Prompt(),
|
||||
Steps: cloneSteps(s.Steps()),
|
||||
Refs: cloneRefs(s.Refs()),
|
||||
Guardrails: cloneGuardrails(s.Guardrails()),
|
||||
}
|
||||
r.log.Info("skill expanded", "skill", wf.Name)
|
||||
return wf, nil
|
||||
}
|
||||
|
||||
// ExpandByName looks up a skill in the registry by name and expands it. It
|
||||
// returns ErrNilRegistrar when the runner has no registry, the registry's error
|
||||
// (registry.ErrNotFound) when the name is absent, and ErrNotFound when the
|
||||
// registered value is not a Skill.
|
||||
func (r *Runner) ExpandByName(ctx context.Context, name string) (Workflow, error) {
|
||||
if r.reg == nil {
|
||||
return Workflow{}, fmt.Errorf("skills: runner: expand %q: %w", name, ErrNilRegistrar)
|
||||
}
|
||||
cap, err := r.reg.Get(name)
|
||||
if err != nil {
|
||||
return Workflow{}, fmt.Errorf("skills: runner: expand %q: %w", name, err)
|
||||
}
|
||||
skill, ok := cap.Value.(sdk.Skill)
|
||||
if !ok {
|
||||
return Workflow{}, fmt.Errorf("skills: runner: expand %q: %w", name, ErrNotFound)
|
||||
}
|
||||
return r.Expand(ctx, skill)
|
||||
}
|
||||
|
||||
// Run is a placeholder for executing a registered skill end to end. Execution
|
||||
// lands in the loop/agent executor (M2) and the full wiring (M12); it always
|
||||
// returns ErrRunPending.
|
||||
func (r *Runner) Run(_ context.Context, _ string, _ any) (any, error) {
|
||||
return nil, ErrRunPending
|
||||
}
|
||||
Reference in new issue
Block a user