From 56ac0ae41709ab9da29661751bb0f4eb533d6c28 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Thu, 25 Dec 2025 06:39:05 +0900 Subject: [PATCH] add agent --- .github/workflows/sisyphus-agent.yml | 280 +++++++++++++++++++++++++++ 1 file changed, 280 insertions(+) create mode 100644 .github/workflows/sisyphus-agent.yml diff --git a/.github/workflows/sisyphus-agent.yml b/.github/workflows/sisyphus-agent.yml new file mode 100644 index 0000000..e87142b --- /dev/null +++ b/.github/workflows/sisyphus-agent.yml @@ -0,0 +1,280 @@ +name: Sisyphus Agent + +on: + workflow_dispatch: + inputs: + prompt: + description: "Custom prompt" + required: false + issue_comment: + types: [created] + pull_request_review: + types: [submitted] + pull_request_review_comment: + types: [created] + +jobs: + agent: + runs-on: ubuntu-latest + # @sisyphus-dev-ai mention only (maintainers, exclude self) + if: | + github.event_name == 'workflow_dispatch' || + (contains(github.event.comment.body || github.event.review.body, '@sisyphus-dev-ai') && + (github.event.comment.user.login || github.event.review.user.login) != 'sisyphus-dev-ai' && + contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association || github.event.review.author_association)) + + # Minimal default GITHUB_TOKEN permissions + permissions: + contents: read + + steps: + # Checkout with sisyphus-dev-ai's PAT + - uses: actions/checkout@v5 + with: + token: ${{ secrets.GH_PAT }} + fetch-depth: 0 + + # Git config - commits as sisyphus-dev-ai + - name: Configure Git as sisyphus-dev-ai + run: | + git config user.name "sisyphus-dev-ai" + git config user.email "sisyphus-dev-ai@users.noreply.github.com" + + # gh CLI auth as sisyphus-dev-ai + - name: Authenticate gh CLI as sisyphus-dev-ai + run: | + echo "${{ secrets.GH_PAT }}" | gh auth login --with-token + gh auth status + + - name: Ensure tmux is available (Linux) + if: runner.os == 'Linux' + run: | + set -euo pipefail + if ! command -v tmux >/dev/null 2>&1; then + sudo apt-get update + sudo apt-get install -y --no-install-recommends tmux + fi + tmux -V + + - name: Setup Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version: latest + + - name: Cache Bun dependencies + uses: actions/cache@v4 + with: + path: | + ~/.bun/install/cache + node_modules + key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }} + restore-keys: | + ${{ runner.os }}-bun- + + # Install OpenCode + oh-my-opencode + auth in single step + - name: Setup OpenCode with oh-my-opencode + env: + OPENCODE_AUTH_JSON: ${{ secrets.OPENCODE_AUTH_JSON }} + ANTHROPIC_BASE_URL: ${{ secrets.ANTHROPIC_BASE_URL }} + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + run: | + export PATH="$HOME/.opencode/bin:$PATH" + + # Install OpenCode (skip if cached) + if ! command -v opencode &>/dev/null; then + for i in 1 2 3; do + echo "Attempt $i: Installing OpenCode..." + curl -fsSL https://opencode.ai/install -o /tmp/opencode-install.sh + if file /tmp/opencode-install.sh | grep -q "shell script\|text"; then + bash /tmp/opencode-install.sh && break + fi + echo "Download corrupted, retrying in 5s..." + sleep 5 + done + fi + opencode --version + + bunx oh-my-opencode install --no-tui --claude=max20 --chatgpt=no --gemini=no + + OPENCODE_JSON=~/.config/opencode/opencode.json + jq --arg baseURL "$ANTHROPIC_BASE_URL" --arg apiKey "$ANTHROPIC_API_KEY" ' + .provider.anthropic = { + "name": "Anthropic", + "npm": "@ai-sdk/anthropic", + "options": { + "baseURL": $baseURL, + "apiKey": $apiKey + }, + "models": { + "claude-opus-4-5": { + "id": "claude-opus-4-5-20251101", + "name": "Opus 4.5", + "limit": { "context": 200000, "output": 64000 }, + "options": { "effort": "high" } + }, + "claude-opus-4-5-high": { + "id": "claude-opus-4-5-20251101", + "name": "Opus 4.5 High", + "limit": { "context": 200000, "output": 128000 }, + "options": { "effort": "high", "thinking": { "type": "enabled", "budgetTokens": 64000 } } + }, + "claude-sonnet-4-5": { + "id": "claude-sonnet-4-5-20250929", + "name": "Sonnet 4.5", + "limit": { "context": 200000, "output": 64000 } + }, + "claude-sonnet-4-5-high": { + "id": "claude-sonnet-4-5-20250929", + "name": "Sonnet 4.5 High", + "limit": { "context": 200000, "output": 128000 }, + "options": { "thinking": { "type": "enabled", "budgetTokens": 64000 } } + }, + "claude-haiku-4-5": { + "id": "claude-haiku-4-5-20251001", + "name": "Haiku 4.5", + "limit": { "context": 200000, "output": 64000 } + } + } + } + ' "$OPENCODE_JSON" > /tmp/oc.json && mv /tmp/oc.json "$OPENCODE_JSON" + + OMO_JSON=~/.config/opencode/oh-my-opencode.json + PROMPT_APPEND=$(cat << 'PROMPT_EOF' + + ## GitHub Actions Environment + + You are `sisyphus-dev-ai` in GitHub Actions. + + ### CRITICAL: GitHub Comments = Your ONLY Output + + User CANNOT see console. Post everything via `gh issue comment` or `gh pr comment`. + + ### Rules + - EVERY response = GitHub comment + - Code changes = PR (never push main/master) + - Setup: bun install first + - Acknowledge immediately, report when done + + ### Git Config + - user.name: sisyphus-dev-ai + - user.email: sisyphus-dev-ai@users.noreply.github.com + PROMPT_EOF + ) + jq --arg append "$PROMPT_APPEND" '.agents.Sisyphus.prompt_append = $append' "$OMO_JSON" > /tmp/omo.json && mv /tmp/omo.json "$OMO_JSON" + + mkdir -p ~/.local/share/opencode + echo "$OPENCODE_AUTH_JSON" > ~/.local/share/opencode/auth.json + chmod 600 ~/.local/share/opencode/auth.json + + cat "$OPENCODE_JSON" + + # Collect context + - name: Collect Context + id: context + env: + GITHUB_TOKEN: ${{ secrets.GH_PAT }} + run: | + EVENT="${{ github.event_name }}" + + if [[ "$EVENT" == "issue_comment" ]]; then + ISSUE_NUM="${{ github.event.issue.number }}" + COMMENT="${{ github.event.comment.body }}" + AUTHOR="${{ github.event.comment.user.login }}" + COMMENT_ID="${{ github.event.comment.id }}" + + # Check if PR or Issue + if gh api "repos/${{ github.repository }}/issues/${ISSUE_NUM}" | jq -e '.pull_request' > /dev/null; then + echo "type=pr" >> $GITHUB_OUTPUT + echo "number=${ISSUE_NUM}" >> $GITHUB_OUTPUT + else + echo "type=issue" >> $GITHUB_OUTPUT + echo "number=${ISSUE_NUM}" >> $GITHUB_OUTPUT + fi + elif [[ "$EVENT" == "pull_request_review_comment" ]]; then + echo "type=pr" >> $GITHUB_OUTPUT + echo "number=${{ github.event.pull_request.number }}" >> $GITHUB_OUTPUT + COMMENT="${{ github.event.comment.body }}" + AUTHOR="${{ github.event.comment.user.login }}" + COMMENT_ID="${{ github.event.comment.id }}" + elif [[ "$EVENT" == "pull_request_review" ]]; then + echo "type=pr" >> $GITHUB_OUTPUT + echo "number=${{ github.event.pull_request.number }}" >> $GITHUB_OUTPUT + COMMENT="${{ github.event.review.body }}" + AUTHOR="${{ github.event.review.user.login }}" + COMMENT_ID="" + fi + + echo "comment<> $GITHUB_OUTPUT + echo "$COMMENT" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + echo "author=$AUTHOR" >> $GITHUB_OUTPUT + echo "comment_id=$COMMENT_ID" >> $GITHUB_OUTPUT + + # Add :eyes: reaction (as sisyphus-dev-ai) + - name: Add eyes reaction + if: steps.context.outputs.comment_id != '' + env: + GITHUB_TOKEN: ${{ secrets.GH_PAT }} + run: | + gh api "/repos/${{ github.repository }}/issues/comments/${{ steps.context.outputs.comment_id }}/reactions" \ + -X POST -f content="eyes" || true + + - name: Run OpenCode + env: + GITHUB_TOKEN: ${{ secrets.GH_PAT }} + run: | + export PATH="$HOME/.opencode/bin:$PATH" + + PROMPT=" + Your username is @sisyphus-dev-ai, mentioned by @${{ steps.context.outputs.author }} in ${{ github.repository }}. + + ## Context + - Type: ${{ steps.context.outputs.type }} + - Number: #${{ steps.context.outputs.number }} + - Repository: ${{ github.repository }} + - Default Branch: ${{ github.event.repository.default_branch }} + + ## User's Request + ${{ steps.context.outputs.comment }} + + --- + + First, acknowledge with \`gh issue comment ${{ steps.context.outputs.number }} --body \"👋 Hey @${{ steps.context.outputs.author }}! I'm on it...\"\` + + Then write everything using the todo tools. + Then investigate and satisfy the request. Only if user requested to you to work explicitely, then use plan agent to plan, todo obsessivley then create a PR to \`${{ github.event.repository.default_branch }}\` branch." + + opencode run "$PROMPT" + + # Push changes (as sisyphus-dev-ai) + - name: Push changes + if: always() + env: + GITHUB_TOKEN: ${{ secrets.GH_PAT }} + run: | + if [[ -n "$(git status --porcelain)" ]]; then + git add -A + git commit -m "chore: changes by sisyphus-dev-ai" || true + fi + + BRANCH=$(git branch --show-current) + if [[ "$BRANCH" != "main" && "$BRANCH" != "master" ]]; then + git push origin "$BRANCH" || true + fi + + # Remove :eyes:, add :+1: + - name: Update reaction + if: always() && steps.context.outputs.comment_id != '' + env: + GITHUB_TOKEN: ${{ secrets.GH_PAT }} + run: | + # Remove eyes + REACTION_ID=$(gh api "/repos/${{ github.repository }}/issues/comments/${{ steps.context.outputs.comment_id }}/reactions" \ + --jq '.[] | select(.content == "eyes" and .user.login == "sisyphus-dev-ai") | .id' | head -1) + if [[ -n "$REACTION_ID" ]]; then + gh api -X DELETE "/repos/${{ github.repository }}/reactions/${REACTION_ID}" || true + fi + + # Add thumbs up + gh api "/repos/${{ github.repository }}/issues/comments/${{ steps.context.outputs.comment_id }}/reactions" \ + -X POST -f content="+1" || true