1- # Engineer Bot — author (bug-fix) .
1+ # Engineer Bot — author.
22#
3- # A maintainer labels a bug-report ISSUE with `engineer-bot`; the bot reproduces
4- # the bug with a failing test, fixes the connector code, and opens a PR. Driven
5- # by the bug-fix flow + this repo's .bot/ (config + prompts).
3+ # A maintainer labels an ISSUE with `engineer-bot`; the bot addresses it and opens
4+ # a PR. The author FLOW is chosen from the issue's TYPE (a GitHub org-level Issue
5+ # Type): `Bug` ⇒ bug-fix (reproduce with a failing test, then fix); `Feature` ⇒
6+ # enhancement (smallest correct change); any other type / none ⇒ the repo's
7+ # .bot/config.yaml `flow:` default. Set the Type BEFORE `engineer-bot` — it's read
8+ # live when the run starts. Driven by the selected flow + this repo's .bot/
9+ # (config + prompts).
610#
711# The engineer builds and runs THIS repo's tests, so it needs the connector's
812# deps installed (via setup-poetry) in addition to the engine. Shared setup
8589 with :
8690 app-id : ${{ secrets.ENGINEER_BOT_APP_ID }}
8791 private-key : ${{ secrets.ENGINEER_BOT_APP_PRIVATE_KEY }}
88- engine-ref : b6205fb502566d617a456ccf3c37f3e4e3072ccd
92+ engine-ref : d24ca2171d191a652a67f4f43995f0959c9a5791
8993
9094 - name : Resolve issue + gather context
9195 id : ctx
@@ -104,40 +108,72 @@ jobs:
104108 run : |
105109 if [ "$EVENT_NAME" = "workflow_dispatch" ]; then RAW="$INPUT_ISSUE"; else RAW="$EVENT_ISSUE"; fi
106110 [[ "$RAW" =~ ^[0-9]+$ ]] || { echo "::error::Invalid issue number '$RAW'"; exit 1; }
107- gh issue view "$RAW" --repo "$REPO" --json number,title,url,body > "$RUNNER_TEMP/issue.json"
111+ # `gh issue view --json` does NOT expose the issue TYPE field, so fetch
112+ # via the REST API (which carries `.type.name`). Body/title/url still
113+ # come from the same JSON. Issue Types are an ORG-level feature; a repo
114+ # without them configured returns `.type == null` (⇒ no --flow ⇒ the
115+ # engine uses the .bot/config.yaml `flow:` default).
116+ gh api "repos/$REPO/issues/$RAW" > "$RUNNER_TEMP/issue.json"
117+ # The REST issues endpoint resolves PR numbers too (PRs are issues in
118+ # the REST model), unlike `gh issue view <pr-number>` which errored.
119+ # Keep rejecting PR numbers cleanly: real issues have `.pull_request == null`.
120+ [ "$(jq -r '.pull_request // "null"' "$RUNNER_TEMP/issue.json")" = "null" ] \
121+ || { echo "::error::#$RAW is a pull request, not an issue"; exit 1; }
108122 jq -r '.body // ""' "$RUNNER_TEMP/issue.json" > "$RUNNER_TEMP/issue_body.txt"
109123 TITLE="$(jq -r '.title // ""' "$RUNNER_TEMP/issue.json")"
110- URL="$(jq -r '.url // ""' "$RUNNER_TEMP/issue.json")"
124+ URL="$(jq -r '.html_url // ""' "$RUNNER_TEMP/issue.json")"
111125 {
112126 echo "ISSUE_NUMBER=$RAW"
113127 echo "ISSUE_URL=$URL"
114128 } >> "$GITHUB_ENV"
115129 echo "issue_number=$RAW" >> "$GITHUB_OUTPUT"
130+ # Derive the author flow from the issue's TYPE (read LIVE here, so a type
131+ # set AFTER this fetch is not seen — set the type BEFORE `engineer-bot`).
132+ # The type→flow MAPPING is pinned (not "use the type name as the flow")
133+ # so an arbitrary custom org type can never select an engine flow:
134+ # Bug ⇒ bug-fix (red→green TDD) Feature ⇒ enhancement (small-change)
135+ # Any other type (incl. Task) or no type ⇒ emit nothing ⇒ the author
136+ # step omits --flow ⇒ the engine uses .bot/config.yaml `flow:`.
137+ TYPE="$(jq -r '.type.name // ""' "$RUNNER_TEMP/issue.json")"
138+ case "$TYPE" in
139+ Bug) echo "flow=bug-fix" >> "$GITHUB_OUTPUT" ;;
140+ Feature) echo "flow=enhancement" >> "$GITHUB_OUTPUT" ;;
141+ esac
116142 DELIM="GHEOF_$(date +%s%N)${RANDOM}"
117143 if printf '%s' "$TITLE" | grep -qF "$DELIM"; then
118144 echo "::error::title delimiter collision — refusing to write \$GITHUB_ENV"; exit 1
119145 fi
120146 { echo "ISSUE_TITLE<<$DELIM"; printf '%s\n' "$TITLE"; echo "$DELIM"; } >> "$GITHUB_ENV"
121147
122- - name : Run author (bug-fix)
148+ - name : Run author
123149 id : author
124150 # Run from RUNNER_TEMP so the engine-rendered prompt's context file
125151 # (issue_body.txt, resolved against cwd) is read from there and the
126152 # checkout stays clean — publish's leftover check fails on any untracked
127153 # path in the repo. TEST_REPO_ROOT points the agent's working tree (and
128154 # the .bot/ lookup) at the checkout; ISSUE_NUMBER/TITLE/URL come from
129- # $GITHUB_ENV (the bot config's author.env_tokens). Flow comes from
130- # .bot/config.yaml (`flow: bug-fix`), so no --flow is passed.
155+ # $GITHUB_ENV (the bot config's author.env_tokens).
156+ #
157+ # The author FLOW is chosen from the issue TYPE by the ctx step above
158+ # (Bug ⇒ bug-fix, Feature ⇒ enhancement). We pass --flow ONLY when that
159+ # step derived one: an empty --flow would be rejected by the CLI's
160+ # `choices`, and omitting it lets the engine fall back to the
161+ # .bot/config.yaml `flow:` default (no/other type, or type-set-late case).
131162 working-directory : ${{ runner.temp }}
132163 env :
133164 MODEL_ENDPOINT : https://${{ secrets.DATABRICKS_HOST }}/serving-endpoints/databricks-claude-opus-4-8/invocations
134165 DATABRICKS_TOKEN : ${{ secrets.DATABRICKS_TOKEN }}
135166 TEST_REPO_ROOT : ${{ github.workspace }}
136167 RUNNER_TEMP : ${{ runner.temp }}
137- run : >-
138- python -m databricks_bot_engine.engineer_bot.run --phase author
139- --system-prompt "$GITHUB_WORKSPACE/.bot/prompts/engineer/system.md"
140- --user-prompt "$GITHUB_WORKSPACE/.bot/prompts/engineer/user.md"
168+ FLOW : ${{ steps.ctx.outputs.flow }}
169+ run : |
170+ args=(
171+ --phase author
172+ --system-prompt "$GITHUB_WORKSPACE/.bot/prompts/engineer/system.md"
173+ --user-prompt "$GITHUB_WORKSPACE/.bot/prompts/engineer/user.md"
174+ )
175+ [ -n "$FLOW" ] && args+=(--flow "$FLOW")
176+ python -m databricks_bot_engine.engineer_bot.run "${args[@]}"
141177
142178 - name : Open / update fix PR
143179 id : publish
0 commit comments