feat: PM-Agent also need to look at PR comments
From Gitea issue #116. Authored by the PM agent's worker; the merge gate is the approver. Refs #116. Agent: pm-agent (issue #116, mode revise)
This commit is contained in:
1 parent
2fdb95393c
commit
e8e9de8611
7 files changed
+471
-189
No files matched your search
+45
-16
@@ -169,16 +169,17 @@ the live Gitea — see `decisions/2026-11-07-pm-agent-pr-mentions.md`.
|
||||
With it on, the dispatcher runs a second, independent pass each poll. A mention of the bot
|
||||
account on a **pull request** makes the PM read that pull request — its description, its
|
||||
changed files, its diff, the thread it was mentioned in and the rest of the conversation —
|
||||
and **reply in that same thread**. Both places count: the pull request's conversation, and
|
||||
inline review threads against a file and a line.
|
||||
and **reply where it was mentioned**. Three places count: the pull request's conversation, a
|
||||
review's own body (Gitea renders it in the conversation, so the reply goes there), and an
|
||||
inline review comment against a file and a line.
|
||||
|
||||
```
|
||||
@pm-agent in a PR comment ─▶ discover (notifications, else open PRs)
|
||||
or an inline review thread │
|
||||
├─▶ read /issues/{n}/comments, /pulls/{n}/reviews,
|
||||
or in a review body │
|
||||
or on a line inline ├─▶ read /issues/{n}/comments, /pulls/{n}/reviews,
|
||||
│ .../reviews/{id}/comments
|
||||
├─▶ decide: self-authored? already answered? mentioned,
|
||||
│ or a follow-up in an already-mentioned thread?
|
||||
├─▶ decide, per comment: self-authored? already
|
||||
│ answered? does it name the bot?
|
||||
├─▶ assemble the PR + diff + thread, every field fenced
|
||||
│ and labelled UNTRUSTED
|
||||
├─▶ ask the model: `comment` or `decline`, and nothing else
|
||||
@@ -191,13 +192,37 @@ ask for work in a shape this program would accept. Nothing on the path calls `bu
|
||||
The change-authoring half of issue #116 — revise a branch an agent owns, versus open a fresh
|
||||
branch and PR against `main` for somebody else's — is a separate issue and a separate PR.
|
||||
|
||||
**"The same thread."** Inline review comments have a thread identity in Gitea (comments on
|
||||
the same file and diff position are one conversation). Pull-request conversation comments do
|
||||
not — they are a flat list — so the issue path's existing convention is reused: the
|
||||
conversation is **one** thread, and from the first mention in a thread onward, every later
|
||||
non-bot comment in it continues the conversation without a new mention. A comment made
|
||||
*before* the mention is not pulled in, and continuation is per thread, not per pull request.
|
||||
That is a policy choice, not a Gitea fact; it is flagged on issue #116.
|
||||
**An explicit mention is the only trigger.** A comment is answered if and only if it is not
|
||||
the bot's own, it spells out `@`-the-bot-account, and no earlier reply of the bot's says it
|
||||
was already answered. Nothing else is actionable: a comment with no mention produces **no
|
||||
reply and no model call**, however recently the bot was mentioned or replied nearby. So a
|
||||
mention is a discrete, self-limiting request — one `@` gets one reply in the place it was
|
||||
written, and the rest of the pull request is read as *context* rather than as a queue of
|
||||
questions.
|
||||
|
||||
That is the operator's decision on issue #116, taken once it was established that pull-request
|
||||
conversation comments are a flat list rather than a hierarchy: *"since there is no threads and
|
||||
the PR comments are flat, then the pm-agent should be looking for explicit mentions rather than
|
||||
a single mention and continued scrapping of comments within the PR in perpetuity"*. It replaced
|
||||
an earlier rule where the first mention in a thread armed replies to every later non-bot
|
||||
comment in it. It is applied uniformly, including to inline review comments — those *are*
|
||||
genuinely threaded in Gitea, but keeping continuation for them alone would be a second rule
|
||||
nobody asked for. The fixtures that used to assert continuation are **inverted, not deleted**,
|
||||
so the old behaviour cannot creep back unnoticed.
|
||||
|
||||
Two practical consequences. A mention is **repeatable**: ask again by tagging again, and each
|
||||
tag gets its own reply. And a mention is **not a conversation** — the PM is told to answer as
|
||||
if it is the last word it will see, and to ask you to tag it again if it needs something back.
|
||||
|
||||
What remains, unavoidably, is that *anyone* who writes the handle gets a reply — the operator's
|
||||
answer (3) is "anyone can talk and have the agent work" — and Gitea cannot tell a quoted
|
||||
mention (`> @pm-agent what do you think?`) from a fresh one, so re-quoting an old mention in a
|
||||
new comment costs one more reply.
|
||||
|
||||
**Thread identity is now only about where the reply goes.** Inline review comments are grouped
|
||||
by (path, position), which is Gitea's own grouping and is what makes the reply land in the
|
||||
thread that was spoken to rather than beside it; conversation comments and review bodies are
|
||||
answered in the conversation. None of that is part of the trigger any more.
|
||||
|
||||
**Loop prevention.** There is no author gate — anyone who can comment can start a run, which
|
||||
is the operator's decision (issue #116, answer 3: *"anyone can talk and have the agent work.
|
||||
@@ -223,9 +248,13 @@ bot's *own* comments — pasting it into yours does not silence a mention.
|
||||
|
||||
The operator asked for "a way to check for '@'s for the bot account instead of scouring the
|
||||
entire pull request list and associated threads". That is Gitea's notification list: a
|
||||
mention subscribes the mentioned account to the thread, and the subscription then raises a
|
||||
notification for **every later comment on it** — which answers discovery and thread
|
||||
continuation with one bounded call.
|
||||
mention subscribes the mentioned account to the thread, so one bounded call names the pull
|
||||
requests worth reading.
|
||||
|
||||
It is a **hint, never the decision** — the trigger is re-derived by reading that pull
|
||||
request's comments. That split is why the endpoint over-delivering is harmless: the
|
||||
subscription keeps raising notifications for later comments on a pull request the bot was
|
||||
once mentioned on, and since those comments carry no mention, they resolve to nothing.
|
||||
|
||||
**It will be refused on today's token.** `/api/v1/notifications` sits behind Gitea's
|
||||
`notification` scope category, and the bot's token is minted
|
||||
|
||||
@@ -131,11 +131,16 @@ data:
|
||||
|
||||
# --- mentions on a pull request (issue #116) --------------------------------
|
||||
# OFF. Turning it on makes the dispatcher also look at PULL REQUESTS: a mention of the bot
|
||||
# account in a pull request's conversation, or inside an inline review thread, makes the PM
|
||||
# read that pull request and reply in that same thread, and follow-up comments in a thread
|
||||
# that already holds a mention continue the conversation with no new mention. It can ONLY
|
||||
# reply — a mention cannot start, revise or push a branch; that is the second half of
|
||||
# issue #116 and has its own issue.
|
||||
# account in a pull request's conversation, in a review's body, or on a line inside an
|
||||
# inline review thread, makes the PM read that pull request and reply where it was
|
||||
# mentioned. It can ONLY reply — a mention cannot start, revise or push a branch; that is
|
||||
# the second half of issue #116 and has its own issue.
|
||||
#
|
||||
# AN EXPLICIT MENTION IS THE ONLY TRIGGER, and a mention is self-limiting: one `@` gets one
|
||||
# reply, and no other comment on the pull request is picked up. A comment that does not
|
||||
# name the bot costs nothing — no reply and no model call — however recently the bot was
|
||||
# mentioned or replied nearby. So the spend on this path is bounded by how often somebody
|
||||
# types the handle, not by how busy the pull request is.
|
||||
#
|
||||
# WHY IT SHIPS OFF. Not one call on this path has been made against the live Gitea — the
|
||||
# branch that wrote it held no Gitea credential and no cluster — and the cheap mention
|
||||
@@ -178,8 +183,8 @@ data:
|
||||
# Plan mode for the pull-request path: discover, assemble the payload, PRINT it to the
|
||||
# dispatcher's stdout, ask no model and post nothing. Setting it also enables the path, so
|
||||
# it is one knob to look before leaping. PM_DRY_RUN above implies it, because on this path
|
||||
# the posted reply IS the action under test and also the marker that changes future
|
||||
# behaviour — posting it would make a dry run not dry.
|
||||
# the posted reply IS the action under test, and it also carries the idempotency marker —
|
||||
# posting it would make a dry run not dry.
|
||||
PM_PLAN: "false"
|
||||
|
||||
# If the gate refuses a worker's change, the branch is NOT pushed by default and the issue
|
||||
|
||||
Reference in new issue
Block a user