chore: sync workflow templates - #128
Conversation
Automated sync from stranske/Workflows Template hash: 13e4f1e21f38 Changes synced from sync-manifest.yml
🤖 Keepalive Loop StatusPR #128 | Agent: Codex | Iteration 0/5 Current State
🔍 Failure Classification| Error type | infrastructure | |
|
Status | ✅ no new diagnostics |
|
Autofix updated these files:
|
There was a problem hiding this comment.
Pull request overview
This PR syncs workflow templates from the stranske/Workflows repository, introducing five new agent-based workflows and a minor formatting improvement to issue_formatter.py. The workflows implement various automation features for issue and PR management using LLM-based analysis.
Key Changes:
- Added five new agent workflow files implementing issue processing automation (verify-to-issue, auto-label, capability check, decomposition, duplicate detection)
- Minor formatting fix in issue_formatter.py adding proper import grouping per PEP 8
- All workflows follow consistent patterns using Python scripts embedded via heredoc or -c flag with environment variable passing
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| scripts/langchain/issue_formatter.py | Adds blank line between third-party and local imports (PEP 8 compliance) |
| .github/workflows/agents-verify-to-issue.yml | Creates follow-up issues from PR verification feedback via label trigger |
| .github/workflows/agents-auto-label.yml | Suggests and auto-applies labels using semantic similarity matching |
| .github/workflows/agents-capability-check.yml | Pre-flight gate checking if agents can complete assigned tasks |
| .github/workflows/agents-decompose.yml | Breaks down large issues into manageable sub-tasks using LLM |
| .github/workflows/agents-dedup.yml | Detects and flags potential duplicate issues via embeddings |
|
|
||
| - name: Create follow-up issue | ||
| id: create-issue | ||
| if: steps.check-merged.outputs.merged == 'true' |
There was a problem hiding this comment.
When no verification comment is found, the extract step calls core.setFailed() but subsequent steps don't check if extraction was successful. They only check if the PR is merged. This means steps 3-5 will attempt to run even when extraction failed, potentially causing errors when trying to access undefined outputs. Consider adding a check for steps.extract.outcome == 'success' to the conditionals of subsequent steps, or use 'return' to exit early without failing the step.
| if: steps.check-merged.outputs.merged == 'true' | |
| if: steps.check-merged.outputs.merged == 'true' && steps.extract.outcome == 'success' |
| with open('../open_issues.json') as f: | ||
| issues_data = json.load(f) |
There was a problem hiding this comment.
The file read operation doesn't include error handling. If the file doesn't exist or contains invalid JSON, the workflow will fail with an unclear error. Consider adding a try-except block with a descriptive error message to make debugging easier.
| with open('../open_issues.json') as f: | |
| issues_data = json.load(f) | |
| try: | |
| with open('../open_issues.json') as f: | |
| issues_data = json.load(f) | |
| except FileNotFoundError: | |
| print('::warning::open_issues.json not found; skipping duplicate detection') | |
| with open(os.environ['GITHUB_OUTPUT'], 'a') as f: | |
| f.write('has_duplicates=false\n') | |
| sys.exit(0) | |
| except json.JSONDecodeError as e: | |
| print(f'::error::Failed to parse open_issues.json as JSON: {e}') | |
| sys.exit(1) |
| tasks = open('../tasks.md').read() | ||
| acceptance = open('../acceptance.md').read() |
There was a problem hiding this comment.
The file read operations don't include error handling. If the files don't exist or contain invalid data, the workflow will fail with an unclear error. Consider adding a try-except block with a descriptive error message to make debugging easier.
| tasks = open('../tasks.md').read() | |
| acceptance = open('../acceptance.md').read() | |
| try: | |
| with open('../tasks.md', 'r', encoding='utf-8') as f: | |
| tasks = f.read() | |
| with open('../acceptance.md', 'r', encoding='utf-8') as f: | |
| acceptance = f.read() | |
| except OSError as e: | |
| print(f'::error::Failed to read input files: {e}') | |
| with open(os.environ['GITHUB_OUTPUT'], 'a') as f: | |
| f.write('check_failed=true\n') | |
| sys.exit(1) |
|
|
||
| permissions: | ||
| contents: read | ||
| issues: write |
There was a problem hiding this comment.
This workflow uses the label_matcher.py script which performs embedding-based similarity matching, but it's missing the 'models: read' permission that other similar workflows (agents-dedup.yml, agents-decompose.yml, agents-capability-check.yml) include. If the embedding provider requires this permission, the workflow may fail. Consider adding 'models: read' to the permissions block for consistency.
| issues: write | |
| issues: write | |
| models: read |
| title: '[Follow-up] Address verification concerns from PR #' + prNumber, | ||
| body: issueBody, | ||
| labels: ['follow-up', 'agents:optimize'] | ||
| }); |
There was a problem hiding this comment.
The JSON.parse call uses a template literal that directly interpolates step outputs without validation. If the step output contains special characters or malformed JSON, this could cause a runtime error. Consider using process.env with proper error handling instead, similar to how other parts of the workflow handle multi-line content.
| with: | ||
| script: | | ||
| const autoApplyLabels = JSON.parse('${{ steps.match.outputs.auto_apply_labels }}'); |
There was a problem hiding this comment.
The JSON.parse call uses a template literal to directly parse step outputs. If the auto_apply_labels output contains special characters or is malformed, this will cause a runtime error. Consider using a safer parsing approach with try-catch error handling or accessing the value through process.env.
| with: | |
| script: | | |
| const autoApplyLabels = JSON.parse('${{ steps.match.outputs.auto_apply_labels }}'); | |
| env: | |
| AUTO_APPLY_LABELS: ${{ steps.match.outputs.auto_apply_labels }} | |
| with: | |
| script: | | |
| let autoApplyLabelsRaw = process.env.AUTO_APPLY_LABELS; | |
| let autoApplyLabels; | |
| try { | |
| autoApplyLabels = JSON.parse(autoApplyLabelsRaw || '[]'); | |
| } catch (error) { | |
| core.setFailed(`Failed to parse AUTO_APPLY_LABELS: ${error}`); | |
| return; | |
| } |
| const suggestedLabels = JSON.parse('${{ steps.match.outputs.suggested_labels }}'); | ||
| const autoApplied = JSON.parse('${{ steps.match.outputs.auto_apply_labels }}'); |
There was a problem hiding this comment.
The JSON.parse call uses a template literal to directly parse step outputs. If the suggested_labels output contains special characters or is malformed, this will cause a runtime error. Consider using a safer parsing approach with try-catch error handling or accessing the value through process.env.
| from scripts.langchain.task_decomposer import decompose_task | ||
|
|
||
| # Read issue context | ||
| context = open('../issue_context.md').read() |
There was a problem hiding this comment.
The file read operation doesn't include error handling. If the file doesn't exist or contains invalid data, the workflow will fail with an unclear error. Consider adding a try-except block with a descriptive error message to make debugging easier.
| context = open('../issue_context.md').read() | |
| try: | |
| with open('../issue_context.md', 'r', encoding='utf-8') as f: | |
| context = f.read() | |
| except Exception as e: | |
| print(f'::error::Failed to read issue context from ../issue_context.md: {e}') | |
| sys.exit(1) |
| with open(os.environ['GITHUB_OUTPUT'], 'a') as f: | ||
| f.write('check_failed=false\n') | ||
| f.write(f'recommendation={result.recommendation}\n') | ||
| f.write(f'blocked_count={len(result.blocked_tasks)}\n') | ||
| f.write(f'partial_count={len(result.partial_tasks)}\n') | ||
| f.write(f'result_json={json.dumps(result_dict)}\n') |
There was a problem hiding this comment.
Writing complex JSON directly to GITHUB_OUTPUT and then parsing it through YAML interpolation could cause issues if the JSON contains special characters that interfere with YAML parsing. Consider using a file-based approach (write to a file, then read from that file) for complex data structures, similar to how duplicates.json and subtasks.md are handled in other workflows.
| with open(os.environ['GITHUB_OUTPUT'], 'a') as f: | |
| f.write('check_failed=false\n') | |
| f.write(f'recommendation={result.recommendation}\n') | |
| f.write(f'blocked_count={len(result.blocked_tasks)}\n') | |
| f.write(f'partial_count={len(result.partial_tasks)}\n') | |
| f.write(f'result_json={json.dumps(result_dict)}\n') | |
| # Write full JSON result to a file to avoid complex JSON in GITHUB_OUTPUT | |
| json_path = os.path.join('..', 'capability_result.json') | |
| with open(json_path, 'w') as json_file: | |
| json.dump(result_dict, json_file) | |
| with open(os.environ['GITHUB_OUTPUT'], 'a') as f: | |
| f.write('check_failed=false\n') | |
| f.write(f'recommendation={result.recommendation}\n') | |
| f.write(f'blocked_count={len(result.blocked_tasks)}\n') | |
| f.write(f'partial_count={len(result.partial_tasks)}\n') | |
| f.write(f'result_json_path={os.path.abspath(json_path)}\n') |
Sync Summary
Files Updated
Files Skipped
Review Checklist
Source: stranske/Workflows
Manifest:
.github/sync-manifest.yml