From 343fd679308e351dd26e26341bf170568e660197 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Fri, 5 Sep 2025 07:27:44 -0700 Subject: [PATCH 1/4] Add documentation for custom agentic engine with manual safe output writing (#66) * Initial plan * Add documentation for custom agentic engine marked as experimental Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> * Document how custom engines can write safe output entries manually via JSONL Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> Co-authored-by: Peli de Halleux --- pkg/cli/templates/instructions.md | 61 +++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 3 deletions(-) diff --git a/pkg/cli/templates/instructions.md b/pkg/cli/templates/instructions.md index b554ade0fc9..e6f853552b3 100644 --- a/pkg/cli/templates/instructions.md +++ b/pkg/cli/templates/instructions.md @@ -61,15 +61,70 @@ The YAML frontmatter supports these fields: ### Agentic Workflow Specific Fields - **`engine:`** - AI processor configuration - - String format: `"claude"` (default), `"codex"` + - String format: `"claude"` (default), `"codex"`, `"custom"` (⚠️ experimental) - Object format for extended configuration: ```yaml engine: - id: claude # Required: coding agent identifier (claude, codex) + id: claude # Required: coding agent identifier (claude, codex, custom) version: beta # Optional: version of the action model: claude-3-5-sonnet-20241022 # Optional: LLM model to use max-turns: 5 # Optional: maximum chat iterations per run ``` + - **Custom engine format** (⚠️ experimental): + ```yaml + engine: + id: custom # Required: custom engine identifier + max-turns: 10 # Optional: maximum iterations (for consistency) + steps: # Required: array of custom GitHub Actions steps + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "18" + - name: Run tests + run: npm test + ``` + The `custom` engine allows you to define your own GitHub Actions steps instead of using an AI processor. Each step in the `steps` array follows standard GitHub Actions step syntax with `name`, `uses`/`run`, `with`, `env`, etc. This is useful for deterministic workflows that don't require AI processing. + + **Writing Safe Output Entries Manually (Custom Engines):** + + Custom engines can write safe output entries by appending JSON objects to the `$GITHUB_AW_SAFE_OUTPUTS` environment variable (a JSONL file). Each line should contain a complete JSON object with a `type` field and the relevant data for that output type. + + ```bash + # Create an issue + echo '{"type": "create-issue", "title": "Issue Title", "body": "Issue description", "labels": ["label1", "label2"]}' >> $GITHUB_AW_SAFE_OUTPUTS + + # Add a comment to an issue/PR + echo '{"type": "add-issue-comment", "body": "Comment text"}' >> $GITHUB_AW_SAFE_OUTPUTS + + # Add labels to an issue/PR + echo '{"type": "add-issue-label", "labels": ["bug", "enhancement"]}' >> $GITHUB_AW_SAFE_OUTPUTS + + # Update an issue + echo '{"type": "update-issue", "title": "New title", "body": "New body", "status": "closed"}' >> $GITHUB_AW_SAFE_OUTPUTS + + # Create a pull request (after making file changes) + echo '{"type": "create-pull-request", "title": "PR Title", "body": "PR description", "labels": ["automation"], "draft": true}' >> $GITHUB_AW_SAFE_OUTPUTS + + # Create a PR review comment + echo '{"type": "create-pull-request-review-comment", "path": "file.js", "line": 10, "body": "Review comment"}' >> $GITHUB_AW_SAFE_OUTPUTS + + # Push to branch (after making file changes) + echo '{"type": "push-to-branch", "message": "Commit message"}' >> $GITHUB_AW_SAFE_OUTPUTS + + # Create a discussion + echo '{"type": "create-discussion", "title": "Discussion Title", "body": "Discussion content"}' >> $GITHUB_AW_SAFE_OUTPUTS + + # Report missing tools + echo '{"type": "missing-tool", "tool": "tool-name", "reason": "Why it is needed", "alternatives": "Possible alternatives"}' >> $GITHUB_AW_SAFE_OUTPUTS + ``` + + **Important Notes for Manual Safe Output Writing:** + - Each JSON object must be on a single line (JSONL format) + - All string values should be properly escaped JSON strings + - The `type` field is required and must match the configured safe output types + - File changes for `create-pull-request` and `push-to-branch` are collected automatically via `git add -A` + - Output entries are processed only if the corresponding safe output type is configured in the workflow frontmatter + - Invalid JSON entries are ignored with warnings in the workflow logs - **`network:`** - Network access control for Claude Code engine (top-level field) - String format: `"defaults"` (curated allow-list of development domains) @@ -799,7 +854,7 @@ The workflow frontmatter is validated against JSON Schema during compilation. Co - **Invalid field names** - Only fields in the schema are allowed - **Wrong field types** - e.g., `timeout_minutes` must be integer -- **Invalid enum values** - e.g., `engine` must be "claude" or "codex" +- **Invalid enum values** - e.g., `engine` must be "claude", "codex", or "custom" - **Missing required fields** - Some triggers require specific configuration Use `gh aw compile --verbose` to see detailed validation messages, or `gh aw compile --verbose` to validate a specific workflow. \ No newline at end of file From d1d2f7a4a68e03bd6bf9847ab6bcf4ccde08abaf Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Fri, 5 Sep 2025 07:57:15 -0700 Subject: [PATCH 2/4] Add processed output display to step summary in workflow compilation (#71) * Initial plan * Update step summary to include processed output from collect_output Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .../test-claude-add-issue-comment.lock.yml | 6 ++ .../test-claude-add-issue-labels.lock.yml | 6 ++ .../workflows/test-claude-command.lock.yml | 6 ++ .../test-claude-create-issue.lock.yml | 6 ++ ...reate-pull-request-review-comment.lock.yml | 6 ++ .../test-claude-create-pull-request.lock.yml | 6 ++ ...est-claude-create-security-report.lock.yml | 6 ++ .github/workflows/test-claude-mcp.lock.yml | 6 ++ .../test-claude-push-to-branch.lock.yml | 6 ++ .../test-claude-update-issue.lock.yml | 6 ++ .../test-codex-add-issue-comment.lock.yml | 6 ++ .../test-codex-add-issue-labels.lock.yml | 6 ++ .github/workflows/test-codex-command.lock.yml | 6 ++ .../test-codex-create-issue.lock.yml | 6 ++ ...reate-pull-request-review-comment.lock.yml | 6 ++ .../test-codex-create-pull-request.lock.yml | 6 ++ ...test-codex-create-security-report.lock.yml | 6 ++ .github/workflows/test-codex-mcp.lock.yml | 6 ++ .../test-codex-push-to-branch.lock.yml | 6 ++ .../test-codex-update-issue.lock.yml | 6 ++ .github/workflows/test-proxy.lock.yml | 6 ++ .../test-safe-outputs-custom-engine.lock.yml | 6 ++ pkg/workflow/compiler.go | 6 ++ pkg/workflow/step_summary_test.go | 91 +++++++++++++++++++ 24 files changed, 229 insertions(+) create mode 100644 pkg/workflow/step_summary_test.go diff --git a/.github/workflows/test-claude-add-issue-comment.lock.yml b/.github/workflows/test-claude-add-issue-comment.lock.yml index 8f1b701d3ef..d2e38909a11 100644 --- a/.github/workflows/test-claude-add-issue-comment.lock.yml +++ b/.github/workflows/test-claude-add-issue-comment.lock.yml @@ -1244,6 +1244,12 @@ jobs: echo "" >> $GITHUB_STEP_SUMMARY fi echo '``````' >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "## Processed Output" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo '``````json' >> $GITHUB_STEP_SUMMARY + echo '${{ steps.collect_output.outputs.output }}' >> $GITHUB_STEP_SUMMARY + echo '``````' >> $GITHUB_STEP_SUMMARY - name: Upload agentic output file if: always() && steps.collect_output.outputs.output != '' uses: actions/upload-artifact@v4 diff --git a/.github/workflows/test-claude-add-issue-labels.lock.yml b/.github/workflows/test-claude-add-issue-labels.lock.yml index 041b92372d2..606fabdbd44 100644 --- a/.github/workflows/test-claude-add-issue-labels.lock.yml +++ b/.github/workflows/test-claude-add-issue-labels.lock.yml @@ -1244,6 +1244,12 @@ jobs: echo "" >> $GITHUB_STEP_SUMMARY fi echo '``````' >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "## Processed Output" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo '``````json' >> $GITHUB_STEP_SUMMARY + echo '${{ steps.collect_output.outputs.output }}' >> $GITHUB_STEP_SUMMARY + echo '``````' >> $GITHUB_STEP_SUMMARY - name: Upload agentic output file if: always() && steps.collect_output.outputs.output != '' uses: actions/upload-artifact@v4 diff --git a/.github/workflows/test-claude-command.lock.yml b/.github/workflows/test-claude-command.lock.yml index 4bed937f937..af713d26e64 100644 --- a/.github/workflows/test-claude-command.lock.yml +++ b/.github/workflows/test-claude-command.lock.yml @@ -1520,6 +1520,12 @@ jobs: echo "" >> $GITHUB_STEP_SUMMARY fi echo '``````' >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "## Processed Output" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo '``````json' >> $GITHUB_STEP_SUMMARY + echo '${{ steps.collect_output.outputs.output }}' >> $GITHUB_STEP_SUMMARY + echo '``````' >> $GITHUB_STEP_SUMMARY - name: Upload agentic output file if: always() && steps.collect_output.outputs.output != '' uses: actions/upload-artifact@v4 diff --git a/.github/workflows/test-claude-create-issue.lock.yml b/.github/workflows/test-claude-create-issue.lock.yml index 5f9f47a4940..1dbc3776bf0 100644 --- a/.github/workflows/test-claude-create-issue.lock.yml +++ b/.github/workflows/test-claude-create-issue.lock.yml @@ -1054,6 +1054,12 @@ jobs: echo "" >> $GITHUB_STEP_SUMMARY fi echo '``````' >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "## Processed Output" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo '``````json' >> $GITHUB_STEP_SUMMARY + echo '${{ steps.collect_output.outputs.output }}' >> $GITHUB_STEP_SUMMARY + echo '``````' >> $GITHUB_STEP_SUMMARY - name: Upload agentic output file if: always() && steps.collect_output.outputs.output != '' uses: actions/upload-artifact@v4 diff --git a/.github/workflows/test-claude-create-pull-request-review-comment.lock.yml b/.github/workflows/test-claude-create-pull-request-review-comment.lock.yml index 060df6d2840..e98a1582c05 100644 --- a/.github/workflows/test-claude-create-pull-request-review-comment.lock.yml +++ b/.github/workflows/test-claude-create-pull-request-review-comment.lock.yml @@ -1258,6 +1258,12 @@ jobs: echo "" >> $GITHUB_STEP_SUMMARY fi echo '``````' >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "## Processed Output" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo '``````json' >> $GITHUB_STEP_SUMMARY + echo '${{ steps.collect_output.outputs.output }}' >> $GITHUB_STEP_SUMMARY + echo '``````' >> $GITHUB_STEP_SUMMARY - name: Upload agentic output file if: always() && steps.collect_output.outputs.output != '' uses: actions/upload-artifact@v4 diff --git a/.github/workflows/test-claude-create-pull-request.lock.yml b/.github/workflows/test-claude-create-pull-request.lock.yml index a34c7cb5f98..aabab1cbc7f 100644 --- a/.github/workflows/test-claude-create-pull-request.lock.yml +++ b/.github/workflows/test-claude-create-pull-request.lock.yml @@ -1073,6 +1073,12 @@ jobs: echo "" >> $GITHUB_STEP_SUMMARY fi echo '``````' >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "## Processed Output" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo '``````json' >> $GITHUB_STEP_SUMMARY + echo '${{ steps.collect_output.outputs.output }}' >> $GITHUB_STEP_SUMMARY + echo '``````' >> $GITHUB_STEP_SUMMARY - name: Upload agentic output file if: always() && steps.collect_output.outputs.output != '' uses: actions/upload-artifact@v4 diff --git a/.github/workflows/test-claude-create-security-report.lock.yml b/.github/workflows/test-claude-create-security-report.lock.yml index 170789c2c0d..6991a88575f 100644 --- a/.github/workflows/test-claude-create-security-report.lock.yml +++ b/.github/workflows/test-claude-create-security-report.lock.yml @@ -1250,6 +1250,12 @@ jobs: echo "" >> $GITHUB_STEP_SUMMARY fi echo '``````' >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "## Processed Output" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo '``````json' >> $GITHUB_STEP_SUMMARY + echo '${{ steps.collect_output.outputs.output }}' >> $GITHUB_STEP_SUMMARY + echo '``````' >> $GITHUB_STEP_SUMMARY - name: Upload agentic output file if: always() && steps.collect_output.outputs.output != '' uses: actions/upload-artifact@v4 diff --git a/.github/workflows/test-claude-mcp.lock.yml b/.github/workflows/test-claude-mcp.lock.yml index 149f514596f..df66ee69929 100644 --- a/.github/workflows/test-claude-mcp.lock.yml +++ b/.github/workflows/test-claude-mcp.lock.yml @@ -1266,6 +1266,12 @@ jobs: echo "" >> $GITHUB_STEP_SUMMARY fi echo '``````' >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "## Processed Output" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo '``````json' >> $GITHUB_STEP_SUMMARY + echo '${{ steps.collect_output.outputs.output }}' >> $GITHUB_STEP_SUMMARY + echo '``````' >> $GITHUB_STEP_SUMMARY - name: Upload agentic output file if: always() && steps.collect_output.outputs.output != '' uses: actions/upload-artifact@v4 diff --git a/.github/workflows/test-claude-push-to-branch.lock.yml b/.github/workflows/test-claude-push-to-branch.lock.yml index 94553f1019c..064f3907326 100644 --- a/.github/workflows/test-claude-push-to-branch.lock.yml +++ b/.github/workflows/test-claude-push-to-branch.lock.yml @@ -1160,6 +1160,12 @@ jobs: echo "" >> $GITHUB_STEP_SUMMARY fi echo '``````' >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "## Processed Output" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo '``````json' >> $GITHUB_STEP_SUMMARY + echo '${{ steps.collect_output.outputs.output }}' >> $GITHUB_STEP_SUMMARY + echo '``````' >> $GITHUB_STEP_SUMMARY - name: Upload agentic output file if: always() && steps.collect_output.outputs.output != '' uses: actions/upload-artifact@v4 diff --git a/.github/workflows/test-claude-update-issue.lock.yml b/.github/workflows/test-claude-update-issue.lock.yml index 945a9f6bcd4..42b367c058c 100644 --- a/.github/workflows/test-claude-update-issue.lock.yml +++ b/.github/workflows/test-claude-update-issue.lock.yml @@ -1247,6 +1247,12 @@ jobs: echo "" >> $GITHUB_STEP_SUMMARY fi echo '``````' >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "## Processed Output" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo '``````json' >> $GITHUB_STEP_SUMMARY + echo '${{ steps.collect_output.outputs.output }}' >> $GITHUB_STEP_SUMMARY + echo '``````' >> $GITHUB_STEP_SUMMARY - name: Upload agentic output file if: always() && steps.collect_output.outputs.output != '' uses: actions/upload-artifact@v4 diff --git a/.github/workflows/test-codex-add-issue-comment.lock.yml b/.github/workflows/test-codex-add-issue-comment.lock.yml index 04efff422b1..556a6eaf772 100644 --- a/.github/workflows/test-codex-add-issue-comment.lock.yml +++ b/.github/workflows/test-codex-add-issue-comment.lock.yml @@ -1076,6 +1076,12 @@ jobs: echo "" >> $GITHUB_STEP_SUMMARY fi echo '``````' >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "## Processed Output" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo '``````json' >> $GITHUB_STEP_SUMMARY + echo '${{ steps.collect_output.outputs.output }}' >> $GITHUB_STEP_SUMMARY + echo '``````' >> $GITHUB_STEP_SUMMARY - name: Upload agentic output file if: always() && steps.collect_output.outputs.output != '' uses: actions/upload-artifact@v4 diff --git a/.github/workflows/test-codex-add-issue-labels.lock.yml b/.github/workflows/test-codex-add-issue-labels.lock.yml index 3d92299147b..b0d69b10c9e 100644 --- a/.github/workflows/test-codex-add-issue-labels.lock.yml +++ b/.github/workflows/test-codex-add-issue-labels.lock.yml @@ -1076,6 +1076,12 @@ jobs: echo "" >> $GITHUB_STEP_SUMMARY fi echo '``````' >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "## Processed Output" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo '``````json' >> $GITHUB_STEP_SUMMARY + echo '${{ steps.collect_output.outputs.output }}' >> $GITHUB_STEP_SUMMARY + echo '``````' >> $GITHUB_STEP_SUMMARY - name: Upload agentic output file if: always() && steps.collect_output.outputs.output != '' uses: actions/upload-artifact@v4 diff --git a/.github/workflows/test-codex-command.lock.yml b/.github/workflows/test-codex-command.lock.yml index e41823b0791..cd5cafc8cd4 100644 --- a/.github/workflows/test-codex-command.lock.yml +++ b/.github/workflows/test-codex-command.lock.yml @@ -1520,6 +1520,12 @@ jobs: echo "" >> $GITHUB_STEP_SUMMARY fi echo '``````' >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "## Processed Output" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo '``````json' >> $GITHUB_STEP_SUMMARY + echo '${{ steps.collect_output.outputs.output }}' >> $GITHUB_STEP_SUMMARY + echo '``````' >> $GITHUB_STEP_SUMMARY - name: Upload agentic output file if: always() && steps.collect_output.outputs.output != '' uses: actions/upload-artifact@v4 diff --git a/.github/workflows/test-codex-create-issue.lock.yml b/.github/workflows/test-codex-create-issue.lock.yml index adce36de850..7d3ca4e99b1 100644 --- a/.github/workflows/test-codex-create-issue.lock.yml +++ b/.github/workflows/test-codex-create-issue.lock.yml @@ -886,6 +886,12 @@ jobs: echo "" >> $GITHUB_STEP_SUMMARY fi echo '``````' >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "## Processed Output" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo '``````json' >> $GITHUB_STEP_SUMMARY + echo '${{ steps.collect_output.outputs.output }}' >> $GITHUB_STEP_SUMMARY + echo '``````' >> $GITHUB_STEP_SUMMARY - name: Upload agentic output file if: always() && steps.collect_output.outputs.output != '' uses: actions/upload-artifact@v4 diff --git a/.github/workflows/test-codex-create-pull-request-review-comment.lock.yml b/.github/workflows/test-codex-create-pull-request-review-comment.lock.yml index d488cf67e1e..89783447e99 100644 --- a/.github/workflows/test-codex-create-pull-request-review-comment.lock.yml +++ b/.github/workflows/test-codex-create-pull-request-review-comment.lock.yml @@ -1090,6 +1090,12 @@ jobs: echo "" >> $GITHUB_STEP_SUMMARY fi echo '``````' >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "## Processed Output" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo '``````json' >> $GITHUB_STEP_SUMMARY + echo '${{ steps.collect_output.outputs.output }}' >> $GITHUB_STEP_SUMMARY + echo '``````' >> $GITHUB_STEP_SUMMARY - name: Upload agentic output file if: always() && steps.collect_output.outputs.output != '' uses: actions/upload-artifact@v4 diff --git a/.github/workflows/test-codex-create-pull-request.lock.yml b/.github/workflows/test-codex-create-pull-request.lock.yml index 0588a6efeaa..18d1edcfae6 100644 --- a/.github/workflows/test-codex-create-pull-request.lock.yml +++ b/.github/workflows/test-codex-create-pull-request.lock.yml @@ -893,6 +893,12 @@ jobs: echo "" >> $GITHUB_STEP_SUMMARY fi echo '``````' >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "## Processed Output" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo '``````json' >> $GITHUB_STEP_SUMMARY + echo '${{ steps.collect_output.outputs.output }}' >> $GITHUB_STEP_SUMMARY + echo '``````' >> $GITHUB_STEP_SUMMARY - name: Upload agentic output file if: always() && steps.collect_output.outputs.output != '' uses: actions/upload-artifact@v4 diff --git a/.github/workflows/test-codex-create-security-report.lock.yml b/.github/workflows/test-codex-create-security-report.lock.yml index 0e8629837a7..de605ee8e12 100644 --- a/.github/workflows/test-codex-create-security-report.lock.yml +++ b/.github/workflows/test-codex-create-security-report.lock.yml @@ -1082,6 +1082,12 @@ jobs: echo "" >> $GITHUB_STEP_SUMMARY fi echo '``````' >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "## Processed Output" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo '``````json' >> $GITHUB_STEP_SUMMARY + echo '${{ steps.collect_output.outputs.output }}' >> $GITHUB_STEP_SUMMARY + echo '``````' >> $GITHUB_STEP_SUMMARY - name: Upload agentic output file if: always() && steps.collect_output.outputs.output != '' uses: actions/upload-artifact@v4 diff --git a/.github/workflows/test-codex-mcp.lock.yml b/.github/workflows/test-codex-mcp.lock.yml index 4c8e645eb1c..405ab281222 100644 --- a/.github/workflows/test-codex-mcp.lock.yml +++ b/.github/workflows/test-codex-mcp.lock.yml @@ -1095,6 +1095,12 @@ jobs: echo "" >> $GITHUB_STEP_SUMMARY fi echo '``````' >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "## Processed Output" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo '``````json' >> $GITHUB_STEP_SUMMARY + echo '${{ steps.collect_output.outputs.output }}' >> $GITHUB_STEP_SUMMARY + echo '``````' >> $GITHUB_STEP_SUMMARY - name: Upload agentic output file if: always() && steps.collect_output.outputs.output != '' uses: actions/upload-artifact@v4 diff --git a/.github/workflows/test-codex-push-to-branch.lock.yml b/.github/workflows/test-codex-push-to-branch.lock.yml index 44f1d17316c..f43838f2126 100644 --- a/.github/workflows/test-codex-push-to-branch.lock.yml +++ b/.github/workflows/test-codex-push-to-branch.lock.yml @@ -982,6 +982,12 @@ jobs: echo "" >> $GITHUB_STEP_SUMMARY fi echo '``````' >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "## Processed Output" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo '``````json' >> $GITHUB_STEP_SUMMARY + echo '${{ steps.collect_output.outputs.output }}' >> $GITHUB_STEP_SUMMARY + echo '``````' >> $GITHUB_STEP_SUMMARY - name: Upload agentic output file if: always() && steps.collect_output.outputs.output != '' uses: actions/upload-artifact@v4 diff --git a/.github/workflows/test-codex-update-issue.lock.yml b/.github/workflows/test-codex-update-issue.lock.yml index 671b66e9f32..394b43b3859 100644 --- a/.github/workflows/test-codex-update-issue.lock.yml +++ b/.github/workflows/test-codex-update-issue.lock.yml @@ -1079,6 +1079,12 @@ jobs: echo "" >> $GITHUB_STEP_SUMMARY fi echo '``````' >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "## Processed Output" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo '``````json' >> $GITHUB_STEP_SUMMARY + echo '${{ steps.collect_output.outputs.output }}' >> $GITHUB_STEP_SUMMARY + echo '``````' >> $GITHUB_STEP_SUMMARY - name: Upload agentic output file if: always() && steps.collect_output.outputs.output != '' uses: actions/upload-artifact@v4 diff --git a/.github/workflows/test-proxy.lock.yml b/.github/workflows/test-proxy.lock.yml index 917b2178762..b3b30549097 100644 --- a/.github/workflows/test-proxy.lock.yml +++ b/.github/workflows/test-proxy.lock.yml @@ -1232,6 +1232,12 @@ jobs: echo "" >> $GITHUB_STEP_SUMMARY fi echo '``````' >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "## Processed Output" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo '``````json' >> $GITHUB_STEP_SUMMARY + echo '${{ steps.collect_output.outputs.output }}' >> $GITHUB_STEP_SUMMARY + echo '``````' >> $GITHUB_STEP_SUMMARY - name: Upload agentic output file if: always() && steps.collect_output.outputs.output != '' uses: actions/upload-artifact@v4 diff --git a/.github/workflows/test-safe-outputs-custom-engine.lock.yml b/.github/workflows/test-safe-outputs-custom-engine.lock.yml index 0c909b0c408..a75d6c77edb 100644 --- a/.github/workflows/test-safe-outputs-custom-engine.lock.yml +++ b/.github/workflows/test-safe-outputs-custom-engine.lock.yml @@ -1066,6 +1066,12 @@ jobs: echo "" >> $GITHUB_STEP_SUMMARY fi echo '``````' >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "## Processed Output" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo '``````json' >> $GITHUB_STEP_SUMMARY + echo '${{ steps.collect_output.outputs.output }}' >> $GITHUB_STEP_SUMMARY + echo '``````' >> $GITHUB_STEP_SUMMARY - name: Upload agentic output file if: always() && steps.collect_output.outputs.output != '' uses: actions/upload-artifact@v4 diff --git a/pkg/workflow/compiler.go b/pkg/workflow/compiler.go index 8b049992492..bc39c9eaf1e 100644 --- a/pkg/workflow/compiler.go +++ b/pkg/workflow/compiler.go @@ -3800,6 +3800,12 @@ func (c *Compiler) generateOutputCollectionStep(yaml *strings.Builder, data *Wor yaml.WriteString(" echo \"\" >> $GITHUB_STEP_SUMMARY\n") yaml.WriteString(" fi\n") yaml.WriteString(" echo '``````' >> $GITHUB_STEP_SUMMARY\n") + yaml.WriteString(" echo \"\" >> $GITHUB_STEP_SUMMARY\n") + yaml.WriteString(" echo \"## Processed Output\" >> $GITHUB_STEP_SUMMARY\n") + yaml.WriteString(" echo \"\" >> $GITHUB_STEP_SUMMARY\n") + yaml.WriteString(" echo '``````json' >> $GITHUB_STEP_SUMMARY\n") + yaml.WriteString(" echo '${{ steps.collect_output.outputs.output }}' >> $GITHUB_STEP_SUMMARY\n") + yaml.WriteString(" echo '``````' >> $GITHUB_STEP_SUMMARY\n") yaml.WriteString(" - name: Upload agentic output file\n") yaml.WriteString(" if: always() && steps.collect_output.outputs.output != ''\n") yaml.WriteString(" uses: actions/upload-artifact@v4\n") diff --git a/pkg/workflow/step_summary_test.go b/pkg/workflow/step_summary_test.go new file mode 100644 index 00000000000..f566f18e5eb --- /dev/null +++ b/pkg/workflow/step_summary_test.go @@ -0,0 +1,91 @@ +package workflow + +import ( + "os" + "path/filepath" + "strings" + "testing" +) + +func TestStepSummaryIncludesProcessedOutput(t *testing.T) { + // Create temporary directory for test files + tmpDir, err := os.MkdirTemp("", "step-summary-test") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpDir) + + // Test case with Claude engine + testContent := `--- +on: push +permissions: + contents: read + issues: write +tools: + github: + allowed: [list_issues] +engine: claude +safe-outputs: + create-issue: +--- + +# Test Step Summary with Processed Output + +This workflow tests that the step summary includes both JSONL and processed output. +` + + testFile := filepath.Join(tmpDir, "test-step-summary.md") + if err := os.WriteFile(testFile, []byte(testContent), 0644); err != nil { + t.Fatal(err) + } + + compiler := NewCompiler(false, "", "test") + + // Compile the workflow + err = compiler.CompileWorkflow(testFile) + if err != nil { + t.Fatalf("Unexpected error compiling workflow: %v", err) + } + + // Read the generated lock file + lockFile := filepath.Join(tmpDir, "test-step-summary.lock.yml") + content, err := os.ReadFile(lockFile) + if err != nil { + t.Fatalf("Failed to read generated lock file: %v", err) + } + + lockContent := string(content) + + // Verify that the "Print agent output to step summary" step exists + if !strings.Contains(lockContent, "- name: Print agent output to step summary") { + t.Error("Expected 'Print agent output to step summary' step") + } + + // Verify that the step includes the original JSONL output section + if !strings.Contains(lockContent, "## Agent Output (JSONL)") { + t.Error("Expected '## Agent Output (JSONL)' section in step summary") + } + + // Verify that the step includes the new processed output section + if !strings.Contains(lockContent, "## Processed Output") { + t.Error("Expected '## Processed Output' section in step summary") + } + + // Verify that the processed output references the collect_output step output + if !strings.Contains(lockContent, "${{ steps.collect_output.outputs.output }}") { + t.Error("Expected reference to steps.collect_output.outputs.output in step summary") + } + + // Verify both outputs are in code blocks + jsonlBlockCount := strings.Count(lockContent, "echo '``````json'") + if jsonlBlockCount < 2 { + t.Errorf("Expected at least 2 JSON code blocks in step summary, got %d", jsonlBlockCount) + } + + codeBlockEndCount := strings.Count(lockContent, "echo '``````'") + if codeBlockEndCount < 2 { + t.Errorf("Expected at least 2 code block end markers in step summary, got %d", codeBlockEndCount) + } + + t.Log("Step summary correctly includes both JSONL and processed output sections") +} From f82ceb41fb1f4f60f60d24266f351c9447b5620a Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Fri, 5 Sep 2025 09:25:29 -0700 Subject: [PATCH 3/4] Store prompt filename in GITHUB_AW_PROMPT environment variable, support id/continue-on-error fields, and use environment variable for prompt file operations (#70) * Initial plan * Implement GITHUB_AW_PROMPT environment variable and id/continue-on-error support Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> * Improve prompt file generation with more robust heredoc delimiter Replace 'EOF' with 'GITHUB_AW_PROMPT_END' as the heredoc delimiter for writing prompt content to /tmp/aw-prompts/prompt.txt. This change prevents potential conflicts if user workflow content contains "EOF" on its own line, which could prematurely terminate the heredoc and break prompt file generation. The new delimiter is more unique and descriptive, making it extremely unlikely to collide with user markdown content while clearly indicating its purpose in the workflow context. Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> * Use environment variable $GITHUB_AW_PROMPT with EOF delimiter instead of hardcoded path and GITHUB_AW_PROMPT_END Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> Co-authored-by: Peli de Halleux --- ...xample-engine-network-permissions.lock.yml | 8 +- .../test-claude-add-issue-comment.lock.yml | 6 +- .../test-claude-add-issue-labels.lock.yml | 6 +- .../workflows/test-claude-command.lock.yml | 6 +- .../test-claude-create-issue.lock.yml | 6 +- ...reate-pull-request-review-comment.lock.yml | 6 +- .../test-claude-create-pull-request.lock.yml | 6 +- ...est-claude-create-security-report.lock.yml | 6 +- .github/workflows/test-claude-mcp.lock.yml | 6 +- .../test-claude-push-to-branch.lock.yml | 6 +- .../test-claude-update-issue.lock.yml | 6 +- .../test-codex-add-issue-comment.lock.yml | 6 +- .../test-codex-add-issue-labels.lock.yml | 6 +- .github/workflows/test-codex-command.lock.yml | 6 +- .../test-codex-create-issue.lock.yml | 6 +- ...reate-pull-request-review-comment.lock.yml | 6 +- .../test-codex-create-pull-request.lock.yml | 6 +- ...test-codex-create-security-report.lock.yml | 6 +- .github/workflows/test-codex-mcp.lock.yml | 6 +- .../test-codex-push-to-branch.lock.yml | 6 +- .../test-codex-update-issue.lock.yml | 6 +- .github/workflows/test-proxy.lock.yml | 6 +- .../test-safe-outputs-custom-engine.lock.yml | 15 +++- package-lock.json | 2 +- pkg/workflow/claude_engine.go | 29 ++++--- pkg/workflow/codex_engine.go | 33 ++++++-- pkg/workflow/codex_engine_test.go | 75 +++++++++++++++++++ pkg/workflow/codex_test.go | 4 +- pkg/workflow/compiler.go | 9 ++- pkg/workflow/custom_engine.go | 45 +++++++---- pkg/workflow/custom_engine_test.go | 71 +++++++++++++++++- pkg/workflow/output_missing_tool_test.go | 23 ++++++ 32 files changed, 351 insertions(+), 89 deletions(-) diff --git a/.github/workflows/example-engine-network-permissions.lock.yml b/.github/workflows/example-engine-network-permissions.lock.yml index 26ce5bf562f..a99ab39e9ee 100644 --- a/.github/workflows/example-engine-network-permissions.lock.yml +++ b/.github/workflows/example-engine-network-permissions.lock.yml @@ -165,9 +165,11 @@ jobs: } EOF - name: Create prompt + env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt run: | mkdir -p /tmp/aw-prompts - cat > /tmp/aw-prompts/prompt.txt << 'EOF' + cat > $GITHUB_AW_PROMPT << 'EOF' # Secure Web Research Task Please research the GitHub API documentation or Stack Overflow and find information about repository topics. Summarize them in a brief report. @@ -178,7 +180,7 @@ jobs: echo "## Generated Prompt" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo '``````markdown' >> $GITHUB_STEP_SUMMARY - cat /tmp/aw-prompts/prompt.txt >> $GITHUB_STEP_SUMMARY + cat $GITHUB_AW_PROMPT >> $GITHUB_STEP_SUMMARY echo '``````' >> $GITHUB_STEP_SUMMARY - name: Generate agentic run info uses: actions/github-script@v7 @@ -283,6 +285,8 @@ jobs: prompt_file: /tmp/aw-prompts/prompt.txt settings: .claude/settings.json timeout_minutes: 5 + env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt - name: Capture Agentic Action logs if: always() run: | diff --git a/.github/workflows/test-claude-add-issue-comment.lock.yml b/.github/workflows/test-claude-add-issue-comment.lock.yml index d2e38909a11..75c6c26a383 100644 --- a/.github/workflows/test-claude-add-issue-comment.lock.yml +++ b/.github/workflows/test-claude-add-issue-comment.lock.yml @@ -371,10 +371,11 @@ jobs: EOF - name: Create prompt env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} run: | mkdir -p /tmp/aw-prompts - cat > /tmp/aw-prompts/prompt.txt << 'EOF' + cat > $GITHUB_AW_PROMPT << 'EOF' If the title of the issue #${{ github.event.issue.number }} is "Hello from Claude" then add a comment on the issue "Reply from Claude". @@ -414,7 +415,7 @@ jobs: echo "## Generated Prompt" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo '``````markdown' >> $GITHUB_STEP_SUMMARY - cat /tmp/aw-prompts/prompt.txt >> $GITHUB_STEP_SUMMARY + cat $GITHUB_AW_PROMPT >> $GITHUB_STEP_SUMMARY echo '``````' >> $GITHUB_STEP_SUMMARY - name: Generate agentic run info uses: actions/github-script@v7 @@ -521,6 +522,7 @@ jobs: settings: .claude/settings.json timeout_minutes: 5 env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} - name: Capture Agentic Action logs if: always() diff --git a/.github/workflows/test-claude-add-issue-labels.lock.yml b/.github/workflows/test-claude-add-issue-labels.lock.yml index 606fabdbd44..e8c7600c2fa 100644 --- a/.github/workflows/test-claude-add-issue-labels.lock.yml +++ b/.github/workflows/test-claude-add-issue-labels.lock.yml @@ -371,10 +371,11 @@ jobs: EOF - name: Create prompt env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} run: | mkdir -p /tmp/aw-prompts - cat > /tmp/aw-prompts/prompt.txt << 'EOF' + cat > $GITHUB_AW_PROMPT << 'EOF' If the title of the issue #${{ github.event.issue.number }} is exactly "[claude-test] Hello from Claude" then add the issue labels "claude-safe-output-label-test" to the issue. @@ -414,7 +415,7 @@ jobs: echo "## Generated Prompt" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo '``````markdown' >> $GITHUB_STEP_SUMMARY - cat /tmp/aw-prompts/prompt.txt >> $GITHUB_STEP_SUMMARY + cat $GITHUB_AW_PROMPT >> $GITHUB_STEP_SUMMARY echo '``````' >> $GITHUB_STEP_SUMMARY - name: Generate agentic run info uses: actions/github-script@v7 @@ -521,6 +522,7 @@ jobs: settings: .claude/settings.json timeout_minutes: 5 env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} - name: Capture Agentic Action logs if: always() diff --git a/.github/workflows/test-claude-command.lock.yml b/.github/workflows/test-claude-command.lock.yml index af713d26e64..3146c0e57e1 100644 --- a/.github/workflows/test-claude-command.lock.yml +++ b/.github/workflows/test-claude-command.lock.yml @@ -634,10 +634,11 @@ jobs: EOF - name: Create prompt env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} run: | mkdir -p /tmp/aw-prompts - cat > /tmp/aw-prompts/prompt.txt << 'EOF' + cat > $GITHUB_AW_PROMPT << 'EOF' Add a reply comment to issue #${{ github.event.issue.number }} answering the question "${{ needs.task.outputs.text }}" given the context of the repo, starting with saying you're Claude. If there is no command write out a haiku about the repo. @@ -690,7 +691,7 @@ jobs: echo "## Generated Prompt" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo '``````markdown' >> $GITHUB_STEP_SUMMARY - cat /tmp/aw-prompts/prompt.txt >> $GITHUB_STEP_SUMMARY + cat $GITHUB_AW_PROMPT >> $GITHUB_STEP_SUMMARY echo '``````' >> $GITHUB_STEP_SUMMARY - name: Generate agentic run info uses: actions/github-script@v7 @@ -797,6 +798,7 @@ jobs: settings: .claude/settings.json timeout_minutes: 5 env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} - name: Capture Agentic Action logs if: always() diff --git a/.github/workflows/test-claude-create-issue.lock.yml b/.github/workflows/test-claude-create-issue.lock.yml index 1dbc3776bf0..ddb98d89da3 100644 --- a/.github/workflows/test-claude-create-issue.lock.yml +++ b/.github/workflows/test-claude-create-issue.lock.yml @@ -179,10 +179,11 @@ jobs: EOF - name: Create prompt env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} run: | mkdir -p /tmp/aw-prompts - cat > /tmp/aw-prompts/prompt.txt << 'EOF' + cat > $GITHUB_AW_PROMPT << 'EOF' Create an issue with title "Hello from Claude" and body "World" Add a haiku about GitHub Actions and AI to the issue body. @@ -224,7 +225,7 @@ jobs: echo "## Generated Prompt" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo '``````markdown' >> $GITHUB_STEP_SUMMARY - cat /tmp/aw-prompts/prompt.txt >> $GITHUB_STEP_SUMMARY + cat $GITHUB_AW_PROMPT >> $GITHUB_STEP_SUMMARY echo '``````' >> $GITHUB_STEP_SUMMARY - name: Generate agentic run info uses: actions/github-script@v7 @@ -331,6 +332,7 @@ jobs: settings: .claude/settings.json timeout_minutes: 5 env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} - name: Capture Agentic Action logs if: always() diff --git a/.github/workflows/test-claude-create-pull-request-review-comment.lock.yml b/.github/workflows/test-claude-create-pull-request-review-comment.lock.yml index e98a1582c05..7ce1008d74e 100644 --- a/.github/workflows/test-claude-create-pull-request-review-comment.lock.yml +++ b/.github/workflows/test-claude-create-pull-request-review-comment.lock.yml @@ -382,10 +382,11 @@ jobs: EOF - name: Create prompt env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} run: | mkdir -p /tmp/aw-prompts - cat > /tmp/aw-prompts/prompt.txt << 'EOF' + cat > $GITHUB_AW_PROMPT << 'EOF' Analyze the pull request and create a few targeted review comments on the code changes. Create 2-3 review comments focusing on: @@ -428,7 +429,7 @@ jobs: echo "## Generated Prompt" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo '``````markdown' >> $GITHUB_STEP_SUMMARY - cat /tmp/aw-prompts/prompt.txt >> $GITHUB_STEP_SUMMARY + cat $GITHUB_AW_PROMPT >> $GITHUB_STEP_SUMMARY echo '``````' >> $GITHUB_STEP_SUMMARY - name: Generate agentic run info uses: actions/github-script@v7 @@ -535,6 +536,7 @@ jobs: settings: .claude/settings.json timeout_minutes: 5 env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} - name: Capture Agentic Action logs if: always() diff --git a/.github/workflows/test-claude-create-pull-request.lock.yml b/.github/workflows/test-claude-create-pull-request.lock.yml index aabab1cbc7f..5bda9abe558 100644 --- a/.github/workflows/test-claude-create-pull-request.lock.yml +++ b/.github/workflows/test-claude-create-pull-request.lock.yml @@ -179,10 +179,11 @@ jobs: EOF - name: Create prompt env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} run: | mkdir -p /tmp/aw-prompts - cat > /tmp/aw-prompts/prompt.txt << 'EOF' + cat > $GITHUB_AW_PROMPT << 'EOF' Add a file "TEST.md" with content "Hello from Claude" Add a log file "foo.log" containing the current time. This is just a log file and isn't meant to go in the pull request. @@ -231,7 +232,7 @@ jobs: echo "## Generated Prompt" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo '``````markdown' >> $GITHUB_STEP_SUMMARY - cat /tmp/aw-prompts/prompt.txt >> $GITHUB_STEP_SUMMARY + cat $GITHUB_AW_PROMPT >> $GITHUB_STEP_SUMMARY echo '``````' >> $GITHUB_STEP_SUMMARY - name: Generate agentic run info uses: actions/github-script@v7 @@ -350,6 +351,7 @@ jobs: settings: .claude/settings.json timeout_minutes: 5 env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} - name: Capture Agentic Action logs if: always() diff --git a/.github/workflows/test-claude-create-security-report.lock.yml b/.github/workflows/test-claude-create-security-report.lock.yml index 6991a88575f..4f39ce1c604 100644 --- a/.github/workflows/test-claude-create-security-report.lock.yml +++ b/.github/workflows/test-claude-create-security-report.lock.yml @@ -368,10 +368,11 @@ jobs: EOF - name: Create prompt env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} run: | mkdir -p /tmp/aw-prompts - cat > /tmp/aw-prompts/prompt.txt << 'EOF' + cat > $GITHUB_AW_PROMPT << 'EOF' # Security Analysis with Claude Analyze the repository codebase for security vulnerabilities and create security reports. @@ -420,7 +421,7 @@ jobs: echo "## Generated Prompt" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo '``````markdown' >> $GITHUB_STEP_SUMMARY - cat /tmp/aw-prompts/prompt.txt >> $GITHUB_STEP_SUMMARY + cat $GITHUB_AW_PROMPT >> $GITHUB_STEP_SUMMARY echo '``````' >> $GITHUB_STEP_SUMMARY - name: Generate agentic run info uses: actions/github-script@v7 @@ -527,6 +528,7 @@ jobs: settings: .claude/settings.json timeout_minutes: 5 env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} - name: Capture Agentic Action logs if: always() diff --git a/.github/workflows/test-claude-mcp.lock.yml b/.github/workflows/test-claude-mcp.lock.yml index df66ee69929..c259c43c941 100644 --- a/.github/workflows/test-claude-mcp.lock.yml +++ b/.github/workflows/test-claude-mcp.lock.yml @@ -382,10 +382,11 @@ jobs: EOF - name: Create prompt env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} run: | mkdir -p /tmp/aw-prompts - cat > /tmp/aw-prompts/prompt.txt << 'EOF' + cat > $GITHUB_AW_PROMPT << 'EOF' **First, get the current time using the get_current_time tool to timestamp your analysis.** Create an issue with title "Hello from Claude" and a comment in the body saying what the current time is and if you were successful in using the MCP tool @@ -435,7 +436,7 @@ jobs: echo "## Generated Prompt" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo '``````markdown' >> $GITHUB_STEP_SUMMARY - cat /tmp/aw-prompts/prompt.txt >> $GITHUB_STEP_SUMMARY + cat $GITHUB_AW_PROMPT >> $GITHUB_STEP_SUMMARY echo '``````' >> $GITHUB_STEP_SUMMARY - name: Generate agentic run info uses: actions/github-script@v7 @@ -543,6 +544,7 @@ jobs: settings: .claude/settings.json timeout_minutes: 5 env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} - name: Capture Agentic Action logs if: always() diff --git a/.github/workflows/test-claude-push-to-branch.lock.yml b/.github/workflows/test-claude-push-to-branch.lock.yml index 064f3907326..8683196ef14 100644 --- a/.github/workflows/test-claude-push-to-branch.lock.yml +++ b/.github/workflows/test-claude-push-to-branch.lock.yml @@ -233,10 +233,11 @@ jobs: EOF - name: Create prompt env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} run: | mkdir -p /tmp/aw-prompts - cat > /tmp/aw-prompts/prompt.txt << 'EOF' + cat > $GITHUB_AW_PROMPT << 'EOF' Create a new file called "claude-test-file.md" with the following content: ```markdown @@ -318,7 +319,7 @@ jobs: echo "## Generated Prompt" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo '``````markdown' >> $GITHUB_STEP_SUMMARY - cat /tmp/aw-prompts/prompt.txt >> $GITHUB_STEP_SUMMARY + cat $GITHUB_AW_PROMPT >> $GITHUB_STEP_SUMMARY echo '``````' >> $GITHUB_STEP_SUMMARY - name: Generate agentic run info uses: actions/github-script@v7 @@ -437,6 +438,7 @@ jobs: settings: .claude/settings.json timeout_minutes: 5 env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} - name: Capture Agentic Action logs if: always() diff --git a/.github/workflows/test-claude-update-issue.lock.yml b/.github/workflows/test-claude-update-issue.lock.yml index 42b367c058c..408e721b97d 100644 --- a/.github/workflows/test-claude-update-issue.lock.yml +++ b/.github/workflows/test-claude-update-issue.lock.yml @@ -371,10 +371,11 @@ jobs: EOF - name: Create prompt env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} run: | mkdir -p /tmp/aw-prompts - cat > /tmp/aw-prompts/prompt.txt << 'EOF' + cat > $GITHUB_AW_PROMPT << 'EOF' If the title of the issue #${{ github.event.issue.number }} is exactly "[claude-test] Update Issue Test" then: 1. Change the status to "closed" @@ -417,7 +418,7 @@ jobs: echo "## Generated Prompt" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo '``````markdown' >> $GITHUB_STEP_SUMMARY - cat /tmp/aw-prompts/prompt.txt >> $GITHUB_STEP_SUMMARY + cat $GITHUB_AW_PROMPT >> $GITHUB_STEP_SUMMARY echo '``````' >> $GITHUB_STEP_SUMMARY - name: Generate agentic run info uses: actions/github-script@v7 @@ -524,6 +525,7 @@ jobs: settings: .claude/settings.json timeout_minutes: 5 env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} - name: Capture Agentic Action logs if: always() diff --git a/.github/workflows/test-codex-add-issue-comment.lock.yml b/.github/workflows/test-codex-add-issue-comment.lock.yml index 556a6eaf772..0a16c853852 100644 --- a/.github/workflows/test-codex-add-issue-comment.lock.yml +++ b/.github/workflows/test-codex-add-issue-comment.lock.yml @@ -266,10 +266,11 @@ jobs: EOF - name: Create prompt env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} run: | mkdir -p /tmp/aw-prompts - cat > /tmp/aw-prompts/prompt.txt << 'EOF' + cat > $GITHUB_AW_PROMPT << 'EOF' If the title of the issue #${{ github.event.issue.number }} is "Hello from Codex" then add a comment on the issue "Reply from Codex". @@ -309,7 +310,7 @@ jobs: echo "## Generated Prompt" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo '``````markdown' >> $GITHUB_STEP_SUMMARY - cat /tmp/aw-prompts/prompt.txt >> $GITHUB_STEP_SUMMARY + cat $GITHUB_AW_PROMPT >> $GITHUB_STEP_SUMMARY echo '``````' >> $GITHUB_STEP_SUMMARY - name: Generate agentic run info uses: actions/github-script@v7 @@ -363,6 +364,7 @@ jobs: -c model=o4-mini \ --full-auto "$INSTRUCTION" 2>&1 | tee /tmp/test-codex-add-issue-comment.log env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} GITHUB_STEP_SUMMARY: ${{ env.GITHUB_STEP_SUMMARY }} OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} diff --git a/.github/workflows/test-codex-add-issue-labels.lock.yml b/.github/workflows/test-codex-add-issue-labels.lock.yml index b0d69b10c9e..250f0da98c2 100644 --- a/.github/workflows/test-codex-add-issue-labels.lock.yml +++ b/.github/workflows/test-codex-add-issue-labels.lock.yml @@ -266,10 +266,11 @@ jobs: EOF - name: Create prompt env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} run: | mkdir -p /tmp/aw-prompts - cat > /tmp/aw-prompts/prompt.txt << 'EOF' + cat > $GITHUB_AW_PROMPT << 'EOF' If the title of the issue #${{ github.event.issue.number }} is "[codex-test] Hello from Codex" then add the issue labels "codex-safe-output-label-test" to the issue. @@ -309,7 +310,7 @@ jobs: echo "## Generated Prompt" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo '``````markdown' >> $GITHUB_STEP_SUMMARY - cat /tmp/aw-prompts/prompt.txt >> $GITHUB_STEP_SUMMARY + cat $GITHUB_AW_PROMPT >> $GITHUB_STEP_SUMMARY echo '``````' >> $GITHUB_STEP_SUMMARY - name: Generate agentic run info uses: actions/github-script@v7 @@ -363,6 +364,7 @@ jobs: -c model=o4-mini \ --full-auto "$INSTRUCTION" 2>&1 | tee /tmp/test-codex-add-issue-labels.log env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} GITHUB_STEP_SUMMARY: ${{ env.GITHUB_STEP_SUMMARY }} OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} diff --git a/.github/workflows/test-codex-command.lock.yml b/.github/workflows/test-codex-command.lock.yml index cd5cafc8cd4..97e82954a02 100644 --- a/.github/workflows/test-codex-command.lock.yml +++ b/.github/workflows/test-codex-command.lock.yml @@ -634,10 +634,11 @@ jobs: EOF - name: Create prompt env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} run: | mkdir -p /tmp/aw-prompts - cat > /tmp/aw-prompts/prompt.txt << 'EOF' + cat > $GITHUB_AW_PROMPT << 'EOF' Add a reply comment to issue #${{ github.event.issue.number }} answering the question "${{ needs.task.outputs.text }}" given the context of the repo, starting with saying you're Codex. If there is no command write out a haiku about the repo. @@ -690,7 +691,7 @@ jobs: echo "## Generated Prompt" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo '``````markdown' >> $GITHUB_STEP_SUMMARY - cat /tmp/aw-prompts/prompt.txt >> $GITHUB_STEP_SUMMARY + cat $GITHUB_AW_PROMPT >> $GITHUB_STEP_SUMMARY echo '``````' >> $GITHUB_STEP_SUMMARY - name: Generate agentic run info uses: actions/github-script@v7 @@ -797,6 +798,7 @@ jobs: settings: .claude/settings.json timeout_minutes: 5 env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} - name: Capture Agentic Action logs if: always() diff --git a/.github/workflows/test-codex-create-issue.lock.yml b/.github/workflows/test-codex-create-issue.lock.yml index 7d3ca4e99b1..7de5ea36e29 100644 --- a/.github/workflows/test-codex-create-issue.lock.yml +++ b/.github/workflows/test-codex-create-issue.lock.yml @@ -74,10 +74,11 @@ jobs: EOF - name: Create prompt env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} run: | mkdir -p /tmp/aw-prompts - cat > /tmp/aw-prompts/prompt.txt << 'EOF' + cat > $GITHUB_AW_PROMPT << 'EOF' Create an issue with title "Hello from Codex" and body "World" Add a haiku about GitHub Actions and AI to the issue body. @@ -119,7 +120,7 @@ jobs: echo "## Generated Prompt" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo '``````markdown' >> $GITHUB_STEP_SUMMARY - cat /tmp/aw-prompts/prompt.txt >> $GITHUB_STEP_SUMMARY + cat $GITHUB_AW_PROMPT >> $GITHUB_STEP_SUMMARY echo '``````' >> $GITHUB_STEP_SUMMARY - name: Generate agentic run info uses: actions/github-script@v7 @@ -173,6 +174,7 @@ jobs: -c model=o4-mini \ --full-auto "$INSTRUCTION" 2>&1 | tee /tmp/test-codex-create-issue.log env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} GITHUB_STEP_SUMMARY: ${{ env.GITHUB_STEP_SUMMARY }} OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} diff --git a/.github/workflows/test-codex-create-pull-request-review-comment.lock.yml b/.github/workflows/test-codex-create-pull-request-review-comment.lock.yml index 89783447e99..ab3f5e31bed 100644 --- a/.github/workflows/test-codex-create-pull-request-review-comment.lock.yml +++ b/.github/workflows/test-codex-create-pull-request-review-comment.lock.yml @@ -277,10 +277,11 @@ jobs: EOF - name: Create prompt env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} run: | mkdir -p /tmp/aw-prompts - cat > /tmp/aw-prompts/prompt.txt << 'EOF' + cat > $GITHUB_AW_PROMPT << 'EOF' Analyze the pull request and create a few targeted review comments on the code changes. Create 2-3 review comments focusing on: @@ -323,7 +324,7 @@ jobs: echo "## Generated Prompt" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo '``````markdown' >> $GITHUB_STEP_SUMMARY - cat /tmp/aw-prompts/prompt.txt >> $GITHUB_STEP_SUMMARY + cat $GITHUB_AW_PROMPT >> $GITHUB_STEP_SUMMARY echo '``````' >> $GITHUB_STEP_SUMMARY - name: Generate agentic run info uses: actions/github-script@v7 @@ -377,6 +378,7 @@ jobs: -c model=o4-mini \ --full-auto "$INSTRUCTION" 2>&1 | tee /tmp/test-codex-create-pull-request-review-comment.log env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} GITHUB_STEP_SUMMARY: ${{ env.GITHUB_STEP_SUMMARY }} OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} diff --git a/.github/workflows/test-codex-create-pull-request.lock.yml b/.github/workflows/test-codex-create-pull-request.lock.yml index 18d1edcfae6..266574369de 100644 --- a/.github/workflows/test-codex-create-pull-request.lock.yml +++ b/.github/workflows/test-codex-create-pull-request.lock.yml @@ -74,10 +74,11 @@ jobs: EOF - name: Create prompt env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} run: | mkdir -p /tmp/aw-prompts - cat > /tmp/aw-prompts/prompt.txt << 'EOF' + cat > $GITHUB_AW_PROMPT << 'EOF' Add a file "TEST.md" with content "Hello from Codex" Add a log file "foo.log" containing the current time. This is just a log file and isn't meant to go in the pull request. @@ -126,7 +127,7 @@ jobs: echo "## Generated Prompt" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo '``````markdown' >> $GITHUB_STEP_SUMMARY - cat /tmp/aw-prompts/prompt.txt >> $GITHUB_STEP_SUMMARY + cat $GITHUB_AW_PROMPT >> $GITHUB_STEP_SUMMARY echo '``````' >> $GITHUB_STEP_SUMMARY - name: Generate agentic run info uses: actions/github-script@v7 @@ -180,6 +181,7 @@ jobs: -c model=o4-mini \ --full-auto "$INSTRUCTION" 2>&1 | tee /tmp/test-codex-create-pull-request.log env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} GITHUB_STEP_SUMMARY: ${{ env.GITHUB_STEP_SUMMARY }} OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} diff --git a/.github/workflows/test-codex-create-security-report.lock.yml b/.github/workflows/test-codex-create-security-report.lock.yml index de605ee8e12..2b89c1a2413 100644 --- a/.github/workflows/test-codex-create-security-report.lock.yml +++ b/.github/workflows/test-codex-create-security-report.lock.yml @@ -263,10 +263,11 @@ jobs: EOF - name: Create prompt env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} run: | mkdir -p /tmp/aw-prompts - cat > /tmp/aw-prompts/prompt.txt << 'EOF' + cat > $GITHUB_AW_PROMPT << 'EOF' # Security Analysis with Codex Analyze the repository codebase for security vulnerabilities and create security reports. @@ -315,7 +316,7 @@ jobs: echo "## Generated Prompt" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo '``````markdown' >> $GITHUB_STEP_SUMMARY - cat /tmp/aw-prompts/prompt.txt >> $GITHUB_STEP_SUMMARY + cat $GITHUB_AW_PROMPT >> $GITHUB_STEP_SUMMARY echo '``````' >> $GITHUB_STEP_SUMMARY - name: Generate agentic run info uses: actions/github-script@v7 @@ -369,6 +370,7 @@ jobs: -c model=o4-mini \ --full-auto "$INSTRUCTION" 2>&1 | tee /tmp/security-analysis-with-codex.log env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} GITHUB_STEP_SUMMARY: ${{ env.GITHUB_STEP_SUMMARY }} OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} diff --git a/.github/workflows/test-codex-mcp.lock.yml b/.github/workflows/test-codex-mcp.lock.yml index 405ab281222..5209bf7cf1b 100644 --- a/.github/workflows/test-codex-mcp.lock.yml +++ b/.github/workflows/test-codex-mcp.lock.yml @@ -275,10 +275,11 @@ jobs: EOF - name: Create prompt env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} run: | mkdir -p /tmp/aw-prompts - cat > /tmp/aw-prompts/prompt.txt << 'EOF' + cat > $GITHUB_AW_PROMPT << 'EOF' **First, get the current time using the get_current_time tool to timestamp your analysis.** Create an issue with title "Hello from Codex" and a comment in the body saying what the current time is and if you were successful in using the MCP tool @@ -328,7 +329,7 @@ jobs: echo "## Generated Prompt" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo '``````markdown' >> $GITHUB_STEP_SUMMARY - cat /tmp/aw-prompts/prompt.txt >> $GITHUB_STEP_SUMMARY + cat $GITHUB_AW_PROMPT >> $GITHUB_STEP_SUMMARY echo '``````' >> $GITHUB_STEP_SUMMARY - name: Generate agentic run info uses: actions/github-script@v7 @@ -382,6 +383,7 @@ jobs: -c model=o4-mini \ --full-auto "$INSTRUCTION" 2>&1 | tee /tmp/test-codex-mcp.log env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} GITHUB_STEP_SUMMARY: ${{ env.GITHUB_STEP_SUMMARY }} OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} diff --git a/.github/workflows/test-codex-push-to-branch.lock.yml b/.github/workflows/test-codex-push-to-branch.lock.yml index f43838f2126..d8f510ffa6a 100644 --- a/.github/workflows/test-codex-push-to-branch.lock.yml +++ b/.github/workflows/test-codex-push-to-branch.lock.yml @@ -128,10 +128,11 @@ jobs: EOF - name: Create prompt env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} run: | mkdir -p /tmp/aw-prompts - cat > /tmp/aw-prompts/prompt.txt << 'EOF' + cat > $GITHUB_AW_PROMPT << 'EOF' Create a new file called "codex-test-file.md" with the following content: ```markdown @@ -215,7 +216,7 @@ jobs: echo "## Generated Prompt" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo '``````markdown' >> $GITHUB_STEP_SUMMARY - cat /tmp/aw-prompts/prompt.txt >> $GITHUB_STEP_SUMMARY + cat $GITHUB_AW_PROMPT >> $GITHUB_STEP_SUMMARY echo '``````' >> $GITHUB_STEP_SUMMARY - name: Generate agentic run info uses: actions/github-script@v7 @@ -269,6 +270,7 @@ jobs: -c model=o4-mini \ --full-auto "$INSTRUCTION" 2>&1 | tee /tmp/test-codex-push-to-branch.log env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} GITHUB_STEP_SUMMARY: ${{ env.GITHUB_STEP_SUMMARY }} OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} diff --git a/.github/workflows/test-codex-update-issue.lock.yml b/.github/workflows/test-codex-update-issue.lock.yml index 394b43b3859..a74ddcb9356 100644 --- a/.github/workflows/test-codex-update-issue.lock.yml +++ b/.github/workflows/test-codex-update-issue.lock.yml @@ -266,10 +266,11 @@ jobs: EOF - name: Create prompt env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} run: | mkdir -p /tmp/aw-prompts - cat > /tmp/aw-prompts/prompt.txt << 'EOF' + cat > $GITHUB_AW_PROMPT << 'EOF' If the title of the issue #${{ github.event.issue.number }} is exactly "[codex-test] Update Issue Test" then: 1. Change the status to "closed" @@ -312,7 +313,7 @@ jobs: echo "## Generated Prompt" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo '``````markdown' >> $GITHUB_STEP_SUMMARY - cat /tmp/aw-prompts/prompt.txt >> $GITHUB_STEP_SUMMARY + cat $GITHUB_AW_PROMPT >> $GITHUB_STEP_SUMMARY echo '``````' >> $GITHUB_STEP_SUMMARY - name: Generate agentic run info uses: actions/github-script@v7 @@ -366,6 +367,7 @@ jobs: -c model=o4-mini \ --full-auto "$INSTRUCTION" 2>&1 | tee /tmp/test-codex-update-issue.log env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} GITHUB_STEP_SUMMARY: ${{ env.GITHUB_STEP_SUMMARY }} OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} diff --git a/.github/workflows/test-proxy.lock.yml b/.github/workflows/test-proxy.lock.yml index b3b30549097..3254bacf7f6 100644 --- a/.github/workflows/test-proxy.lock.yml +++ b/.github/workflows/test-proxy.lock.yml @@ -335,10 +335,11 @@ jobs: EOF - name: Create prompt env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} run: | mkdir -p /tmp/aw-prompts - cat > /tmp/aw-prompts/prompt.txt << 'EOF' + cat > $GITHUB_AW_PROMPT << 'EOF' ## Task Description Test the MCP network permissions feature to validate that domain restrictions are properly enforced. @@ -401,7 +402,7 @@ jobs: echo "## Generated Prompt" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo '``````markdown' >> $GITHUB_STEP_SUMMARY - cat /tmp/aw-prompts/prompt.txt >> $GITHUB_STEP_SUMMARY + cat $GITHUB_AW_PROMPT >> $GITHUB_STEP_SUMMARY echo '``````' >> $GITHUB_STEP_SUMMARY - name: Generate agentic run info uses: actions/github-script@v7 @@ -509,6 +510,7 @@ jobs: settings: .claude/settings.json timeout_minutes: 5 env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} - name: Capture Agentic Action logs if: always() diff --git a/.github/workflows/test-safe-outputs-custom-engine.lock.yml b/.github/workflows/test-safe-outputs-custom-engine.lock.yml index a75d6c77edb..3237233984b 100644 --- a/.github/workflows/test-safe-outputs-custom-engine.lock.yml +++ b/.github/workflows/test-safe-outputs-custom-engine.lock.yml @@ -84,10 +84,11 @@ jobs: EOF - name: Create prompt env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} run: | mkdir -p /tmp/aw-prompts - cat > /tmp/aw-prompts/prompt.txt << 'EOF' + cat > $GITHUB_AW_PROMPT << 'EOF' # Test Safe Outputs - Custom Engine This workflow validates all safe output types using the custom engine implementation. It demonstrates the ability to use GitHub Actions steps directly in agentic workflows while leveraging the safe output processing system. @@ -223,7 +224,7 @@ jobs: echo "## Generated Prompt" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo '``````markdown' >> $GITHUB_STEP_SUMMARY - cat /tmp/aw-prompts/prompt.txt >> $GITHUB_STEP_SUMMARY + cat $GITHUB_AW_PROMPT >> $GITHUB_STEP_SUMMARY echo '``````' >> $GITHUB_STEP_SUMMARY - name: Generate agentic run info uses: actions/github-script@v7 @@ -268,6 +269,7 @@ jobs: echo '{"type": "create-issue", "title": "[Custom Engine Test] Test Issue Created by Custom Engine", "body": "# Test Issue Created by Custom Engine\n\nThis issue was automatically created by the test-safe-outputs-custom-engine workflow to validate the create-issue safe output functionality.\n\n**Test Details:**\n- Engine: Custom\n- Trigger: ${{ github.event_name }}\n- Repository: ${{ github.repository }}\n- Run ID: ${{ github.run_id }}\n\nThis is a test issue and can be closed after verification.", "labels": ["test-safe-outputs", "automation", "custom-engine"]}' >> $GITHUB_AW_SAFE_OUTPUTS env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} - name: Generate Add Issue Comment Output @@ -275,6 +277,7 @@ jobs: echo '{"type": "add-issue-comment", "body": "## Test Comment from Custom Engine\n\nThis comment was automatically posted by the test-safe-outputs-custom-engine workflow to validate the add-issue-comment safe output functionality.\n\n**Test Information:**\n- Workflow: test-safe-outputs-custom-engine\n- Engine Type: Custom (GitHub Actions steps)\n- Execution Time: '"$(date)"'\n- Event: ${{ github.event_name }}\n\n✅ Safe output testing in progress..."}' >> $GITHUB_AW_SAFE_OUTPUTS env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} - name: Generate Add Issue Labels Output @@ -282,6 +285,7 @@ jobs: echo '{"type": "add-issue-label", "labels": ["test-safe-outputs", "automation", "custom-engine"]}' >> $GITHUB_AW_SAFE_OUTPUTS env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} - name: Generate Update Issue Output @@ -289,6 +293,7 @@ jobs: echo '{"type": "update-issue", "title": "[UPDATED] Test Issue - Custom Engine Safe Output Test", "body": "# Updated Issue Body\n\nThis issue has been updated by the test-safe-outputs-custom-engine workflow to validate the update-issue safe output functionality.\n\n**Update Details:**\n- Updated by: Custom Engine\n- Update time: '"$(date)"'\n- Original trigger: ${{ github.event_name }}\n\n**Test Status:** ✅ Update functionality verified", "status": "open"}' >> $GITHUB_AW_SAFE_OUTPUTS env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} - name: Generate Create Pull Request Output @@ -302,6 +307,7 @@ jobs: echo '{"type": "create-pull-request", "title": "[Custom Engine Test] Test Pull Request - Custom Engine Safe Output", "body": "# Test Pull Request - Custom Engine Safe Output\n\nThis pull request was automatically created by the test-safe-outputs-custom-engine workflow to validate the create-pull-request safe output functionality.\n\n## Changes Made\n- Created test file with timestamp\n- Demonstrates custom engine file creation capabilities\n\n## Test Information\n- Engine: Custom (GitHub Actions steps)\n- Workflow: test-safe-outputs-custom-engine\n- Trigger Event: ${{ github.event_name }}\n- Run ID: ${{ github.run_id }}\n\nThis PR can be merged or closed after verification of the safe output functionality.", "labels": ["test-safe-outputs", "automation", "custom-engine"], "draft": true}' >> $GITHUB_AW_SAFE_OUTPUTS env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} - name: Generate Create Discussion Output @@ -309,6 +315,7 @@ jobs: echo '{"type": "create-discussion", "title": "[Custom Engine Test] Test Discussion - Custom Engine Safe Output", "body": "# Test Discussion - Custom Engine Safe Output\n\nThis discussion was automatically created by the test-safe-outputs-custom-engine workflow to validate the create-discussion safe output functionality.\n\n## Purpose\nThis discussion serves as a test of the safe output systems ability to create GitHub discussions through custom engine workflows.\n\n## Test Details\n- **Engine Type:** Custom (GitHub Actions steps)\n- **Workflow:** test-safe-outputs-custom-engine\n- **Created:** '"$(date)"'\n- **Trigger:** ${{ github.event_name }}\n- **Repository:** ${{ github.repository }}\n\n## Discussion Points\n1. Custom engine successfully executed\n2. Safe output file generation completed\n3. Discussion creation triggered\n\nFeel free to participate in this test discussion or archive it after verification."}' >> $GITHUB_AW_SAFE_OUTPUTS env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} - name: Generate PR Review Comment Output @@ -316,6 +323,7 @@ jobs: echo '{"type": "create-pull-request-review-comment", "path": "README.md", "line": 1, "body": "## Custom Engine Review Comment Test\n\nThis review comment was automatically created by the test-safe-outputs-custom-engine workflow to validate the create-pull-request-review-comment safe output functionality.\n\n**Review Details:**\n- Generated by: Custom Engine\n- Test time: '"$(date)"'\n- Workflow: test-safe-outputs-custom-engine\n\n✅ PR review comment safe output test completed."}' >> $GITHUB_AW_SAFE_OUTPUTS env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} - name: Generate Push to Branch Output @@ -328,6 +336,7 @@ jobs: echo '{"type": "push-to-branch", "message": "Custom engine test: Push to branch functionality\n\nThis commit was generated by the test-safe-outputs-custom-engine workflow to validate the push-to-branch safe output functionality.\n\nFiles created:\n- branch-push-test-[timestamp].md\n\nTest executed at: '"$(date)"'"}' >> $GITHUB_AW_SAFE_OUTPUTS env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} - name: Generate Missing Tool Output @@ -335,6 +344,7 @@ jobs: echo '{"type": "missing-tool", "tool": "example-missing-tool", "reason": "This is a test of the missing-tool safe output functionality. No actual tool is missing.", "alternatives": "This is a simulated missing tool report generated by the custom engine test workflow.", "context": "test-safe-outputs-custom-engine workflow validation"}' >> $GITHUB_AW_SAFE_OUTPUTS env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} - name: List generated outputs @@ -350,6 +360,7 @@ jobs: ls -la *.md 2>/dev/null || echo "No additional .md files found" env: + GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }} - name: Ensure log file exists diff --git a/package-lock.json b/package-lock.json index 5f6152140e4..e3b562eb91c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "gh-aw", + "name": "gh-aw-copilots", "lockfileVersion": 3, "requires": true, "packages": { diff --git a/pkg/workflow/claude_engine.go b/pkg/workflow/claude_engine.go index 44e54252aed..1aaa4963225 100644 --- a/pkg/workflow/claude_engine.go +++ b/pkg/workflow/claude_engine.go @@ -183,26 +183,23 @@ func (e *ClaudeEngine) GetExecutionSteps(workflowData *WorkflowData, logFile str } } - // Add environment section if needed - hasEnvSection := workflowData.SafeOutputs != nil || - (workflowData.EngineConfig != nil && len(workflowData.EngineConfig.Env) > 0) || - (workflowData.EngineConfig != nil && workflowData.EngineConfig.MaxTurns != "") + // Add environment section - always include environment section for GITHUB_AW_PROMPT + stepLines = append(stepLines, " env:") - if hasEnvSection { - stepLines = append(stepLines, " env:") + // Always add GITHUB_AW_PROMPT for agentic workflows + stepLines = append(stepLines, " GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt") - if workflowData.SafeOutputs != nil { - stepLines = append(stepLines, " GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }}") - } + if workflowData.SafeOutputs != nil { + stepLines = append(stepLines, " GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }}") + } - if workflowData.EngineConfig != nil && workflowData.EngineConfig.MaxTurns != "" { - stepLines = append(stepLines, fmt.Sprintf(" GITHUB_AW_MAX_TURNS: %s", workflowData.EngineConfig.MaxTurns)) - } + if workflowData.EngineConfig != nil && workflowData.EngineConfig.MaxTurns != "" { + stepLines = append(stepLines, fmt.Sprintf(" GITHUB_AW_MAX_TURNS: %s", workflowData.EngineConfig.MaxTurns)) + } - if workflowData.EngineConfig != nil && len(workflowData.EngineConfig.Env) > 0 { - for key, value := range workflowData.EngineConfig.Env { - stepLines = append(stepLines, fmt.Sprintf(" %s: %s", key, value)) - } + if workflowData.EngineConfig != nil && len(workflowData.EngineConfig.Env) > 0 { + for key, value := range workflowData.EngineConfig.Env { + stepLines = append(stepLines, fmt.Sprintf(" %s: %s", key, value)) } } diff --git a/pkg/workflow/codex_engine.go b/pkg/workflow/codex_engine.go index cc243fe3c43..dd42236f639 100644 --- a/pkg/workflow/codex_engine.go +++ b/pkg/workflow/codex_engine.go @@ -84,6 +84,7 @@ codex exec \ env := map[string]string{ "OPENAI_API_KEY": "${{ secrets.OPENAI_API_KEY }}", "GITHUB_STEP_SUMMARY": "${{ env.GITHUB_STEP_SUMMARY }}", + "GITHUB_AW_PROMPT": "/tmp/aw-prompts/prompt.txt", } // Add GITHUB_AW_SAFE_OUTPUTS if output is needed @@ -145,6 +146,31 @@ func (e *CodexEngine) convertStepToYAML(stepMap map[string]any) (string, error) } } + // Add id field if present + if id, hasID := stepMap["id"]; hasID { + if idStr, ok := id.(string); ok { + stepYAML = append(stepYAML, fmt.Sprintf(" id: %s", idStr)) + } + } + + // Add continue-on-error field if present + if continueOnError, hasContinueOnError := stepMap["continue-on-error"]; hasContinueOnError { + // Handle both string and boolean values for continue-on-error + switch v := continueOnError.(type) { + case bool: + stepYAML = append(stepYAML, fmt.Sprintf(" continue-on-error: %t", v)) + case string: + stepYAML = append(stepYAML, fmt.Sprintf(" continue-on-error: %s", v)) + } + } + + // Add uses action + if uses, hasUses := stepMap["uses"]; hasUses { + if usesStr, ok := uses.(string); ok { + stepYAML = append(stepYAML, fmt.Sprintf(" uses: %s", usesStr)) + } + } + // Add run command if run, hasRun := stepMap["run"]; hasRun { if runStr, ok := run.(string); ok { @@ -157,13 +183,6 @@ func (e *CodexEngine) convertStepToYAML(stepMap map[string]any) (string, error) } } - // Add uses action - if uses, hasUses := stepMap["uses"]; hasUses { - if usesStr, ok := uses.(string); ok { - stepYAML = append(stepYAML, fmt.Sprintf(" uses: %s", usesStr)) - } - } - // Add with parameters if with, hasWith := stepMap["with"]; hasWith { if withMap, ok := with.(map[string]any); ok { diff --git a/pkg/workflow/codex_engine_test.go b/pkg/workflow/codex_engine_test.go index 681b08e4862..161b7c024cf 100644 --- a/pkg/workflow/codex_engine_test.go +++ b/pkg/workflow/codex_engine_test.go @@ -125,3 +125,78 @@ func TestCodexEngineWithVersion(t *testing.T) { t.Error("Expected versioned npm install command with @openai/codex@3.0.1") } } + +func TestCodexEngineConvertStepToYAMLWithIdAndContinueOnError(t *testing.T) { + engine := NewCodexEngine() + + // Test step with id and continue-on-error fields + stepMap := map[string]any{ + "name": "Test step with id and continue-on-error", + "id": "test-step", + "continue-on-error": true, + "run": "echo 'test'", + } + + yaml, err := engine.convertStepToYAML(stepMap) + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + // Check that id field is included + if !strings.Contains(yaml, "id: test-step") { + t.Errorf("Expected YAML to contain 'id: test-step', got:\n%s", yaml) + } + + // Check that continue-on-error field is included + if !strings.Contains(yaml, "continue-on-error: true") { + t.Errorf("Expected YAML to contain 'continue-on-error: true', got:\n%s", yaml) + } + + // Test with string continue-on-error + stepMap2 := map[string]any{ + "name": "Test step with string continue-on-error", + "id": "test-step-2", + "continue-on-error": "false", + "uses": "actions/checkout@v4", + } + + yaml2, err := engine.convertStepToYAML(stepMap2) + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + // Check that continue-on-error field is included as string + if !strings.Contains(yaml2, "continue-on-error: false") { + t.Errorf("Expected YAML to contain 'continue-on-error: false', got:\n%s", yaml2) + } +} + +func TestCodexEngineExecutionIncludesGitHubAWPrompt(t *testing.T) { + engine := NewCodexEngine() + + workflowData := &WorkflowData{ + Name: "test-workflow", + } + + steps := engine.GetExecutionSteps(workflowData, "/tmp/test.log") + + // Should have at least one step + if len(steps) == 0 { + t.Error("Expected at least one execution step") + return + } + + // Check that GITHUB_AW_PROMPT environment variable is included + foundPromptEnv := false + for _, step := range steps { + stepContent := strings.Join([]string(step), "\n") + if strings.Contains(stepContent, "GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt") { + foundPromptEnv = true + break + } + } + + if !foundPromptEnv { + t.Error("Expected GITHUB_AW_PROMPT environment variable in codex execution steps") + } +} diff --git a/pkg/workflow/codex_test.go b/pkg/workflow/codex_test.go index 1a23a01d9b2..f20b2e2f62f 100644 --- a/pkg/workflow/codex_test.go +++ b/pkg/workflow/codex_test.go @@ -155,7 +155,7 @@ This is a test workflow. if !strings.Contains(lockContent, "Print prompt to step summary") { t.Errorf("Expected lock file to contain 'Print prompt to step summary' step but it didn't.\nContent:\n%s", lockContent) } - if !strings.Contains(lockContent, "cat /tmp/aw-prompts/prompt.txt >> $GITHUB_STEP_SUMMARY") { + if !strings.Contains(lockContent, "cat $GITHUB_AW_PROMPT >> $GITHUB_STEP_SUMMARY") { t.Errorf("Expected lock file to contain prompt printing command but it didn't.\nContent:\n%s", lockContent) } // Ensure it does NOT contain Claude Code @@ -174,7 +174,7 @@ This is a test workflow. if !strings.Contains(lockContent, "Print prompt to step summary") { t.Errorf("Expected lock file to contain 'Print prompt to step summary' step but it didn't.\nContent:\n%s", lockContent) } - if !strings.Contains(lockContent, "cat /tmp/aw-prompts/prompt.txt >> $GITHUB_STEP_SUMMARY") { + if !strings.Contains(lockContent, "cat $GITHUB_AW_PROMPT >> $GITHUB_STEP_SUMMARY") { t.Errorf("Expected lock file to contain prompt printing command but it didn't.\nContent:\n%s", lockContent) } // Check that mcp-servers.json is generated (not config.toml) diff --git a/pkg/workflow/compiler.go b/pkg/workflow/compiler.go index bc39c9eaf1e..09b0857a08a 100644 --- a/pkg/workflow/compiler.go +++ b/pkg/workflow/compiler.go @@ -2720,15 +2720,18 @@ func (c *Compiler) generateUploadAccessLogs(yaml *strings.Builder, tools map[str func (c *Compiler) generatePrompt(yaml *strings.Builder, data *WorkflowData, engine CodingAgentEngine) { yaml.WriteString(" - name: Create prompt\n") + // Add environment variables section - always include GITHUB_AW_PROMPT + yaml.WriteString(" env:\n") + yaml.WriteString(" GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt\n") + // Only add GITHUB_AW_SAFE_OUTPUTS environment variable if safe-outputs feature is used if data.SafeOutputs != nil { - yaml.WriteString(" env:\n") yaml.WriteString(" GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }}\n") } yaml.WriteString(" run: |\n") yaml.WriteString(" mkdir -p /tmp/aw-prompts\n") - yaml.WriteString(" cat > /tmp/aw-prompts/prompt.txt << 'EOF'\n") + yaml.WriteString(" cat > $GITHUB_AW_PROMPT << 'EOF'\n") // Add markdown content with proper indentation for _, line := range strings.Split(data.MarkdownContent, "\n") { @@ -2967,7 +2970,7 @@ func (c *Compiler) generatePrompt(yaml *strings.Builder, data *WorkflowData, eng yaml.WriteString(" echo \"## Generated Prompt\" >> $GITHUB_STEP_SUMMARY\n") yaml.WriteString(" echo \"\" >> $GITHUB_STEP_SUMMARY\n") yaml.WriteString(" echo '``````markdown' >> $GITHUB_STEP_SUMMARY\n") - yaml.WriteString(" cat /tmp/aw-prompts/prompt.txt >> $GITHUB_STEP_SUMMARY\n") + yaml.WriteString(" cat $GITHUB_AW_PROMPT >> $GITHUB_STEP_SUMMARY\n") yaml.WriteString(" echo '``````' >> $GITHUB_STEP_SUMMARY\n") } diff --git a/pkg/workflow/custom_engine.go b/pkg/workflow/custom_engine.go index 0630454b3f1..bbf9bac8a51 100644 --- a/pkg/workflow/custom_engine.go +++ b/pkg/workflow/custom_engine.go @@ -36,10 +36,8 @@ func (e *CustomEngine) GetExecutionSteps(workflowData *WorkflowData, logFile str // Generate each custom step if they exist, with environment variables if workflowData.EngineConfig != nil && len(workflowData.EngineConfig.Steps) > 0 { - // Check if we need environment section for any step - hasEnvSection := workflowData.SafeOutputs != nil || - (workflowData.EngineConfig != nil && workflowData.EngineConfig.MaxTurns != "") || - (workflowData.EngineConfig != nil && len(workflowData.EngineConfig.Env) > 0) + // Check if we need environment section for any step - always true now for GITHUB_AW_PROMPT + hasEnvSection := true for _, step := range workflowData.EngineConfig.Steps { stepYAML, err := e.convertStepToYAML(step) @@ -50,11 +48,14 @@ func (e *CustomEngine) GetExecutionSteps(workflowData *WorkflowData, logFile str // Check if this step needs environment variables injected stepStr := stepYAML - if hasEnvSection && strings.Contains(stepYAML, "run:") { - // Add environment variables to run steps after the entire run block + if hasEnvSection { + // Add environment variables to all steps (both run and uses) stepStr = strings.TrimRight(stepYAML, "\n") stepStr += "\n env:\n" + // Always add GITHUB_AW_PROMPT for agentic workflows + stepStr += " GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt\n" + // Add GITHUB_AW_SAFE_OUTPUTS if safe-outputs feature is used if workflowData.SafeOutputs != nil { stepStr += " GITHUB_AW_SAFE_OUTPUTS: ${{ env.GITHUB_AW_SAFE_OUTPUTS }}\n" @@ -103,6 +104,31 @@ func (e *CustomEngine) convertStepToYAML(stepMap map[string]any) (string, error) } } + // Add id field if present + if id, hasID := stepMap["id"]; hasID { + if idStr, ok := id.(string); ok { + stepYAML = append(stepYAML, fmt.Sprintf(" id: %s", idStr)) + } + } + + // Add continue-on-error field if present + if continueOnError, hasContinueOnError := stepMap["continue-on-error"]; hasContinueOnError { + // Handle both string and boolean values for continue-on-error + switch v := continueOnError.(type) { + case bool: + stepYAML = append(stepYAML, fmt.Sprintf(" continue-on-error: %t", v)) + case string: + stepYAML = append(stepYAML, fmt.Sprintf(" continue-on-error: %s", v)) + } + } + + // Add uses action + if uses, hasUses := stepMap["uses"]; hasUses { + if usesStr, ok := uses.(string); ok { + stepYAML = append(stepYAML, fmt.Sprintf(" uses: %s", usesStr)) + } + } + // Add run command if run, hasRun := stepMap["run"]; hasRun { if runStr, ok := run.(string); ok { @@ -115,13 +141,6 @@ func (e *CustomEngine) convertStepToYAML(stepMap map[string]any) (string, error) } } - // Add uses action - if uses, hasUses := stepMap["uses"]; hasUses { - if usesStr, ok := uses.(string); ok { - stepYAML = append(stepYAML, fmt.Sprintf(" uses: %s", usesStr)) - } - } - // Add with parameters if with, hasWith := stepMap["with"]; hasWith { if withMap, ok := with.(map[string]any); ok { diff --git a/pkg/workflow/custom_engine_test.go b/pkg/workflow/custom_engine_test.go index e93f27f0f91..39b2fa30423 100644 --- a/pkg/workflow/custom_engine_test.go +++ b/pkg/workflow/custom_engine_test.go @@ -61,6 +61,72 @@ func TestCustomEngineGetExecutionSteps(t *testing.T) { } } +func TestCustomEngineGetExecutionStepsWithIdAndContinueOnError(t *testing.T) { + engine := NewCustomEngine() + + // Create engine config with steps that include id and continue-on-error fields + engineConfig := &EngineConfig{ + ID: "custom", + Steps: []map[string]any{ + { + "name": "Setup with ID", + "id": "setup-step", + "continue-on-error": true, + "uses": "actions/setup-node@v4", + "with": map[string]any{ + "node-version": "18", + }, + }, + { + "name": "Run command with continue-on-error string", + "id": "run-step", + "continue-on-error": "false", + "run": "npm test", + }, + }, + } + + workflowData := &WorkflowData{ + Name: "test-workflow", + EngineConfig: engineConfig, + } + + steps := engine.GetExecutionSteps(workflowData, "/tmp/test.log") + + // Test with engine config - steps should be populated (2 custom steps + 1 log step) + if len(steps) != 3 { + t.Errorf("Expected 3 steps when engine config has 2 steps (2 custom + 1 log), got %d", len(steps)) + } + + // Check the first step content includes id and continue-on-error + if len(steps) > 0 { + firstStepContent := strings.Join([]string(steps[0]), "\n") + if !strings.Contains(firstStepContent, "id: setup-step") { + t.Errorf("Expected first step to contain 'id: setup-step', got:\n%s", firstStepContent) + } + if !strings.Contains(firstStepContent, "continue-on-error: true") { + t.Errorf("Expected first step to contain 'continue-on-error: true', got:\n%s", firstStepContent) + } + if !strings.Contains(firstStepContent, "GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt") { + t.Errorf("Expected first step to contain 'GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt', got:\n%s", firstStepContent) + } + } + + // Check the second step content + if len(steps) > 1 { + secondStepContent := strings.Join([]string(steps[1]), "\n") + if !strings.Contains(secondStepContent, "id: run-step") { + t.Errorf("Expected second step to contain 'id: run-step', got:\n%s", secondStepContent) + } + if !strings.Contains(secondStepContent, "continue-on-error: false") { + t.Errorf("Expected second step to contain 'continue-on-error: false', got:\n%s", secondStepContent) + } + if !strings.Contains(secondStepContent, "GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt") { + t.Errorf("Expected second step to contain 'GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt', got:\n%s", secondStepContent) + } + } +} + func TestCustomEngineGetExecutionStepsWithSteps(t *testing.T) { engine := NewCustomEngine() @@ -105,7 +171,7 @@ func TestCustomEngineGetExecutionStepsWithSteps(t *testing.T) { } } - // Check the second step content + // Check the second step content includes GITHUB_AW_PROMPT if len(config) > 1 { secondStepContent := strings.Join([]string(config[1]), "\n") if !strings.Contains(secondStepContent, "name: Run tests") { @@ -114,6 +180,9 @@ func TestCustomEngineGetExecutionStepsWithSteps(t *testing.T) { if !strings.Contains(secondStepContent, "run:") && !strings.Contains(secondStepContent, "npm test") { t.Errorf("Expected second step to contain run command 'npm test', got:\n%s", secondStepContent) } + if !strings.Contains(secondStepContent, "GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt") { + t.Errorf("Expected second step to contain 'GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt', got:\n%s", secondStepContent) + } } } diff --git a/pkg/workflow/output_missing_tool_test.go b/pkg/workflow/output_missing_tool_test.go index 68589532faa..645401c2f98 100644 --- a/pkg/workflow/output_missing_tool_test.go +++ b/pkg/workflow/output_missing_tool_test.go @@ -113,6 +113,29 @@ func TestMissingToolSafeOutput(t *testing.T) { } } +func TestGeneratePromptIncludesGitHubAWPrompt(t *testing.T) { + compiler := NewCompiler(false, "", "test") + + data := &WorkflowData{ + MarkdownContent: "Test workflow content", + } + + var yaml strings.Builder + compiler.generatePrompt(&yaml, data, &ClaudeEngine{}) + + output := yaml.String() + + // Check that GITHUB_AW_PROMPT environment variable is always included + if !strings.Contains(output, "GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt") { + t.Error("Expected 'GITHUB_AW_PROMPT: /tmp/aw-prompts/prompt.txt' in prompt generation step") + } + + // Check that env section is always present now + if !strings.Contains(output, "env:") { + t.Error("Expected 'env:' section in prompt generation step") + } +} + func TestMissingToolPromptGeneration(t *testing.T) { compiler := NewCompiler(false, "", "test") From 7226c7d9df8721675258df4f2c528263af2a0cfe Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Fri, 5 Sep 2025 09:28:27 -0700 Subject: [PATCH 4/4] Add JSON Schema for Agent Output File Structure (#73) * Initial plan * Add comprehensive JSON schema for agent output file with validation and documentation Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> * Remove extra files, keep only agent-output.json schema Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> Co-authored-by: Peli de Halleux --- schemas/agent-output.json | 309 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 309 insertions(+) create mode 100644 schemas/agent-output.json diff --git a/schemas/agent-output.json b/schemas/agent-output.json new file mode 100644 index 00000000000..16963e10245 --- /dev/null +++ b/schemas/agent-output.json @@ -0,0 +1,309 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://github.com/githubnext/gh-aw-copilots/schemas/agent-output.json", + "title": "GitHub Agentic Workflows Agent Output", + "description": "Schema for the agent output file generated by the collect_output step in GitHub Agentic Workflows. This file contains the validated output from AI agents, structured as SafeOutput items with any validation errors. The actual business logic validation (such as ensuring update-issue has at least one updateable field) is handled by the JavaScript validation code.", + "type": "object", + "properties": { + "items": { + "type": "array", + "description": "Array of validated safe output items", + "items": { + "$ref": "#/$defs/SafeOutput" + } + }, + "errors": { + "type": "array", + "description": "Array of validation errors encountered during processing", + "items": { + "type": "string" + } + } + }, + "required": ["items", "errors"], + "additionalProperties": false, + "$defs": { + "SafeOutput": { + "title": "Safe Output Item", + "description": "Union type of all supported safe output entries", + "oneOf": [ + {"$ref": "#/$defs/CreateIssueOutput"}, + {"$ref": "#/$defs/AddIssueCommentOutput"}, + {"$ref": "#/$defs/CreatePullRequestOutput"}, + {"$ref": "#/$defs/AddIssueLabelOutput"}, + {"$ref": "#/$defs/UpdateIssueOutput"}, + {"$ref": "#/$defs/PushToBranchOutput"}, + {"$ref": "#/$defs/CreatePullRequestReviewCommentOutput"}, + {"$ref": "#/$defs/CreateDiscussionOutput"}, + {"$ref": "#/$defs/MissingToolOutput"}, + {"$ref": "#/$defs/CreateSecurityReportOutput"} + ] + }, + "CreateIssueOutput": { + "title": "Create Issue Output", + "description": "Output for creating a GitHub issue", + "type": "object", + "properties": { + "type": { + "const": "create-issue" + }, + "title": { + "type": "string", + "description": "Title of the issue to create", + "minLength": 1 + }, + "body": { + "type": "string", + "description": "Body content of the issue", + "minLength": 1 + }, + "labels": { + "type": "array", + "description": "Optional labels to add to the issue", + "items": { + "type": "string" + } + } + }, + "required": ["type", "title", "body"], + "additionalProperties": false + }, + "AddIssueCommentOutput": { + "title": "Add Issue Comment Output", + "description": "Output for adding a comment to an issue or pull request", + "type": "object", + "properties": { + "type": { + "const": "add-issue-comment" + }, + "body": { + "type": "string", + "description": "Comment body content", + "minLength": 1 + } + }, + "required": ["type", "body"], + "additionalProperties": false + }, + "CreatePullRequestOutput": { + "title": "Create Pull Request Output", + "description": "Output for creating a GitHub pull request", + "type": "object", + "properties": { + "type": { + "const": "create-pull-request" + }, + "title": { + "type": "string", + "description": "Title of the pull request", + "minLength": 1 + }, + "body": { + "type": "string", + "description": "Body content of the pull request", + "minLength": 1 + }, + "branch": { + "type": "string", + "description": "Optional branch name for the pull request" + }, + "labels": { + "type": "array", + "description": "Optional labels to add to the pull request", + "items": { + "type": "string" + } + } + }, + "required": ["type", "title", "body"], + "additionalProperties": false + }, + "AddIssueLabelOutput": { + "title": "Add Issue Label Output", + "description": "Output for adding labels to an issue or pull request", + "type": "object", + "properties": { + "type": { + "const": "add-issue-label" + }, + "labels": { + "type": "array", + "description": "Array of label names to add", + "items": { + "type": "string" + }, + "minItems": 1 + } + }, + "required": ["type", "labels"], + "additionalProperties": false + }, + "UpdateIssueOutput": { + "title": "Update Issue Output", + "description": "Output for updating an existing issue. Note: The JavaScript validation ensures at least one of status, title, or body is provided.", + "type": "object", + "properties": { + "type": { + "const": "update-issue" + }, + "status": { + "type": "string", + "description": "New status for the issue", + "enum": ["open", "closed"] + }, + "title": { + "type": "string", + "description": "New title for the issue" + }, + "body": { + "type": "string", + "description": "New body content for the issue" + }, + "issue_number": { + "oneOf": [ + {"type": "number"}, + {"type": "string"} + ], + "description": "Issue number to update (for target '*')" + } + }, + "required": ["type"], + "additionalProperties": false + }, + "PushToBranchOutput": { + "title": "Push to Branch Output", + "description": "Output for pushing changes directly to a branch", + "type": "object", + "properties": { + "type": { + "const": "push-to-branch" + }, + "message": { + "type": "string", + "description": "Optional commit message" + }, + "pull_request_number": { + "oneOf": [ + {"type": "number"}, + {"type": "string"} + ], + "description": "Pull request number (for target '*')" + } + }, + "required": ["type"], + "additionalProperties": false + }, + "CreatePullRequestReviewCommentOutput": { + "title": "Create Pull Request Review Comment Output", + "description": "Output for creating a review comment on a specific line of code", + "type": "object", + "properties": { + "type": { + "const": "create-pull-request-review-comment" + }, + "path": { + "type": "string", + "description": "File path for the comment", + "minLength": 1 + }, + "line": { + "oneOf": [ + {"type": "number", "minimum": 1}, + {"type": "string", "pattern": "^[1-9][0-9]*$"} + ], + "description": "Line number for the comment" + }, + "body": { + "type": "string", + "description": "Comment body content", + "minLength": 1 + }, + "start_line": { + "oneOf": [ + {"type": "number", "minimum": 1}, + {"type": "string", "pattern": "^[1-9][0-9]*$"} + ], + "description": "Optional start line for multi-line comments" + }, + "side": { + "type": "string", + "description": "Side of the diff to comment on", + "enum": ["LEFT", "RIGHT"] + } + }, + "required": ["type", "path", "line", "body"], + "additionalProperties": false + }, + "CreateDiscussionOutput": { + "title": "Create Discussion Output", + "description": "Output for creating a GitHub discussion", + "type": "object", + "properties": { + "type": { + "const": "create-discussion" + }, + "title": { + "type": "string", + "description": "Title of the discussion", + "minLength": 1 + }, + "body": { + "type": "string", + "description": "Body content of the discussion", + "minLength": 1 + } + }, + "required": ["type", "title", "body"], + "additionalProperties": false + }, + "MissingToolOutput": { + "title": "Missing Tool Output", + "description": "Output for reporting missing tools or functionality", + "type": "object", + "properties": { + "type": { + "const": "missing-tool" + }, + "tool": { + "type": "string", + "description": "Name of the missing tool", + "minLength": 1 + }, + "reason": { + "type": "string", + "description": "Reason why the tool is needed", + "minLength": 1 + }, + "alternatives": { + "type": "string", + "description": "Optional alternative suggestions" + } + }, + "required": ["type", "tool", "reason"], + "additionalProperties": false + }, + "CreateSecurityReportOutput": { + "title": "Create Security Report Output", + "description": "Output for generating SARIF security reports", + "type": "object", + "properties": { + "type": { + "const": "create-security-report" + }, + "sarif": { + "oneOf": [ + {"type": "object"}, + {"type": "string"} + ], + "description": "SARIF content as object or string" + }, + "category": { + "type": "string", + "description": "Optional category for the security report" + } + }, + "required": ["type", "sarif"], + "additionalProperties": false + } + } +} \ No newline at end of file