diff --git a/docs/public/editor/autocomplete-data.json b/docs/public/editor/autocomplete-data.json index e1cd15cba2c..b24a883f0d1 100644 --- a/docs/public/editor/autocomplete-data.json +++ b/docs/public/editor/autocomplete-data.json @@ -546,12 +546,6 @@ } } }, - "disable-model-invocation": { - "type": "boolean", - "desc": "Controls whether the custom agent should disable model invocation.", - "enum": [true, false], - "leaf": true - }, "secrets": { "type": "object", "desc": "Secret values passed to workflow execution." @@ -1364,7 +1358,7 @@ }, "mode": { "type": "string", - "desc": "Integration mode: 'cli' (recommended) installs @playwright/cli via npm for token-efficient CLI invocations — use play...", + "desc": "Integration mode: 'cli' (recommended) installs @playwright/cli via npm for token-efficient CLI invocations \u2014 use play...", "enum": ["cli", "mcp"], "leaf": true } @@ -2648,7 +2642,6 @@ "steps", "post-steps", "features", - "disable-model-invocation", "secrets", "secret-masking", "bots", diff --git a/docs/scripts/generate-autocomplete-data.js b/docs/scripts/generate-autocomplete-data.js index c8c20e93184..99ad44944a1 100644 --- a/docs/scripts/generate-autocomplete-data.js +++ b/docs/scripts/generate-autocomplete-data.js @@ -36,7 +36,7 @@ const ROOT_SORT_ORDER = [ 'labels', 'metadata', 'tracker-id', 'source', 'run-name', 'runs-on', 'timeout-minutes', 'concurrency', 'environment', 'container', 'services', 'network', 'sandbox', 'plugins', 'if', 'steps', 'post-steps', - 'features', 'disable-model-invocation', 'secrets', + 'features', 'secrets', 'secret-masking', 'bots', 'user-rate-limit', 'strict', 'safe-inputs', 'runtimes', 'jobs', ]; diff --git a/pkg/constants/README.md b/pkg/constants/README.md index ad25289adc4..36f46b5eb70 100644 --- a/pkg/constants/README.md +++ b/pkg/constants/README.md @@ -405,7 +405,7 @@ constants.PriorityJobFields // []string{"name","runs-on","needs","if","per constants.PriorityWorkflowFields // []string{"on","permissions","if","network","imports",...} // Fields silently ignored during frontmatter validation -constants.IgnoredFrontmatterFields // []string{"user-invokable"} +constants.IgnoredFrontmatterFields // []string{} // Fields forbidden in shared/imported workflows (only valid in main workflows) constants.SharedWorkflowForbiddenFields // []string{"on","concurrency","container",...} diff --git a/pkg/constants/constants.go b/pkg/constants/constants.go index ee77ecb9ccd..d62e3b2fb68 100644 --- a/pkg/constants/constants.go +++ b/pkg/constants/constants.go @@ -314,8 +314,7 @@ var PriorityJobFields = []string{"name", "runs-on", "needs", "if", "permissions" var PriorityWorkflowFields = []string{"on", "permissions", "if", "network", "imports", "safe-outputs", "steps"} // IgnoredFrontmatterFields are fields that should be silently ignored during frontmatter validation -// NOTE: user-invokable is a GitHub Copilot custom agent field that is not part of the gh-aw schema -var IgnoredFrontmatterFields = []string{"user-invokable"} +var IgnoredFrontmatterFields = []string{} // SharedWorkflowForbiddenFields lists fields that cannot be used in shared/included workflows. // These fields are only allowed in main workflows (workflows with an 'on' trigger field). diff --git a/pkg/parser/schema_location_test.go b/pkg/parser/schema_location_test.go index 6a3076fd374..64e67559eec 100644 --- a/pkg/parser/schema_location_test.go +++ b/pkg/parser/schema_location_test.go @@ -530,3 +530,27 @@ func TestValidateMainWorkflowFrontmatterWithSchemaAndLocation_RejectsTopLevelCom t.Fatalf("expected unknown property error for command, got: %v", err) } } + +func TestValidateIncludedFileFrontmatterWithSchemaAndLocation_SkipsCustomAgentFiles(t *testing.T) { + // Custom agent files may contain Copilot-specific fields that are not in the + // gh-aw main workflow schema (e.g. user-invokable, disable-model-invocation, + // tools as an array). Schema validation must be skipped for these files. + agentFrontmatter := map[string]any{ + "description": "My custom agent", + "user-invokable": true, + "disable-model-invocation": false, + } + + agentPaths := []string{ + "/repo/.github/agents/my-agent.md", + ".github/agents/my-agent.md", + "/some/path/.github/agents/sub/helper.md", + } + + for _, path := range agentPaths { + err := ValidateIncludedFileFrontmatterWithSchemaAndLocation(agentFrontmatter, path) + if err != nil { + t.Errorf("expected custom agent file %q to pass validation without errors, got: %v", path, err) + } + } +} diff --git a/pkg/parser/schema_utilities_test.go b/pkg/parser/schema_utilities_test.go index 4f06fd4ee75..55d2e9f36a2 100644 --- a/pkg/parser/schema_utilities_test.go +++ b/pkg/parser/schema_utilities_test.go @@ -46,18 +46,6 @@ func TestFilterIgnoredFields(t *testing.T) { "engine": "claude", }, }, - { - name: "frontmatter with user-invokable - should be filtered", - frontmatter: map[string]any{ - "user-invokable": true, - "on": "push", - "engine": "claude", - }, - expected: map[string]any{ - "on": "push", - "engine": "claude", - }, - }, } for _, tt := range tests { diff --git a/pkg/parser/schema_validation.go b/pkg/parser/schema_validation.go index 984a3cd1c45..1d379f2164b 100644 --- a/pkg/parser/schema_validation.go +++ b/pkg/parser/schema_validation.go @@ -130,6 +130,14 @@ func ValidateMainWorkflowFrontmatterWithSchemaAndLocation(frontmatter map[string // ValidateIncludedFileFrontmatterWithSchemaAndLocation validates included file frontmatter with file location info func ValidateIncludedFileFrontmatterWithSchemaAndLocation(frontmatter map[string]any, filePath string) error { schemaValidationLog.Printf("Validating included file frontmatter: file=%s, fields=%d", filePath, len(frontmatter)) + + // Custom agent files (.github/agents/*.md) follow the Copilot agent format, + // which differs from the gh-aw workflow schema. Skip schema validation for them. + if isCustomAgentFile(filePath) { + schemaValidationLog.Printf("Skipping schema validation for custom agent file: %s", filePath) + return nil + } + // Filter out ignored fields before validation filtered := filterIgnoredFields(frontmatter)