Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions agent/skills/fsskills/source.go
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,9 @@ func validateExtensions(extensions []string) {
}

func newScript(name string, fsys fs.FS, runner skills.ScriptRunner) skills.Script {
additionalProperties := map[string]any{
"fsskills.scriptFS": fsys,
}
return skills.Script{
Name: name,
ParametersSchema: defaultFileScriptSchema,
Expand All @@ -558,12 +561,18 @@ func newScript(name string, fsys fs.FS, runner skills.ScriptRunner) skills.Scrip
if runner == nil {
return nil, fmt.Errorf("script %q cannot be executed because no file script runner was provided", name)
}
script := &skills.Script{Name: name}
// Hand the runner a script carrying the same metadata the
// discovered Script exposes (parameters schema and the backing
// fs.FS), so runners that inspect them to locate/execute the
// file see the real values instead of empty ones.
script := &skills.Script{
Name: name,
ParametersSchema: defaultFileScriptSchema,
AdditionalProperties: additionalProperties,
}
return runner(ctx, owner, script, arguments)
},
AdditionalProperties: map[string]any{
"fsskills.scriptFS": fsys,
},
AdditionalProperties: additionalProperties,
}
}

Expand Down
32 changes: 32 additions & 0 deletions agent/skills/fsskills/source_script_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -493,3 +493,35 @@ func TestFileSkill_ScriptContent_IncludesDefaultArraySchema(t *testing.T) {
t.Fatalf("expected JSON quotes to be preserved in schema content, got: %s", content)
}
}

// The runner-facing *Script must carry the same metadata as the discovered
// Script (parameters schema and the fsskills.scriptFS backing FS), otherwise a
// runner that inspects those fields to locate/execute the file sees empty values.
func TestFileSource_Runner_ReceivesScriptMetadata(t *testing.T) {
root := t.TempDir()
createSkillDir(t, root, "meta-skill", "Metadata test", "Body.")
createRelativeFile(t, filepath.Join(root, "meta-skill"), "scripts/test.py", "print('ok')")

var gotSchema string
var gotFS any
var hasFSKey bool
source := fsskills.NewSourceOptions(fsskills.SourceOptions{ScriptRunner: func(_ context.Context, _ *skills.Skill, script *skills.Script, _ []string) (any, error) {
gotSchema = script.ParametersSchema
gotFS, hasFSKey = script.AdditionalProperties["fsskills.scriptFS"]
return "ok", nil
}}, os.DirFS(root))

loaded, err := source.Skills(t.Context())
if err != nil {
t.Fatal(err)
}
if _, err := loaded[0].Scripts[0].Run(t.Context(), loaded[0], nil); err != nil {
t.Fatal(err)
}
if gotSchema == "" {
t.Errorf("runner received empty ParametersSchema; want the discovered script's schema")
}
if !hasFSKey || gotFS == nil {
t.Errorf("runner received no fsskills.scriptFS in AdditionalProperties (hasKey=%v value=%v)", hasFSKey, gotFS)
}
}