name: Deep Agents Example on: issue_comment: types: [created] pull_request_review_comment: types: [created] workflow_dispatch: inputs: prompt: description: "Prompt for the agent" required: true # Cancel superseded runs when @deepagents is mentioned multiple times on the same PR/issue concurrency: group: ${{ github.workflow }}-${{ github.event.issue.number || github.event.pull_request.number || github.run_id }} cancel-in-progress: true jobs: deepagents: if: | github.event_name == 'workflow_dispatch' || ( contains(github.event.comment.body, '@deepagents') && ( github.event.comment.author_association == 'OWNER' || github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'COLLABORATOR' ) && ( github.event_name == 'pull_request_review_comment' || github.event.issue.pull_request ) ) runs-on: ubuntu-latest permissions: contents: write issues: write pull-requests: write steps: - name: Resolve PR number if: github.event_name != 'workflow_dispatch' id: pr-info shell: bash env: GH_TOKEN: ${{ github.token }} # issue_comment uses event.issue.number; review_comment uses event.pull_request.number PR_NUMBER: ${{ github.event.issue.number || github.event.pull_request.number }} run: | echo "number=$PR_NUMBER" >> "$GITHUB_OUTPUT" - name: Acknowledge trigger if: github.event_name != 'workflow_dispatch' continue-on-error: true shell: bash env: GH_TOKEN: ${{ github.token }} COMMENT_ID: ${{ github.event.comment.id }} EVENT_NAME: ${{ github.event_name }} REPO: ${{ github.repository }} run: | # issue_comment reactions use issues/comments; review_comment uses pulls/comments if [ "$EVENT_NAME" = "pull_request_review_comment" ]; then API_PATH="repos/${REPO}/pulls/comments/${COMMENT_ID}/reactions" else API_PATH="repos/${REPO}/issues/comments/${COMMENT_ID}/reactions" fi if ! gh api --method POST "$API_PATH" -f content='rocket'; then echo "::warning::Failed to add reaction to comment ${COMMENT_ID} — comment may have been deleted or token may lack permissions" fi - name: Get PR head SHA if: github.event_name != 'workflow_dispatch' id: pr-sha shell: bash env: GH_TOKEN: ${{ github.token }} PR_NUMBER: ${{ steps.pr-info.outputs.number }} run: | PR_DATA=$(gh pr view "$PR_NUMBER" --repo "$GITHUB_REPOSITORY" --json headRefOid,headRefName) PR_SHA=$(echo "$PR_DATA" | jq -r '.headRefOid') PR_BRANCH=$(echo "$PR_DATA" | jq -r '.headRefName') if [ -z "$PR_SHA" ] || [ "$PR_SHA" = "null" ] || [ -z "$PR_BRANCH" ] || [ "$PR_BRANCH" = "null" ]; then echo "::error::Failed to resolve PR head for #${PR_NUMBER}. API response: ${PR_DATA}" exit 1 fi echo "sha=$PR_SHA" >> "$GITHUB_OUTPUT" echo "branch=$PR_BRANCH" >> "$GITHUB_OUTPUT" - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: # Use the PR branch name so the agent can commit and push to the PR directly. ref: ${{ github.event_name != 'workflow_dispatch' && steps.pr-sha.outputs.branch || '' }} - name: Build PR context prompt if: github.event_name != 'workflow_dispatch' id: build-prompt shell: bash env: GH_TOKEN: ${{ github.token }} TRIGGER_COMMENT_BODY: ${{ github.event.comment.body }} TRIGGER_COMMENT_AUTHOR: ${{ github.event.comment.user.login }} PR_NUMBER: ${{ steps.pr-info.outputs.number }} run: | PROMPT_FILE=$(mktemp) GH_STDERR=$(mktemp) trap 'rm -f "$PROMPT_FILE" "$GH_STDERR"' EXIT # Fetch PR data if ! PR_DATA=$(gh pr view "$PR_NUMBER" --json title,body,author,state,headRefName,baseRefName 2>"$GH_STDERR"); then echo "::error::Failed to fetch PR #${PR_NUMBER} data: $(cat "$GH_STDERR"). Check that the PR exists and the token has 'pull-requests: read' permission." exit 1 fi PR_TITLE=$(echo "$PR_DATA" | jq -r '.title // "Untitled"') PR_BODY=$(echo "$PR_DATA" | jq -r '.body // "No description"') PR_AUTHOR=$(echo "$PR_DATA" | jq -r '.author.login // "unknown"') PR_STATE=$(echo "$PR_DATA" | jq -r '.state // "unknown"') PR_HEAD=$(echo "$PR_DATA" | jq -r '.headRefName // "unknown"') PR_BASE=$(echo "$PR_DATA" | jq -r '.baseRefName // "unknown"') # Fetch PR diff stats (first page) if ! DIFF_STAT=$(gh pr diff "$PR_NUMBER" --name-only 2>"$GH_STDERR"); then echo "::warning::Failed to fetch PR diff: $(cat "$GH_STDERR")" DIFF_STAT="[Error fetching diff — see workflow logs]" fi # Fetch PR comments (first 20 — older ones omitted) if ! PR_COMMENTS=$(gh api "repos/$GITHUB_REPOSITORY/issues/$PR_NUMBER/comments?per_page=20" \ --jq '.[] | "\(.body)"' 2>"$GH_STDERR"); then echo "::warning::Failed to fetch PR comments: $(cat "$GH_STDERR")" PR_COMMENTS="[Error fetching comments — see workflow logs]" fi # Fetch PR reviews (first 10) if ! PR_REVIEWS=$(gh api "repos/$GITHUB_REPOSITORY/pulls/$PR_NUMBER/reviews?per_page=10" \ --jq '.[] | "\(.body // "No review body")"' 2>"$GH_STDERR"); then echo "::warning::Failed to fetch PR reviews: $(cat "$GH_STDERR")" PR_REVIEWS="[Error fetching reviews — see workflow logs]" fi # Fetch review comments / inline code comments (first 30) if ! REVIEW_COMMENTS=$(gh api "repos/$GITHUB_REPOSITORY/pulls/$PR_NUMBER/comments?per_page=30" \ --jq '.[] | "\(.body)"' 2>"$GH_STDERR"); then echo "::warning::Failed to fetch review comments: $(cat "$GH_STDERR")" REVIEW_COMMENTS="[Error fetching review comments — see workflow logs]" fi cat > "$PROMPT_FILE" << 'PROMPT_HEADER' The user has tagged @deepagents in a comment on this pull request. Your task is to resolve their request in the simplest way possible. You have shell access with git and gh available. The repository is checked out on the PR branch. Determine whether the comment requires code changes, and if so implement them directly. - Make only the changes requested. Do not make unrelated changes. - Do not leave comments in your code about the request or changes you're making. - Keep changes minimal and focused. If the comment does not require code changes (e.g. a question), respond by creating a comment on the PR with your answer. After making changes, commit them to the current branch. IMPORTANT: When you are finished, you MUST post a brief summary comment on the PR using `gh pr comment`. The comment should: - Briefly describe what you did (1-3 sentences) - List any files changed or commits made - Note if you were unable to complete any part of the request Always post this summary, even if the task was simple or no code changes were needed. PROMPT_HEADER # Write PR context using printf to avoid shell expansion of user-controlled content { printf '\n' printf '%s\n' "$PR_TITLE" printf '%s\n' "$PR_AUTHOR" printf '%s\n' "$PR_STATE" printf '%s\n' "$PR_BASE" printf '%s\n' "$PR_HEAD" printf '\n%s\n\n' "$PR_BODY" printf '\n\n' printf '\n%s\n\n\n' "$DIFF_STAT" printf '\n%s\n\n\n' "$PR_COMMENTS" printf '\n%s\n\n\n' "$PR_REVIEWS" printf '\n%s\n\n\n' "$REVIEW_COMMENTS" printf '\n' printf 'This is the comment that triggered this workflow. Focus on resolving this request.\n' printf '%s\n' "$TRIGGER_COMMENT_AUTHOR" printf '\n%s\n\n' "$TRIGGER_COMMENT_BODY" printf '\n\n' printf 'Given all of this context, resolve the trigger comment in the simplest way possible.\n' printf 'IMPORTANT: The trigger comment takes precedence. Focus on what was asked, using the PR context to inform your approach.\n' } >> "$PROMPT_FILE" # Set output using heredoc with random delimiter DELIMITER="PROMPT_$(openssl rand -hex 16)" { echo "prompt<<${DELIMITER}" cat "$PROMPT_FILE" echo "${DELIMITER}" } >> "$GITHUB_OUTPUT" - name: Run Deep Agents uses: langchain-ai/deepagents@main with: prompt: ${{ github.event_name != 'workflow_dispatch' && steps.build-prompt.outputs.prompt || github.event.inputs.prompt }} model: claude-sonnet-4-6 anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} # Or: openai_api_key: ${{ secrets.OPENAI_API_KEY }} # Or: google_api_key: ${{ secrets.GOOGLE_API_KEY }} skills_repo: langchain-ai/langchain-skills