Compare commits

...

3 Commits

Author SHA1 Message Date
Jiang Bohan
4696b64324 refactor(daemon): trim quick-create prompt rules to general principles
Reviewers pointed out the previous rewrite traded one prompt smell (over-
permissive verbatim quoting) for another (too many specific rules and
exhaustive bilingual example tables). Rewrites the description block as
general principles with a single representative example each, trusting the
model to generalize:

- "Strip non-spec material before writing" replaces the multi-bullet list
  of routing-meta-instruction and conversational-filler enumerations.
- "Include Context only when references were fetched and produced facts;
  never use it as an apology log" replaces the three "Do NOT emit a
  Context section to" sub-bullets.
- The CC exception (the only operationally non-obvious rule, since
  `multica issue create` has no --subscriber flag) is kept inline as a
  single sentence and is still locked in by the regression test.

Net: ~16 fewer lines of prompt text without losing any of the rules the
test asserts.

Co-authored-by: multica-agent <github@multica.ai>
2026-05-06 17:50:33 +08:00
Jiang Bohan
59c7279b8a fix(daemon): preserve cc mention links in quick-create description
Stripping "cc @Y" wholesale would have lost the mentioned member's only
routing channel: `multica issue create` has no --subscriber/--cc flag, and
the platform auto-subscribes members by parsing `[@Name](mention://member/<uuid>)`
links from the description body. Without the mention link in the body, a
cc'd member would never get subscribed or notified.

Updates the prompt to:
- Strip only the verbal "cc" wrapper from the User request body.
- Append a trailing `CC: <mention links>` line to the description so the
  platform's auto-subscribe logic still picks the mentions up.
- Spell out the contrast for assignee mentions, where --assignee-id is
  the routing channel and the body should not double-encode the mention.

Also adds a substring assertion for the "Pure conversational fillers" rule
that was missing from the original regression test.

Co-authored-by: multica-agent <github@multica.ai>
2026-05-06 17:43:46 +08:00
Jiang Bohan
af0590978c fix(daemon): tighten quick-create prompt to drop meta-instructions and apologetic Context
The quick-create prompt was producing descriptions that:
1. Echoed routing meta-instructions ("create an issue for me", "cc @X") into
   the User request body, even though those phrases are handled by separate
   CLI flags and are not spec content.
2. Emitted a Context section to apologize for resources it could not fetch
   (e.g. an image attachment not piped through to the run), instead of
   staying silent and letting the executing agent ask the user.
3. Preserved pure conversational fillers ("对吧?", "嗯", "那个…") because the
   model treated removing them as forbidden paraphrasing.

Updates the prompt to call out each of these as explicit non-spec material
to strip before writing the description, while keeping the "high fidelity /
no paraphrasing of substantive content" invariant. Adds a regression test
that locks in the new rules at the substring level.

Co-authored-by: multica-agent <github@multica.ai>
2026-05-06 17:36:29 +08:00
2 changed files with 47 additions and 10 deletions

View File

@@ -50,16 +50,11 @@ func buildQuickCreatePrompt(task Task) string {
b.WriteString("- **title**: required. A concise but semantically rich summary. If the input references external resources (PRs, issues, URLs), use your judgment on whether fetching the resource would produce a meaningfully better title — e.g. \"review PR #123\" → \"Review PR #123: Refactor auth module to OAuth2\". Strip filler words but preserve key semantic information.\n\n")
// description — the core optimization
b.WriteString("- **description**: The description will be the primary context for the executing agent. Your goal is **high fidelity** — the executing agent should understand the user's intent as well as if they had read the original input themselves.\n\n")
b.WriteString(" **Structure the description as follows:**\n\n")
b.WriteString(" 1. **User request** — Faithfully restate what the user wants done, in their own terms. Preserve the user's phrasing, tone, and scope. Do NOT paraphrase into generic language (e.g. don't turn \"把这个按钮改成红色\" into \"UI improvement needed\"). Do NOT add implementation plans, acceptance criteria, design decisions, or constraints the user did not express.\n\n")
b.WriteString(" 2. **Context** (only if the input contains URLs, references, or image attachments) — Fetch referenced resources (PRs, issues, docs) and summarize the relevant factual content. Keep summaries to verifiable facts only (e.g. \"PR #45 changes the auth middleware to use JWT\" not \"this suggests we should also update the tests\"). Preserve any image URLs or markdown image references inline.\n\n")
b.WriteString(" Omit the Context section entirely if there are no external references to enrich.\n\n")
b.WriteString(" **Hard rules for description:**\n")
b.WriteString(" - NEVER invent requirements, implementation details, acceptance criteria, or scope that the user did not express.\n")
b.WriteString(" - NEVER reduce the user's multi-sentence input to a single vague sentence. If the user wrote three sentences, the description should carry at least that much information.\n")
b.WriteString(" - Preserve specific names, identifiers, file paths, code snippets, and technical terms from the input verbatim.\n")
b.WriteString(" - Never echo the title in the description.\n\n")
b.WriteString("- **description**: The description is the executing agent's primary context. Aim for high fidelity — they should grasp the user's intent as if they had read the raw input themselves. Use a two-section structure:\n\n")
b.WriteString(" 1. **User request** — Faithfully restate what the user wants in their own words. Preserve specific names, identifiers, file paths, code snippets, and technical terms verbatim. Strip non-spec material before writing it (this is removal, not paraphrasing): verbal routing wrappers about creating the issue (e.g. \"create an issue\", \"分配给 X\") and pure conversational fillers (e.g. \"对吧?\"). When in doubt, keep it.\n\n")
b.WriteString(" CC exception: `multica issue create` has no `--subscriber` flag, and the platform auto-subscribes members whose `[@Name](mention://member/<uuid>)` link appears in the description. When the user wrote \"cc @Y\", strip the verbal \"cc\" wrapper from the User request body and append a final `CC: <mention link(s)>` line to the description so the cc routing still fires.\n\n")
b.WriteString(" 2. **Context** — include ONLY when the input cited external resources AND you successfully fetched them AND they produced verifiable facts worth recording. Summarize facts only (e.g. \"PR #45 changes auth to JWT\"), not interpretation or unsolicited reference implementations. If you have nothing factual to add, omit the section entirely — never use it as an apology log for resources you could not fetch.\n\n")
b.WriteString(" Hard rules: never invent requirements, implementation details, or acceptance criteria the user did not express; never reduce multi-sentence input to a single vague sentence; never echo the title.\n\n")
// priority
b.WriteString("- **priority**: one of `urgent`, `high`, `medium`, `low`, or omit. Map P0/P1 → urgent/high; \"asap\" → urgent. If unspecified, omit.\n\n")

View File

@@ -0,0 +1,42 @@
package daemon
import (
"strings"
"testing"
)
// TestBuildQuickCreatePromptRules locks in the rules that govern how the
// quick-create agent is allowed to translate raw user input into the issue
// description body. Each substring corresponds to a concrete failure mode
// observed in production output:
// - meta-instructions ("create an issue", "cc @X") leaking into the body
// - the Context section being misused as an apology log when no external
// references were actually fetched
// - hard-line rules being silently dropped on prompt rewrites
func TestBuildQuickCreatePromptRules(t *testing.T) {
out := buildQuickCreatePrompt(Task{QuickCreatePrompt: "fix the login button color"})
mustContain := []string{
// high-fidelity invariant
"Faithfully restate what the user wants",
"Preserve specific names, identifiers, file paths",
// strip non-spec material: verbal routing wrappers + conversational fillers
"verbal routing wrappers about creating the issue",
"pure conversational fillers",
// cc routing must survive: mention link stays in description so the
// auto-subscribe path fires (multica issue create has no --subscriber flag)
"CC exception",
"auto-subscribes members",
// context section is conditional and must not be an apology log
"include ONLY when the input cited external resources",
"never use it as an apology log",
// hard rules
"never invent requirements",
"never reduce multi-sentence input",
}
for _, s := range mustContain {
if !strings.Contains(out, s) {
t.Errorf("buildQuickCreatePrompt output missing required rule: %q", s)
}
}
}