mirror of
https://github.com/multica-ai/multica.git
synced 2026-07-30 16:08:55 +02:00
* feat(quick-create): add project picker that remembers last pick Quick-create users targeting one project repeatedly had to restate "in project X" in every prompt. The modal now exposes a project picker beside the agent picker, persists the selection per-workspace, and pins the agent's `multica issue create` invocation to that project so the prompt text doesn't have to. The picked project also flows to the daemon as ProjectID/ProjectTitle and its github_repo resources override the workspace repo fallback — same treatment issue-bound tasks already get. Co-authored-by: multica-agent <github@multica.ai> * fix(quick-create): move project picker into property pill row Reviewer feedback: the picker felt out of place wedged next to the agent header. Move it into a property toolbar row above the footer, reusing the shared `ProjectPicker` + `PillButton` so its placement and styling line up exactly with the manual create panel. This also drops the bespoke dropdown / aria / label strings that were only needed while the picker rendered inline beside "Created by". Co-authored-by: multica-agent <github@multica.ai> * fix(quick-create): clear stale persisted project + carry across mode switch Two review-blocking bugs in PR #2321: 1. The stale-id sweep in AgentCreatePanel only fired when projects.length > 0 and only cleared local state, leaving lastProjectId pointing at a deleted project. The next open re-seeded the dead UUID and submit hit the server's `project not found` rejection. Gate on the query's `isSuccess` so we can tell "loading" apart from "loaded as empty", and clear both local state and the persisted preference when the selection isn't in the resolved list. 2. ManualCreatePanel's switchToAgent dropped the picked project from the carry payload, so flipping manual → agent silently fell back to the agent panel's own lastProjectId — potentially routing the issue to a different project than the one shown in manual mode. Forward project_id alongside prompt / agent_id, and add a regression test. Co-authored-by: multica-agent <github@multica.ai> * test(quick-create): pass new isExpanded props in stale-project tests Main got an expand button on AgentCreatePanel via #2320 while this branch was open, adding `isExpanded` / `setIsExpanded` to the panel's required props. The two new stale-project tests still passed `{ onClose }` only, which CI's typecheck (run on the main+branch merge) caught while my local run did not. Co-authored-by: multica-agent <github@multica.ai> --------- Co-authored-by: multica-agent <github@multica.ai>
79 lines
3.1 KiB
Go
79 lines
3.1 KiB
Go
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)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestBuildQuickCreatePromptProjectPinning verifies that when the user
|
|
// pins a project in the quick-create modal, the prompt instructs the agent
|
|
// to pass `--project <uuid>` exactly. Without this, the agent would re-read
|
|
// the workspace default and silently drop the user's selection — the same
|
|
// "I have to retype 'in project X' every time" failure mode the modal
|
|
// addition was meant to fix.
|
|
func TestBuildQuickCreatePromptProjectPinning(t *testing.T) {
|
|
const projectID = "11111111-2222-3333-4444-555555555555"
|
|
out := buildQuickCreatePrompt(Task{
|
|
QuickCreatePrompt: "fix the login button color",
|
|
ProjectID: projectID,
|
|
ProjectTitle: "Web App",
|
|
})
|
|
mustContain := []string{
|
|
"--project \"" + projectID + "\"",
|
|
"Web App",
|
|
"modal selection is authoritative",
|
|
}
|
|
for _, s := range mustContain {
|
|
if !strings.Contains(out, s) {
|
|
t.Errorf("buildQuickCreatePrompt with project missing %q\n--- output ---\n%s", s, out)
|
|
}
|
|
}
|
|
|
|
// Without a project, the prompt must keep the legacy "omit" instruction
|
|
// so the agent doesn't accidentally start passing --project on plain
|
|
// quick-create runs.
|
|
plain := buildQuickCreatePrompt(Task{QuickCreatePrompt: "fix the login button color"})
|
|
if !strings.Contains(plain, "**project**: omit") {
|
|
t.Errorf("buildQuickCreatePrompt without project must keep the omit instruction, got:\n%s", plain)
|
|
}
|
|
if strings.Contains(plain, "--project") {
|
|
t.Errorf("buildQuickCreatePrompt without project must NOT mention --project, got:\n%s", plain)
|
|
}
|
|
}
|