diff --git a/docs/src/content/docs/agent-factory-status.mdx b/docs/src/content/docs/agent-factory-status.mdx index d3d8fdfabc..8ba7e7f401 100644 --- a/docs/src/content/docs/agent-factory-status.mdx +++ b/docs/src/content/docs/agent-factory-status.mdx @@ -83,10 +83,14 @@ These are experimental agentic workflows used by the GitHub Next team to learn, | [Example: Properly Provisioned Permissions](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/example-permissions-warning.md) | copilot | [![Example: Properly Provisioned Permissions](https://github.com/githubnext/gh-aw/actions/workflows/example-permissions-warning.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/example-permissions-warning.lock.yml) | - | - | | [Firewall Test Agent](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/firewall.md) | copilot | [![Firewall Test Agent](https://github.com/githubnext/gh-aw/actions/workflows/firewall.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/firewall.lock.yml) | - | - | <<<<<<< HEAD +| [Functional Pragmatist](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/functional-pragmatist.md) | copilot | [![Functional Pragmatist](https://github.com/githubnext/gh-aw/actions/workflows/functional-pragmatist.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/functional-pragmatist.lock.yml) | `0 9 * * 2,4` | - | +======= +<<<<<<< HEAD | [Functional Enhancer](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/functional-enhancer.md) | claude | [![Functional Enhancer](https://github.com/githubnext/gh-aw/actions/workflows/functional-enhancer.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/functional-enhancer.lock.yml) | `0 9 * * 2,4` | - | ======= | [Functional Pragmatist](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/functional-programming-enhancer.md) | claude | [![Functional Pragmatist](https://github.com/githubnext/gh-aw/actions/workflows/functional-programming-enhancer.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/functional-programming-enhancer.lock.yml) | `0 9 * * 2,4` | - | >>>>>>> ba904f257b69bfcc9738b01ca4c61995b23506a4 +>>>>>>> origin/main | [GitHub MCP Remote Server Tools Report Generator](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/github-mcp-tools-report.md) | claude | [![GitHub MCP Remote Server Tools Report Generator](https://github.com/githubnext/gh-aw/actions/workflows/github-mcp-tools-report.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/github-mcp-tools-report.lock.yml) | - | - | | [GitHub MCP Structural Analysis](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/github-mcp-structural-analysis.md) | claude | [![GitHub MCP Structural Analysis](https://github.com/githubnext/gh-aw/actions/workflows/github-mcp-structural-analysis.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/github-mcp-structural-analysis.lock.yml) | `0 11 * * 1-5` | - | | [GitHub Remote MCP Authentication Test](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/github-remote-mcp-auth-test.md) | copilot | [![GitHub Remote MCP Authentication Test](https://github.com/githubnext/gh-aw/actions/workflows/github-remote-mcp-auth-test.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/github-remote-mcp-auth-test.lock.yml) | - | - | diff --git a/pkg/workflow/data/action_pins.json b/pkg/workflow/data/action_pins.json index 80130e4a1a..2db5179bb9 100644 --- a/pkg/workflow/data/action_pins.json +++ b/pkg/workflow/data/action_pins.json @@ -100,7 +100,7 @@ "version": "v5.6.0", "sha": "a26af69be951a213d495a4c3e4e4022e16d87065" }, - "actions/upload-artifact@v4": { + "actions/upload-artifact@v4.6.2": { "repo": "actions/upload-artifact", "version": "v4.6.2", "sha": "ea165f8d65b6e75b540449e92b4886f43607fa02" diff --git a/pkg/workflow/prompts_test.go b/pkg/workflow/prompts_test.go index 6a7fec6811..63def6a86e 100644 --- a/pkg/workflow/prompts_test.go +++ b/pkg/workflow/prompts_test.go @@ -72,6 +72,60 @@ func TestSafeOutputsPromptText_FollowsXMLFormat(t *testing.T) { t.Skip("Safe outputs prompt is now generated dynamically based on enabled tools") } +func TestSafeOutputsPrompt_NeverListsToolNames(t *testing.T) { + // CRITICAL: This test ensures tool names are NEVER listed in the safe outputs prompt. + // The agent must query the MCP server to discover available tools - listing them + // directly causes the agent to try accessing them before MCP setup is complete. + compiler := &Compiler{} + var yaml strings.Builder + + // Create a config with multiple safe outputs enabled + safeOutputs := &SafeOutputsConfig{ + CreateIssues: &CreateIssuesConfig{}, + AddComments: &AddCommentsConfig{}, + CreateDiscussions: &CreateDiscussionsConfig{}, + UpdateIssues: &UpdateIssuesConfig{}, + } + + data := &WorkflowData{ + ParsedTools: NewTools(map[string]any{}), + SafeOutputs: safeOutputs, + } + + compiler.generateUnifiedPromptStep(&yaml, data) + output := yaml.String() + + // Verify safe outputs section exists + if !strings.Contains(output, "") { + t.Fatal("Expected safe outputs section in generated prompt") + } + + // CRITICAL: Ensure tool names are NEVER listed in the prompt + forbiddenToolNames := []string{ + "create_issue", + "add_comment", + "create_discussion", + "update_issue", + "update_pull_request", + "close_issue", + "close_pull_request", + "create_pull_request", + "add_labels", + "remove_labels", + } + + for _, toolName := range forbiddenToolNames { + if strings.Contains(output, toolName) { + t.Errorf("CRITICAL: Safe outputs prompt must NOT list tool name %q. Agent should discover tools via MCP server query.", toolName) + } + } + + // Verify the correct instruction is present + if !strings.Contains(output, "Discover available tools from the safeoutputs MCP server") { + t.Error("Expected prompt to instruct agent to query MCP server for tools") + } +} + // ============================================================================ // Cache Memory Prompt Tests // ============================================================================ diff --git a/pkg/workflow/safe_outputs_config_helpers.go b/pkg/workflow/safe_outputs_config_helpers.go index bf1af479fe..175616e630 100644 --- a/pkg/workflow/safe_outputs_config_helpers.go +++ b/pkg/workflow/safe_outputs_config_helpers.go @@ -30,8 +30,10 @@ func HasSafeOutputsEnabled(safeOutputs *SafeOutputsConfig) bool { return enabled } -// GetEnabledSafeOutputToolNames returns a list of enabled safe output tool names -// that can be used in the prompt to inform the agent which tools are available +// GetEnabledSafeOutputToolNames returns a list of enabled safe output tool names. +// NOTE: Tool names should NOT be included in agent prompts. The agent should query +// the MCP server to discover available tools. This function is used for generating +// the tools.json file that the MCP server provides, and for diagnostic logging. func GetEnabledSafeOutputToolNames(safeOutputs *SafeOutputsConfig) []string { tools := getEnabledSafeOutputToolNamesReflection(safeOutputs) diff --git a/pkg/workflow/unified_prompt_step.go b/pkg/workflow/unified_prompt_step.go index 31152251b1..6eea1028c3 100644 --- a/pkg/workflow/unified_prompt_step.go +++ b/pkg/workflow/unified_prompt_step.go @@ -272,10 +272,8 @@ func (c *Compiler) collectPromptSections(data *WorkflowData) []PromptSection { // 7. Safe outputs instructions (if enabled) if HasSafeOutputsEnabled(data.SafeOutputs) { - enabledTools := GetEnabledSafeOutputToolNames(data.SafeOutputs) - if len(enabledTools) > 0 { - unifiedPromptLog.Printf("Adding safe outputs section: tools=%d", len(enabledTools)) - safeOutputsContent := ` + unifiedPromptLog.Print("Adding safe outputs section") + safeOutputsContent := ` GitHub API Access Instructions The gh CLI is NOT authenticated. Do NOT use gh commands for GitHub operations. @@ -290,11 +288,10 @@ Discover available tools from the safeoutputs MCP server. **Note**: If you made no other safe output tool calls during this workflow execution, call the "noop" tool to provide a status message indicating completion or that no actions were needed. ` - sections = append(sections, PromptSection{ - Content: safeOutputsContent, - IsFile: false, - }) - } + sections = append(sections, PromptSection{ + Content: safeOutputsContent, + IsFile: false, + }) } // 8. GitHub context (if GitHub tool is enabled)