diff --git a/.github/workflows/daily-cli-tools-tester.md b/.github/workflows/daily-cli-tools-tester.md index 8077a908e7f..1ce93aefa5b 100644 --- a/.github/workflows/daily-cli-tools-tester.md +++ b/.github/workflows/daily-cli-tools-tester.md @@ -47,8 +47,8 @@ When problems are detected, create detailed GitHub issues with reproduction step **MANDATORY**: Follow these rules on every tool call to keep token consumption under control. - **`logs` calls**: Always pass `count: 3` and `max_tokens: 3000`. Never call `logs` without these limits. -- **`audit` calls**: Always pass `max_tokens: 5000`. Prefer auditing 1–2 representative runs rather than every run found. -- **`compile` calls**: Always pass `max_tokens: 5000`. Use targeted compilation of 3 representative workflows instead of bulk compilation when the goal is validation. +- **`audit` calls**: Prefer auditing 1–2 representative runs rather than every run found. +- **`compile` calls**: Use targeted compilation of 3 representative workflows instead of bulk compilation when the goal is validation. - **Parallel batching**: Combine independent tool calls into a single turn whenever possible (e.g. run 2–3 targeted compiles in parallel rather than sequentially). - **Skip redundant variants**: If a test variant (e.g. a second date-range filter) would produce essentially the same signal as one already run, skip it and document the skip reason. @@ -338,8 +338,8 @@ Test compilation with a targeted sample of representative workflows instead of b ``` Select 3 representative workflows from Phase 1.2 (one simple, one complex, one with imports). -Use the agentic-workflows "compile" tool for each individually (max_tokens: 5000 per call). -After the targeted tests, run one bulk compile (no workflow-name specified) with max_tokens: 5000 +Use the agentic-workflows "compile" tool for each individually. +After the targeted tests, run one bulk compile (no workflow-name specified) to verify overall compilation health. ``` diff --git a/pkg/cli/mcp_tools_output_streams_test.go b/pkg/cli/mcp_tools_output_streams_test.go index 0d5bb9ad844..54253b47518 100644 --- a/pkg/cli/mcp_tools_output_streams_test.go +++ b/pkg/cli/mcp_tools_output_streams_test.go @@ -5,6 +5,8 @@ package cli import ( "context" "os/exec" + "slices" + "strings" "testing" "github.com/modelcontextprotocol/go-sdk/mcp" @@ -49,3 +51,30 @@ func TestCompileTool_UsesOnlyStdoutOnSuccess(t *testing.T) { assert.JSONEq(t, expectedStdout, output, "compile tool should return subprocess stdout only") assert.NotContains(t, output, stderrNoise, "compile tool output should not contain stderr noise") } + +func TestCompileTool_AcceptsDeprecatedMaxTokensParameter(t *testing.T) { + const expectedStdout = `[{"workflow":"test.md","valid":true,"errors":[],"warnings":[]}]` + + var capturedArgs []string + mockExecCmd := func(ctx context.Context, args ...string) *exec.Cmd { + capturedArgs = slices.Clone(args) + return exec.CommandContext(ctx, "sh", "-c", `printf '%s' "$1"`, "sh", expectedStdout) + } + + server := mcp.NewServer(&mcp.Implementation{Name: "test", Version: "1.0"}, nil) + err := registerCompileTool(server, mockExecCmd, "") + require.NoError(t, err, "registerCompileTool should succeed") + + session := connectInMemory(t, server) + result, err := session.CallTool(context.Background(), &mcp.CallToolParams{ + Name: "compile", + Arguments: map[string]any{ + "max_tokens": 5000, + }, + }) + require.NoError(t, err, "compile tool should accept deprecated max_tokens parameter") + + output := extractTextResult(t, result) + assert.JSONEq(t, expectedStdout, output, "compile tool should still return subprocess stdout") + assert.NotContains(t, strings.Join(capturedArgs, " "), "max_tokens", "compile command args should ignore max_tokens") +} diff --git a/pkg/cli/mcp_tools_privileged.go b/pkg/cli/mcp_tools_privileged.go index 2efe8abda81..d8efe2557c2 100644 --- a/pkg/cli/mcp_tools_privileged.go +++ b/pkg/cli/mcp_tools_privileged.go @@ -250,6 +250,7 @@ func registerAuditTool(server *mcp.Server, execCmd execCmdFunc, actor string, va type auditArgs struct { RunIDOrURL string `json:"run_id_or_url" jsonschema:"GitHub Actions workflow run ID or URL. Accepts: numeric run ID (e.g., 1234567890), run URL (https://github.com/owner/repo/actions/runs/1234567890), job URL (https://github.com/owner/repo/actions/runs/1234567890/job/9876543210), or job URL with step (https://github.com/owner/repo/actions/runs/1234567890/job/9876543210#step:7:1)"` Artifacts []string `json:"artifacts,omitempty" jsonschema:"Artifact sets to download (default: all). Valid sets: all, activation, agent, detection, firewall, github-api, mcp"` + MaxTokens int `json:"max_tokens,omitempty" jsonschema:"Deprecated: accepted for backward compatibility but ignored."` } // Generate schema for audit tool diff --git a/pkg/cli/mcp_tools_privileged_test.go b/pkg/cli/mcp_tools_privileged_test.go index a4d0a801845..ba608f144da 100644 --- a/pkg/cli/mcp_tools_privileged_test.go +++ b/pkg/cli/mcp_tools_privileged_test.go @@ -8,6 +8,8 @@ import ( "fmt" "os" "os/exec" + "slices" + "strings" "testing" "github.com/modelcontextprotocol/go-sdk/mcp" @@ -299,6 +301,36 @@ func TestAuditToolErrorEnvelopeSetsIsErrorTrueHelperProcess(t *testing.T) { os.Exit(1) } +func TestAuditTool_AcceptsDeprecatedMaxTokensParameter(t *testing.T) { + const expectedStdout = `{"overview":{"run_id":"1234567890"}}` + + var capturedArgs []string + mockExecCmd := func(ctx context.Context, args ...string) *exec.Cmd { + capturedArgs = slices.Clone(args) + return exec.CommandContext(ctx, "sh", "-c", `printf '%s' "$1"`, "sh", expectedStdout) + } + + server := mcp.NewServer(&mcp.Implementation{Name: "test", Version: "1.0"}, nil) + err := registerAuditTool(server, mockExecCmd, "", false) + require.NoError(t, err, "registerAuditTool should succeed") + + session := connectInMemory(t, server) + result, err := session.CallTool(context.Background(), &mcp.CallToolParams{ + Name: "audit", + Arguments: map[string]any{ + "run_id_or_url": "1234567890", + "max_tokens": 5000, + }, + }) + require.NoError(t, err, "audit tool should accept deprecated max_tokens parameter") + require.NotNil(t, result, "result should not be nil") + + textContent, ok := result.Content[0].(*mcp.TextContent) + require.True(t, ok, "expected text content in audit response") + assert.JSONEq(t, expectedStdout, textContent.Text, "audit tool should return subprocess stdout") + assert.NotContains(t, strings.Join(capturedArgs, " "), "max_tokens", "audit command args should ignore max_tokens") +} + func TestAuditDiffToolErrorEnvelopeSetsIsErrorTrue(t *testing.T) { mockExecCmd := func(ctx context.Context, args ...string) *exec.Cmd { cmd := exec.CommandContext(ctx, os.Args[0], "-test.run=TestAuditDiffToolErrorEnvelopeSetsIsErrorTrueHelperProcess") diff --git a/pkg/cli/mcp_tools_readonly.go b/pkg/cli/mcp_tools_readonly.go index 7af2c902aef..9015ba6a372 100644 --- a/pkg/cli/mcp_tools_readonly.go +++ b/pkg/cli/mcp_tools_readonly.go @@ -83,6 +83,7 @@ func registerCompileTool(server *mcp.Server, execCmd execCmdFunc, manifestCacheF Actionlint bool `json:"actionlint,omitempty" jsonschema:"Run actionlint linter on generated .lock.yml files"` RunnerGuard bool `json:"runner-guard,omitempty" jsonschema:"Run runner-guard taint analysis scanner on generated .lock.yml files"` Fix bool `json:"fix,omitempty" jsonschema:"Apply automatic codemod fixes to workflows before compiling"` + MaxTokens int `json:"max_tokens,omitempty" jsonschema:"Deprecated: accepted for backward compatibility but ignored."` } // Generate schema with elicitation defaults