diff --git a/agent/skills/fsskills/source.go b/agent/skills/fsskills/source.go index b1ef5b38..6ee46dbc 100644 --- a/agent/skills/fsskills/source.go +++ b/agent/skills/fsskills/source.go @@ -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, @@ -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, } } diff --git a/agent/skills/fsskills/source_script_test.go b/agent/skills/fsskills/source_script_test.go index 744fd889..445bf9fb 100644 --- a/agent/skills/fsskills/source_script_test.go +++ b/agent/skills/fsskills/source_script_test.go @@ -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) + } +}