diff --git a/actions/setup/js/safe_output_type_validator.cjs b/actions/setup/js/safe_output_type_validator.cjs index d9de7359671..7f47cb7d1f1 100644 --- a/actions/setup/js/safe_output_type_validator.cjs +++ b/actions/setup/js/safe_output_type_validator.cjs @@ -409,6 +409,15 @@ function validateField(value, fieldName, validation, itemType, lineNum, options) } if (validation.type === "array") { + // Backward compatibility: create_issue agents sometimes provide comma-separated labels as a string. + // Normalize this into a string array before strict array validation. + if (itemType === "create_issue" && fieldName === "labels" && typeof value === "string") { + value = value + .split(",") + .map(item => item.trim()) + .filter(Boolean); + } + if (!Array.isArray(value)) { // For required fields, use "requires a" format for both missing and wrong type if (validation.required) { diff --git a/actions/setup/js/safe_output_type_validator.test.cjs b/actions/setup/js/safe_output_type_validator.test.cjs index 723e49cb428..d628a74c626 100644 --- a/actions/setup/js/safe_output_type_validator.test.cjs +++ b/actions/setup/js/safe_output_type_validator.test.cjs @@ -873,6 +873,15 @@ describe("safe_output_type_validator", () => { expect(Array.isArray(result.normalizedItem.labels)).toBe(true); }); + it("should normalize comma-separated labels string to array", async () => { + const { validateItem } = await import("./safe_output_type_validator.cjs"); + + const result = validateItem({ type: "create_issue", title: "Test", body: "Detailed issue body text.", labels: "reliability, telemetry" }, "create_issue", 1); + + expect(result.isValid).toBe(true); + expect(result.normalizedItem.labels).toEqual(["reliability", "telemetry"]); + }); + it("should reject array with non-string items", async () => { const { validateItem } = await import("./safe_output_type_validator.cjs"); diff --git a/actions/setup/js/safe_outputs_tools.json b/actions/setup/js/safe_outputs_tools.json index 8746d177dc2..60d9d499eb1 100644 --- a/actions/setup/js/safe_outputs_tools.json +++ b/actions/setup/js/safe_outputs_tools.json @@ -1,7 +1,7 @@ [ { "name": "create_issue", - "description": "WRITE-ONCE: do NOT call this tool with empty or placeholder arguments to probe or discover its schema \u2014 required fields (title, body) are listed in this schema; if you are not ready to open the real issue, call `noop` instead. Creates a new GitHub issue for tracking bugs, feature requests, or tasks. Use this for actionable work items that need assignment, labeling, and status tracking. For reports, announcements, or status updates that don't require task tracking, use create_discussion instead.", + "description": "WRITE-ONCE: do NOT call this tool with empty or placeholder arguments to probe or discover its schema \u2014 required fields (title, body) are listed in this schema; if you are not ready to open the real issue, call `noop` instead. Creates a new GitHub issue for tracking bugs, feature requests, or tasks. Use this for actionable work items that need assignment, labeling, and status tracking. For reports, announcements, or status updates that don't require task tracking, use create_discussion instead. Compatibility: labels may be passed as either an array of strings or a comma-separated string; string input is split, trimmed, and normalized to an array.", "inputSchema": { "type": "object", "required": ["title", "body"], @@ -16,11 +16,11 @@ "description": "Detailed issue description in Markdown. Must be the final intended body \u2014 not a placeholder or test value. Do NOT repeat the title as a heading since it already appears as the issue's h1. Include context, reproduction steps, or acceptance criteria as appropriate." }, "labels": { - "type": "array", + "type": ["array", "string"], "items": { "type": "string" }, - "description": "Labels to categorize the issue (e.g., 'bug', 'enhancement'). Labels must exist in the repository." + "description": "Labels to categorize the issue (e.g., 'bug', 'enhancement'). Labels must exist in the repository. Accepts either an array of strings or a comma-separated string; string input is split on commas, trimmed, and normalized to an array." }, "fields": { "type": "array", diff --git a/docs/src/content/docs/specs/safe-outputs-specification.md b/docs/src/content/docs/specs/safe-outputs-specification.md index e73a56edf49..2b7a950963b 100644 --- a/docs/src/content/docs/specs/safe-outputs-specification.md +++ b/docs/src/content/docs/specs/safe-outputs-specification.md @@ -875,7 +875,7 @@ Compiler generates tool schemas: "properties": { "title": {"type": "string"}, "body": {"type": "string"}, - "labels": {"type": "array", "items": {"type": "string"}} + "labels": {"type": ["array", "string"], "items": {"type": "string"}} } } } @@ -1993,14 +1993,14 @@ Schema-only updates without matching agent/runtime sync updates **MUST NOT** be ```json { "name": "create_issue", - "description": "Create a new GitHub issue for tracking bugs, feature requests, or tasks.", + "description": "Create a new GitHub issue for tracking bugs, feature requests, or tasks. Compatibility: labels may be passed as an array or comma-separated string.", "inputSchema": { "type": "object", "required": ["title", "body"], "properties": { "title": {"type": "string", "description": "Issue title"}, "body": {"type": "string", "description": "Issue description in Markdown"}, - "labels": {"type": "array", "items": {"type": "string"}}, + "labels": {"type": ["array", "string"], "items": {"type": "string"}}, "fields": { "type": "array", "items": { diff --git a/pkg/workflow/js/safe_outputs_tools.json b/pkg/workflow/js/safe_outputs_tools.json index 35d34aa915b..ec317e84389 100644 --- a/pkg/workflow/js/safe_outputs_tools.json +++ b/pkg/workflow/js/safe_outputs_tools.json @@ -1,7 +1,7 @@ [ { "name": "create_issue", - "description": "WRITE-ONCE: do NOT call this tool with empty or placeholder arguments to probe or discover its schema \u2014 required fields (title, body) are listed in this schema; if you are not ready to open the real issue, call `noop` instead. Creates a new GitHub issue for tracking bugs, feature requests, or tasks. Use this for actionable work items that need assignment, labeling, and status tracking. For reports, announcements, or status updates that don't require task tracking, use create_discussion instead.", + "description": "WRITE-ONCE: do NOT call this tool with empty or placeholder arguments to probe or discover its schema \u2014 required fields (title, body) are listed in this schema; if you are not ready to open the real issue, call `noop` instead. Creates a new GitHub issue for tracking bugs, feature requests, or tasks. Use this for actionable work items that need assignment, labeling, and status tracking. For reports, announcements, or status updates that don't require task tracking, use create_discussion instead. Compatibility: labels may be passed as either an array of strings or a comma-separated string; string input is split, trimmed, and normalized to an array.", "inputSchema": { "type": "object", "required": [ @@ -19,11 +19,14 @@ "description": "Detailed issue description in Markdown. Must be the final intended body \u2014 not a placeholder or test value. Do NOT repeat the title as a heading since it already appears as the issue's h1. Include context, reproduction steps, or acceptance criteria as appropriate." }, "labels": { - "type": "array", + "type": [ + "array", + "string" + ], "items": { "type": "string" }, - "description": "Labels to categorize the issue (e.g., 'bug', 'enhancement'). Labels must exist in the repository." + "description": "Labels to categorize the issue (e.g., 'bug', 'enhancement'). Labels must exist in the repository. Accepts either an array of strings or a comma-separated string; string input is split on commas, trimmed, and normalized to an array." }, "fields": { "type": "array", diff --git a/schemas/agent-output.json b/schemas/agent-output.json index aca093c99bd..38d1049c161 100644 --- a/schemas/agent-output.json +++ b/schemas/agent-output.json @@ -77,8 +77,8 @@ "minLength": 1 }, "labels": { - "type": "array", - "description": "Optional labels to add to the issue", + "type": ["array", "string"], + "description": "Optional labels to add to the issue. Accepts an array of strings or a comma-separated string (e.g. \"bug, reliability\") that is normalized into an array.", "items": { "type": "string" }