Use labels in triage: a label-listing tool and a labeling triage turn #260

Merged
lucas merged 1 commit from agent/issue-232-label-tools into main 2026-11-11 11:39:38 +01:00
Collaborator

Closes: #232

What changed

forgejo_list_labels (new, read-only, no parameters). Lists the repository's labels plus the owning organisation's, with their descriptions. Org labels are marked [org]; labels that steer the repository's automation are marked [automation], followed by a line explaining that setting those is refused in unattended sessions. When .omp/forgejo.yaml cannot be read the marks fall back to Status/Blocked + the agent/ namespace and the output says so. An agent no longer has to learn the vocabulary from a failing update call, and can see what is off-limits before being denied.

To carry this, fetchAvailableLabels stops narrowing every label to { id, name } and keeps description plus where the label came from; its error handling and de-duplication are unchanged, and the LabelRef-taking helpers are unaffected.

One definition of "automation label". The protected-name derivation moved out of protectedLabelDenial into repo-config.ts as automationLabelNames / isAutomationLabel, so the tool's marks and the policy's denials read the same list. The existing denial message for forgejo_update_issue_labels is byte-identical.

forgejo_create_issue is covered by the rule. Both the conversation and the pull-request policy ran it through an unconditional allow, so an automation label could reach the repository on a new issue. It now goes through the same check, denied with …; create the issue without it. The pull-request policy's decide became async for this.

Default triage labels. Without an issue_handler.prompt the seed told the agent "Do not change labels or anything else", contradicting the same session's system context. It now says to list the labels and apply the ones that fit. The custom-prompt branch is untouched.

The pull-request policy stops advertising a tool it always refused. forgejo_update_issue_labels was spread in from CONVERSATION_TOOL_NAMES but had no rule in decide, so every call fell through to an unattended deny. It is filtered out of that policy's tool list.

No new config keys, no protocol or web changes (the generic Forgejo tool view already renders a parameterless read tool).

Verification

Rebased onto main at 1f40644 (which brought the swapLabels fix and the comment edit/delete tools; the conflicts were the changelog, the trigger-tools doc bullet and the tool-count assertions, now 27).

  • bun run typecheck — clean.
  • bun test — 1649 pass, 0 fail.

New tests: formatLabelList (marks, org/description rendering, the unreadable-config fallback line, the empty case) and policy tests for the forgejo_create_issue label check and the three tool lists. The existing protected-label expectations are left unchanged as the regression check on the refactor.

Closes: #232 ## What changed **`forgejo_list_labels` (new, read-only, no parameters).** Lists the repository's labels plus the owning organisation's, with their descriptions. Org labels are marked `[org]`; labels that steer the repository's automation are marked `[automation]`, followed by a line explaining that setting those is refused in unattended sessions. When `.omp/forgejo.yaml` cannot be read the marks fall back to `Status/Blocked` + the `agent/` namespace and the output says so. An agent no longer has to learn the vocabulary from a failing update call, and can see what is off-limits *before* being denied. To carry this, `fetchAvailableLabels` stops narrowing every label to `{ id, name }` and keeps `description` plus where the label came from; its error handling and de-duplication are unchanged, and the `LabelRef`-taking helpers are unaffected. **One definition of "automation label".** The protected-name derivation moved out of `protectedLabelDenial` into `repo-config.ts` as `automationLabelNames` / `isAutomationLabel`, so the tool's marks and the policy's denials read the same list. The existing denial message for `forgejo_update_issue_labels` is byte-identical. **`forgejo_create_issue` is covered by the rule.** Both the conversation and the pull-request policy ran it through an unconditional allow, so an automation label could reach the repository on a new issue. It now goes through the same check, denied with `…; create the issue without it`. The pull-request policy's `decide` became async for this. **Default triage labels.** Without an `issue_handler.prompt` the seed told the agent "Do not change labels or anything else", contradicting the same session's system context. It now says to list the labels and apply the ones that fit. The custom-prompt branch is untouched. **The pull-request policy stops advertising a tool it always refused.** `forgejo_update_issue_labels` was spread in from `CONVERSATION_TOOL_NAMES` but had no rule in `decide`, so every call fell through to an unattended deny. It is filtered out of that policy's tool list. No new config keys, no protocol or web changes (the generic Forgejo tool view already renders a parameterless read tool). ## Verification Rebased onto `main` at `1f40644` (which brought the `swapLabels` fix and the comment edit/delete tools; the conflicts were the changelog, the trigger-tools doc bullet and the tool-count assertions, now 27). - `bun run typecheck` — clean. - `bun test` — 1649 pass, 0 fail. New tests: `formatLabelList` (marks, org/description rendering, the unreadable-config fallback line, the empty case) and policy tests for the `forgejo_create_issue` label check and the three tool lists. The existing protected-label expectations are left unchanged as the regression check on the refactor.
An agent could set labels but never see them: the only way to learn a
valid name was a failing update call, and nothing told it which labels
are off-limits before the denial. `forgejo_list_labels` lists the repo's
and the owning org's labels with descriptions, marking org labels
`[org]` and the ones that steer the repository's automation
`[automation]`.

The protected-name derivation moves into repo-config as
`isAutomationLabel`, so the tool's marks and the policy's denials cannot
drift apart, and the rule now also covers `forgejo_create_issue`: an
automation label can no longer reach the repository on a freshly created
issue.

Default triage labels. Without an `issue_handler.prompt` the turn used
to be told to leave labels alone, contradicting its own system context;
it now lists the labels and applies the ones that fit. Repositories with
a custom prompt keep steering themselves.

Pull-request sessions lose `forgejo_update_issue_labels` from their tool
set: their policy had no rule for it, so every call fell through to an
unattended deny while the tool was still advertised.

Co-Authored-By: Claude Opus 5 via omp-deck
Author
Collaborator

omp-deck failed to handle this event: the agent's turn failed.

Details are in omp-deck under webhook delivery 33f48ebe-02d3-4fd4-acc8-c4d23aec44d8 (session 01a1ca07-3706-7000-9b1f-cee63e67ac21).

omp-deck failed to handle this event: the agent's turn failed. Details are in omp-deck under webhook delivery `33f48ebe-02d3-4fd4-acc8-c4d23aec44d8` (session `01a1ca07-3706-7000-9b1f-cee63e67ac21`).
Owner

Try again

Try again
omp-deck force-pushed agent/issue-232-label-tools from 7cca040ad8 to ba81bb7b7a 2026-11-11 11:25:30 +01:00 Compare
lucas merged commit ca6d7d6cc7 into main 2026-11-11 11:39:38 +01:00
lucas deleted branch agent/issue-232-label-tools 2026-11-11 11:39:38 +01:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
lucas/omp-deck!260
No description provided.