mirror of
https://gh-proxy.org/https://github.com/klinsmaya/multica.git
synced 2026-11-09 01:46:46 +08:00
* feat(agent): run Meta Muse Code as an MSP runtime Muse Code speaks MSP (Muse Session Protocol) over `muse serve`: JSON-RPC 2.0 on stdio, like ACP, but with its own method vocabulary. A session opens with session/start or session/resume, work is submitted with turn/start, and assistant text, reasoning and tool calls arrive as transcript items. The adapter maps those items onto the Backend contract, reads the terminal turn outcome, and reports a notFound resume as ResumeRejected so the daemon retries on a fresh session instead of losing continuity silently. Approval is a session property, not a launch flag: `muse serve` has no --yolo, and the CLI documents --yolo as TUI-only. A fresh session is created with approvalMode=allowAll and a resumed session re-asserts it with session/setApprovalMode, which is what lets a claimed task run without waiting for a human. The container and per-task worktree remain the isolation boundary, as they are for every other backend. commandId must be UUIDv7 — Muse derives a turn id from it and rejects anything else — so the adapter mints time-ordered ids rather than v4. The model catalog comes from the session-free model/list query and the pick is applied through session/start modelId. * feat(runtime-profiles): allow muse as a protocol family A custom runtime profile may only be based on a protocol family the daemon supports, and the database enforces the same list. Widening both keeps the create flow, the server validation and the CHECK constraint in lockstep with agent.SupportedTypes. * fix(muse): complete runtime integration and lifecycle handling (MUL-8057) Co-authored-by: multica-agent <[email protected]> * docs(muse): document runtime setup and support (MUL-8057) Co-authored-by: multica-agent <[email protected]> --------- Co-authored-by: yushen <[email protected]> Co-authored-by: multica-agent <[email protected]>
62 lines
1.9 KiB
Go
62 lines
1.9 KiB
Go
package execenv
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestMusePrepareDeliversBriefAndSkills(t *testing.T) {
|
|
t.Parallel()
|
|
workDir := t.TempDir()
|
|
briefPath := filepath.Join(workDir, "AGENTS.md")
|
|
const repoInstructions = "# Repository rules\nKeep user files.\n"
|
|
if err := os.WriteFile(briefPath, []byte(repoInstructions), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
env, err := Prepare(PrepareParams{
|
|
WorkspacesRoot: t.TempDir(), WorkspaceID: "muse-workspace", TaskID: "muse-task",
|
|
Provider: "muse", LocalWorkDir: workDir,
|
|
Task: TaskContextForEnv{
|
|
IssueID: "11111111-2222-3333-4444-555555555555",
|
|
AgentSkills: []SkillContextForEnv{{Name: "muse-workflow", Content: "Follow the Muse workflow."}},
|
|
},
|
|
}, discardLogger())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := InjectRuntimeConfig(env.WorkDir, "muse", TaskContextForEnv{
|
|
IssueID: "11111111-2222-3333-4444-555555555555",
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
brief, err := os.ReadFile(briefPath)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, want := range []string{repoInstructions, "multica issue comment add", "## Output"} {
|
|
if !strings.Contains(string(brief), want) {
|
|
t.Errorf("runtime brief is missing %q", want)
|
|
}
|
|
}
|
|
skillPath := filepath.Join(workDir, ".agents", "skills", "muse-workflow", "SKILL.md")
|
|
skill, err := os.ReadFile(skillPath)
|
|
if err != nil || !strings.Contains(string(skill), "Follow the Muse workflow.") {
|
|
t.Errorf("native skill missing: content=%q err=%v", skill, err)
|
|
}
|
|
if err := CleanupSidecars(env.RootDir); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := CleanupRuntimeConfig(workDir, "muse"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
restored, err := os.ReadFile(briefPath)
|
|
if err != nil || string(restored) != repoInstructions {
|
|
t.Errorf("repository instructions changed after cleanup: %q, %v", restored, err)
|
|
}
|
|
if _, err := os.Stat(skillPath); !os.IsNotExist(err) {
|
|
t.Errorf("managed skill survived cleanup: %v", err)
|
|
}
|
|
}
|