From 302041fd8b7c74f6a6bb67d9c4b6986d34a8fd6e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Feb 2026 10:39:56 +0000 Subject: [PATCH 1/3] Initial plan From 125e77111742f66d8069e385b504d3f4c6e7e0d0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Feb 2026 10:46:41 +0000 Subject: [PATCH 2/3] Fix dispatch_workflow to wrap inputs properly When dispatch_workflow tools are called via MCP, the workflow inputs were being spread at the top level instead of being wrapped in an "inputs" property. This caused the handler to not recognize them. Changed the handler creation in attachHandlers() to properly wrap the tool arguments in an "inputs" property when creating the dispatch_workflow message. Updated tests to verify the inputs are properly wrapped. Co-authored-by: mnkiefer <8320933+mnkiefer@users.noreply.github.com> --- actions/setup/js/safe_outputs_tools_loader.cjs | 14 +++++--------- .../setup/js/safe_outputs_tools_loader.test.cjs | 17 +++++++++-------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/actions/setup/js/safe_outputs_tools_loader.cjs b/actions/setup/js/safe_outputs_tools_loader.cjs index 5d5af91538..56df445b7d 100644 --- a/actions/setup/js/safe_outputs_tools_loader.cjs +++ b/actions/setup/js/safe_outputs_tools_loader.cjs @@ -67,18 +67,14 @@ function attachHandlers(tools, handlers) { // Check if this is a dispatch_workflow tool (dynamic tool with workflow metadata) if (tool._workflow_name) { - // Create a custom handler that adds workflow_name and uses dispatch_workflow type + // Create a custom handler that wraps args in inputs and adds workflow_name const workflowName = tool._workflow_name; tool.handler = args => { - // Add workflow_name to the args and call default handler with dispatch_workflow type - const entry = { - ...args, + // Wrap args in inputs property to match dispatch_workflow schema + return handlers.defaultHandler("dispatch_workflow")({ + inputs: args, workflow_name: workflowName, - type: "dispatch_workflow", - }; - - // Use the default handler logic but with dispatch_workflow type - return handlers.defaultHandler("dispatch_workflow")({ ...args, workflow_name: workflowName }); + }); }; } }); diff --git a/actions/setup/js/safe_outputs_tools_loader.test.cjs b/actions/setup/js/safe_outputs_tools_loader.test.cjs index da322a9f00..9d428ea38b 100644 --- a/actions/setup/js/safe_outputs_tools_loader.test.cjs +++ b/actions/setup/js/safe_outputs_tools_loader.test.cjs @@ -190,7 +190,7 @@ describe("safe_outputs_tools_loader", () => { expect(defaultHandler).toHaveBeenCalledWith("dispatch_workflow"); }); - it("should include workflow_name in dispatch_workflow handler args", () => { + it("should wrap args in inputs property for dispatch_workflow handler", () => { const tools = [{ name: "ci_workflow", description: "CI workflow", _workflow_name: "ci" }]; const mockHandlerFunction = vi.fn(); const defaultHandler = vi.fn(() => mockHandlerFunction); @@ -204,16 +204,17 @@ describe("safe_outputs_tools_loader", () => { const result = attachHandlers(tools, handlers); // Call the handler - const mockArgs = { input1: "value1" }; + const mockArgs = { input1: "value1", input2: "value2" }; result[0].handler(mockArgs); - // Verify the handler function was called with workflow_name - expect(mockHandlerFunction).toHaveBeenCalledWith( - expect.objectContaining({ - workflow_name: "ci", + // Verify the handler function was called with workflow_name and inputs wrapped + expect(mockHandlerFunction).toHaveBeenCalledWith({ + workflow_name: "ci", + inputs: { input1: "value1", - }) - ); + input2: "value2", + }, + }); }); }); From 3b7a1e083ae89fe0237f4718d298ba2e3338bacf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Feb 2026 10:58:35 +0000 Subject: [PATCH 3/3] Add tests for dispatch_workflow with no inputs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added comprehensive test coverage for workflows that have no input parameters: 1. dispatch_workflow.test.cjs - Test handler with missing inputs property 2. safe_outputs_tools_loader.test.cjs - Test handler with empty object and undefined args All cases are properly handled: - Empty object {} → inputs: {} is passed - undefined/missing → no inputs property (handler defaults to empty object) The dispatch_workflow handler already handles both cases correctly by initializing inputs as an empty object and only processing item.inputs if it exists. Co-authored-by: mnkiefer <8320933+mnkiefer@users.noreply.github.com> --- actions/setup/js/dispatch_workflow.test.cjs | 27 +++++++++++ .../js/safe_outputs_tools_loader.test.cjs | 46 +++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/actions/setup/js/dispatch_workflow.test.cjs b/actions/setup/js/dispatch_workflow.test.cjs index 73890a1a31..a11b4ef690 100644 --- a/actions/setup/js/dispatch_workflow.test.cjs +++ b/actions/setup/js/dispatch_workflow.test.cjs @@ -195,6 +195,33 @@ describe("dispatch_workflow handler factory", () => { ); }); + it("should handle workflows with no inputs", async () => { + const config = { + workflows: ["no-inputs-workflow"], + workflow_files: { + "no-inputs-workflow": ".lock.yml", + }, + }; + const handler = await main(config); + + // Test with inputs property missing entirely + const message = { + type: "dispatch_workflow", + workflow_name: "no-inputs-workflow", + }; + + const result = await handler(message, {}); + + expect(result.success).toBe(true); + expect(github.rest.actions.createWorkflowDispatch).toHaveBeenCalledWith({ + owner: "test-owner", + repo: "test-repo", + workflow_id: "no-inputs-workflow.lock.yml", + ref: expect.any(String), + inputs: {}, // Should pass empty object even when inputs property is missing + }); + }); + it("should delay 5 seconds between dispatches", async () => { const config = { workflows: ["workflow1", "workflow2"], diff --git a/actions/setup/js/safe_outputs_tools_loader.test.cjs b/actions/setup/js/safe_outputs_tools_loader.test.cjs index 9d428ea38b..f61aeb5f71 100644 --- a/actions/setup/js/safe_outputs_tools_loader.test.cjs +++ b/actions/setup/js/safe_outputs_tools_loader.test.cjs @@ -216,6 +216,52 @@ describe("safe_outputs_tools_loader", () => { }, }); }); + + it("should handle dispatch_workflow with no inputs (empty object)", () => { + const tools = [{ name: "no_inputs_workflow", description: "No inputs workflow", _workflow_name: "no-inputs" }]; + const mockHandlerFunction = vi.fn(); + const defaultHandler = vi.fn(() => mockHandlerFunction); + const handlers = { + createPullRequestHandler: vi.fn(), + pushToPullRequestBranchHandler: vi.fn(), + uploadAssetHandler: vi.fn(), + defaultHandler: defaultHandler, + }; + + const result = attachHandlers(tools, handlers); + + // Call the handler with empty object (typical for MCP tools with no inputs) + result[0].handler({}); + + // Verify inputs is still included as empty object + expect(mockHandlerFunction).toHaveBeenCalledWith({ + workflow_name: "no-inputs", + inputs: {}, + }); + }); + + it("should handle dispatch_workflow with undefined args", () => { + const tools = [{ name: "undefined_workflow", description: "Undefined workflow", _workflow_name: "undefined-test" }]; + const mockHandlerFunction = vi.fn(); + const defaultHandler = vi.fn(() => mockHandlerFunction); + const handlers = { + createPullRequestHandler: vi.fn(), + pushToPullRequestBranchHandler: vi.fn(), + uploadAssetHandler: vi.fn(), + defaultHandler: defaultHandler, + }; + + const result = attachHandlers(tools, handlers); + + // Call the handler with undefined (edge case) + result[0].handler(undefined); + + // When args is undefined, inputs should not be included + // The dispatch_workflow handler will handle missing inputs property + expect(mockHandlerFunction).toHaveBeenCalledWith({ + workflow_name: "undefined-test", + }); + }); }); describe("registerPredefinedTools", () => {