Skip to content
This repository was archived by the owner on Jun 3, 2026. It is now read-only.

Task 3.3: Implement Tool Result Status Auto-Detection for BedrockModelProvider #38

Task 3.3: Implement Tool Result Status Auto-Detection for BedrockModelProvider

Task 3.3: Implement Tool Result Status Auto-Detection for BedrockModelProvider #38

name: Strands Command Handler
on:
issue_comment:
types: [created]
workflow_dispatch:
inputs:
issue_id:
description: 'Issue ID to process (can be issue or PR number)'
required: true
type: string
command:
description: 'Strands command to execute'
required: false
type: string
default: ''
jobs:
authorization-check:
if: startsWith(github.event.comment.body, '/strands') || github.event_name == 'workflow_dispatch'
permissions: read-all
runs-on: ubuntu-latest
outputs:
approval-env: ${{ steps.collab-check.outputs.result || steps.auto-approve.outputs.result }}
steps:
- name: Collaborator Check
if: github.event_name != 'workflow_dispatch'
uses: actions/github-script@v8
id: collab-check
with:
result-encoding: string
script: |
try {
const permissionResponse = await github.rest.repos.getCollaboratorPermissionLevel({
owner: context.repo.owner,
repo: context.repo.repo,
username: context.payload.comment.user.login,
});
const permission = permissionResponse.data.permission;
const hasWriteAccess = ['write', 'admin'].includes(permission);
if (!hasWriteAccess) {
console.log(`User ${context.payload.comment.user.login} does not have write access to the repository (permission: ${permission})`);
return "manual-approval"
} else {
console.log(`Verified ${context.payload.comment.user.login} has write access. Auto Approving strands command.`)
return "auto-approve"
}
} catch (error) {
console.log(`${context.payload.comment.user.login} does not have write access. Requiring Manual Approval to run strands command.`)
return "manual-approval"
}
- name: Auto-approve for workflow dispatch
if: github.event_name == 'workflow_dispatch'
id: auto-approve
uses: actions/github-script@v8
with:
result-encoding: string
script: |
return "auto-approve"
execute:
needs: [authorization-check]
environment: ${{ needs.authorization-check.outputs.approval-env }}
permissions:
contents: write
issues: write
pull-requests: write
id-token: write # Required for OIDC
runs-on: ubuntu-latest
steps:
- name: Add strands-running label
uses: actions/github-script@v8
with:
script: |
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: ${{ inputs.issue_id || github.event.issue.number }},
labels: ['strands-running']
});
- name: Determine PR context
id: determine-context
uses: actions/github-script@v7
with:
script: |
try {
const issueId = context.eventName === 'workflow_dispatch'
? '${{ inputs.issue_id }}'
: context.payload.issue.number.toString();
const command = context.eventName === 'workflow_dispatch'
? '${{ inputs.command }}'
: (context.payload.comment.body.match(/^\/strands\s*(.*)$/)?.[1]?.trim() || '');
console.log(`Event: ${context.eventName}, Issue ID: ${issueId}, Command: "${command}"`);
const issue = await github.rest.issues.get({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueId
});
const isPrContext = !!issue.data.pull_request;
const mode = (isPrContext || command.startsWith('implement')) ? 'implementer' : 'reviewer';
console.log(`Is PR: ${isPrContext}, Mode: ${mode}`);
let targetIssueId;
if (!isPrContext) {
targetIssueId = issueId;
console.log(`Target issue ID: ${targetIssueId} (same as issue)`);
} else {
const closingIssuesData = await github.graphql(`
query($owner: String!, $repo: String!, $number: Int!) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $number) {
closingIssuesReferences(first: 10) {
nodes { number }
}
}
}
}
`, {
owner: context.repo.owner,
repo: context.repo.repo,
number: parseInt(issueId)
});
const issues = closingIssuesData?.repository?.pullRequest?.closingIssuesReferences?.nodes || [];
console.log(`Found ${issues.length} closing issue(s)`);
if (issues.length !== 1) {
const errorMsg = issues.length > 1
? `Pull request has ${issues.length} closing issues. Only one closing issue is allowed.`
: 'Pull request must have exactly one closing issue.';
console.error(errorMsg);
core.setFailed(errorMsg);
return;
}
targetIssueId = issues[0].number.toString();
console.log(`Target issue ID: ${targetIssueId} (from closing issues)`);
}
console.log(`Setting outputs - issue_id: ${issueId}, target_issue_id: ${targetIssueId}, pr_id: ${isPrContext ? issueId : ''}, mode: ${mode}`);
core.setOutput('issue_id', issueId);
core.setOutput('target_issue_id', targetIssueId);
core.setOutput('pr_id', isPrContext ? issueId : '');
core.setOutput('mode', mode);
core.setOutput('command', command);
} catch (error) {
const errorMsg = `Failed to determine context: ${error.message}`;
console.error(errorMsg);
core.setFailed(errorMsg);
}
- name: Checkout repository
uses: actions/checkout@v4
with:
ref: ${{ steps.determine-context.outputs.pr_id && format('refs/pull/{0}/head', steps.determine-context.outputs.pr_id) || 'main' }}
- name: Build prompts
id: process
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
try {
const mode = '${{ steps.determine-context.outputs.mode }}';
const targetIssueId = '${{ steps.determine-context.outputs.target_issue_id }}';
const issueId = '${{ steps.determine-context.outputs.issue_id }}';
const command = '${{ steps.determine-context.outputs.command }}';
const isPrContext = '${{ steps.determine-context.outputs.pr_id }}' !== '';
console.log(`Building prompts - mode: ${mode}, target issue: ${targetIssueId}, is PR: ${isPrContext}`);
const sessionId = `${mode}-${targetIssueId}`;
console.log(`Session ID: ${sessionId}`);
const scriptFile = mode === 'implementer'
? '.github/agent-scripts/task-implementer.script.md'
: '.github/agent-scripts/task-reviewer.script.md';
console.log(`Reading script file: ${scriptFile}`);
let systemPrompt = fs.readFileSync(scriptFile, 'utf8');
systemPrompt = systemPrompt
.replace(/\{\{ISSUE_NUMBER\}\}/g, targetIssueId);
const first20Lines = systemPrompt.split('\n').slice(0, 20).join('\n');
console.log(`System prompt (first 20 lines):\n${first20Lines}`);
let prompt = '';
if (isPrContext) prompt += `The pull request id is: ${issueId}\n`;
prompt += `${command}\n`;
prompt += 'review and continue';
console.log(`Task prompt: "${prompt}"`);
core.setOutput('session_id', sessionId);
core.setOutput('system_prompt', systemPrompt);
core.setOutput('prompt', prompt);
} catch (error) {
const errorMsg = `Failed to build prompts: ${error.message}`;
console.error(errorMsg);
core.setFailed(errorMsg);
}
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '20'
- name: Install dependencies
run: npm install
- name: Execute strands command
uses: strands-agents/strands-action@main
timeout-minutes: 60
with:
aws_role_arn: ${{ secrets.AWS_ROLE_ARN }}
system_prompt: ${{ steps.process.outputs.system_prompt }}
session_id: ${{ steps.process.outputs.session_id }}
session_s3_bucket: ${{ secrets.TYPESCRIPT_SESSIONS_BUCKET }}
thinking_type: "enabled"
budget_tokens: "8000"
model: "global.anthropic.claude-sonnet-4-5-20250929-v1:0"
anthropic_beta: "interleaved-thinking-2025-05-14"
max_tokens: "64000"
tools: "str_replace_based_edit_tool,shell,http_request,create_issue,get_issue,update_issue,list_issues,add_issue_comment,get_issue_comments,create_pull_request,get_pull_request,update_pull_request,list_pull_requests,get_pr_review_and_comments,reply_to_review_comment,notebook,handoff_to_user"
task: ${{ steps.process.outputs.prompt }}
- name: Remove strands-running label
if: always()
uses: actions/github-script@v8
with:
script: |
try {
await github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: ${{ inputs.issue_id || github.event.issue.number }},
name: 'strands-running'
});
} catch (error) {
console.log('Label removal failed (may not exist):', error.message);
}