Files
deepagents/.github/workflows/deepagents-example.yml.example
John Kennedy 37c5be9561 chore(infra): SHA-pin actions/checkout in example workflow (#4293)
## Summary

Pin `actions/checkout@v6` →
`actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1` in
`deepagents-example.yml.example`.

All other workflows and composite actions in the repo were already
SHA-pinned. This completes coverage for every third-party action
reference in `.github/`.

## Why

SHA-pinning third-party GitHub Actions is a supply-chain security best
practice recommended by GitHub and security scanners. Tag-based
references (`@v6`) are mutable — a compromised maintainer account or
stolen token can push malicious code under the same tag. SHA-pinned
references are immutable.

## Notes

The `langchain-ai/deepagents@main` self-reference in the example
template is intentionally left unpinned — it is a template file
(`.example` suffix) for downstream consumers, not a live workflow.

Co-authored-by: Deep Agent <agent@deepagents.dev>
2026-06-25 20:09:09 -04:00

219 lines
9.9 KiB
Plaintext

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 '.[] | "<comment author=\"\(.user.login)\">\(.body)</comment>"' 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 '.[] | "<review author=\"\(.user.login)\" state=\"\(.state)\">\(.body // "No review body")</review>"' 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 '.[] | "<review-comment author=\"\(.user.login)\" path=\"\(.path)\" line=\"\(.line // .original_line)\">\(.body)</review-comment>"' 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'
<instructions>
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.
</instructions>
PROMPT_HEADER
# Write PR context using printf to avoid shell expansion of user-controlled content
{
printf '<pull-request>\n'
printf '<title>%s</title>\n' "$PR_TITLE"
printf '<author>%s</author>\n' "$PR_AUTHOR"
printf '<state>%s</state>\n' "$PR_STATE"
printf '<base>%s</base>\n' "$PR_BASE"
printf '<head>%s</head>\n' "$PR_HEAD"
printf '<body>\n%s\n</body>\n' "$PR_BODY"
printf '</pull-request>\n\n'
printf '<changed-files>\n%s\n</changed-files>\n\n' "$DIFF_STAT"
printf '<pull-request-comments>\n%s\n</pull-request-comments>\n\n' "$PR_COMMENTS"
printf '<pull-request-reviews>\n%s\n</pull-request-reviews>\n\n' "$PR_REVIEWS"
printf '<review-comments>\n%s\n</review-comments>\n\n' "$REVIEW_COMMENTS"
printf '<trigger-comment>\n'
printf 'This is the comment that triggered this workflow. Focus on resolving this request.\n'
printf '<author>%s</author>\n' "$TRIGGER_COMMENT_AUTHOR"
printf '<body>\n%s\n</body>\n' "$TRIGGER_COMMENT_BODY"
printf '</trigger-comment>\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