Repository navigation
routing: try a group's rules on a message before saving them #2829
Description
A real case: a user routes with a group, intent rules and a small classifier (Clef on Cloudflare Workers AI, say). The intents are written in English, as the templates suggest: a hard task: designing, debugging, a change across several files, or planning. Then they are stuck: their own message — 帮我把这个函数改成并发安全的 ("make this function concurrency-safe") — will the classifier call it hard or easy? The rule doesn't say: its behavior is whatever the small model answers for that message. Today the only way to learn it is to save the draft, run a real agent conversation, and read classWhy on the Routing page. Every wording change walks the loop again.
Proposal
A try box under the rules in the group editor. Paste a message and see, in under a second in the GUI, which intent the classifier picked, which rule matched, and which member goes first — for an unsaved draft.
Implementation
- One decision function for try and live traffic: the part of
ruleForthat keeps nothing is split out asturnDecide. A live turn calls it and keeps what it decided underturnRules, as before;TryRuleonly calls it. No dry-run flag crosses the hot path. - A try asks the classifier by itself (
directAnswer): no shared cache read or write, no rest for a classifier that failed, no failure note on the group's card, and no request to any member. - Three entries: the editor's try box,
POST /api/groups/try, andmagpie group try <id> <message…>— the CLI decides beside any running magpie, asking the classifier itself from the same files, for a saved group. - The answer is the trace's own
RuleHit, rendered by the Routing page's existingruleWhy/classWhy.
Verified
- 14 cases on real machines, macOS and Windows, all passing. On Windows the GUI's real classifier calls took 548–791 ms and the CLI 0.79–1.08 s (process start included); on macOS the CLI decided in 654 ms. No member model took a request the whole time. A try's classifier call is recorded like any classifier call (
agent: magpie,kind: routing) and shows on the Routing page with the classifier badge. - Branch ggbdpq-try-rule:
22952132is the feature,b96469dcfixes the single-intent wording. Both commit bodies carry the full record: guard tests shown red when broken and green restored;go vetandgo buildon darwin, linux and windows; the GUI in Chromium and WebKit —routing-rule-try.test.cjs16/16, and the 17 group-editor regression files it runs with, 194 tests across both engines.
Savings (an estimate)
Tuning a group of 2–3 intent rules usually takes 5–20 tries. Each try today is a real agent conversation (about 10k–50k tokens) plus 0.5–2 minutes of hands-on time; a try is about 150 tokens and under a second.
Boundaries
- Purely additive: remove it and no existing path changes.
- It serves users who write intent rules and iterate on their wording. A group with no deciding rules says so at once and asks the classifier nothing.
- A try is a preview: a conversation's first turn, no reasoning, images or folder, and it knows nothing of affinity or rests.
- One observation: with a single intent in the group, small models occasionally lean toward 1 (one "hey, what's up?" came back as a hard task). A try shows this; it doesn't fix it.
Open question
On the Routing page, a try's classifier call looks the same as a live one. Whether to tell them apart (a field of its own) is the maintainer's call; the branch doesn't do it.
Attribution: If these commits are applied, please keep their author (ggbdpq) or add Co-authored-by: ggbdpq <ggbdpq@gmail.com>.
AI: written with AI assistance — Generated-by: GLM-5.3-Flash (ZCode).
Activity
ggbdpq commentedon Oct 23, 2026
Refresh of the branch for #2829, the Routing group editor's "Try these rules" box shared earlier on
ggbdpq-try-ruleatb96469dc: what a draft's rules would decide for a conversation's first turn saying the words given — the classifier asked for real, the matching rule named, nothing routed and nothing kept — throughPOST /api/groups/tryandmagpie group try, beside any running magpie; and a group with a single intent asks whether the turn is it, not which of the kinds it is.Rebased onto
fa22bc64(new head26eb3fbe). The only conflict wasinternal/gui/assets/plugins/routing/i18n.js, where upstream and this branch added entries at the top of the same four language blocks; both sides are kept, no wording changed.internal/gateway/rules.go, whereruleForandturnDecidelive, has no upstream change since the old base, so the gateway side carries over as it was.Tests, all on the new head:
go test ./internal/gateway/green (whole package);go test -tags nogui ./internal/cli/green; theinternal/guipackage'sTestGroup*/TestTry*/TestTurn*green. (TestProxyCheckSaysAProxyPassedByis red, and is red on a cleanfa22bc64too — pre-existing, not this change's.)routing-rule-try.test.cjs16/16 in Chromium and WebKit across the five languages;i18n-keys,routing-intent-fallbackand five group-editor regressions (group-editor-align,group-editor-fits,group-fold,routing-groups-jump,routing-save-blank) 93/93.Refreshed with AI assistance (GLM-5.3-Flash via ZCode).
yetone commentedon Oct 27, 2026
谢谢 @ggbdpq,需求说得很清楚,分支和测试记录也很完整。这次先不合,原因如下:
ruleFor拆成turnDecide,这会动到每个路由轮次都要走的热路径。分支基于fa22bc64,之后 main 上的rules.go又改过(规则可以列多个模型,见hit.More),没法原样落上去。现在想验证规则写法,可以不跑完整的 agent 对话:保存分组后,直接对网关发一条只有你那句话的请求,
model写分组 id,max_tokens设成 1;规则里限定了 agent 的话,用Authorization: Bearer magpie-<agent>。这一条就是新对话的第一轮,Routing 页会显示 classWhy、命中的规则和先走的成员。代价是成员会收到一次极短的请求。这条先开着,留给 owner 决定要不要做界面版。如果只要 CLI/API(
magpie group try,不加界面),建议单独开一个 issue 讨论。ggbdpq commentedon Oct 27, 2026
Thanks for the detailed reply, and I accept the decision — the UI-addition rule settled after the #1354 rollback is a fair line, and the turnDecide hot-path concern stands on its own. The branch stays on the fork for reference. If a non-UI variant (rule-side verification only, via the gateway request you described or a CLI/API form) is ever wanted, I'm happy to discuss it in a separate issue. The no-UI recipe you gave is already useful as is.