8 "github.com/stretchr/testify/require"
11 func TestRootRouteToolsPersistAndRemoveRoutes(t *testing.T) {
13 server := newModelFake(t)
14 test := newDaemonMessageTest(t, dir, server)
16 source := "whatsapp:" + whatsappTestFamily.String()
17 arguments := `{"source":"` + source + `","agent":"Garden"}`
18 require.Equal(t, "Route set.", root.tools.run(t.Context(), "route", arguments))
19 require.Equal(t, source+" -> Garden", root.tools.run(t.Context(), "routes", `{}`))
21 info, err := os.Stat(filepath.Join(root.agent.dir, "routes.json"))
22 require.NoError(t, err)
23 require.Equal(t, os.FileMode(0o600), info.Mode().Perm())
24 require.Contains(t, test.logs.String(), "route set kind=whatsapp name=Garden")
25 require.NotContains(t, test.logs.String(), whatsappTestFamily.String())
28 restored := newDaemonMessageTest(t, dir, server)
29 require.Equal(t, source+" -> Garden", restored.loops[0].tools.run(t.Context(), "routes", `{}`))
30 require.Equal(t, "Route removed.", restored.loops[0].tools.run(t.Context(), "unroute", `{"source":"`+source+`"}`))
31 require.Equal(t, "No routes.", restored.loops[0].tools.run(t.Context(), "routes", `{}`))
32 require.Contains(t, restored.logs.String(), "route removed kind=whatsapp")
35 empty := newDaemonMessageTest(t, dir, server)
36 require.Equal(t, "No routes.", empty.loops[0].tools.run(t.Context(), "routes", `{}`))
37 require.Zero(t, server.Calls())
40 func TestRoutesRefuseUnknownSourcesAndNonchildren(t *testing.T) {
41 test := newDaemonMessageTest(t, t.TempDir(), newModelFake(t))
42 testCases := []struct {
52 cause: "unknown source kind",
56 source: whatsappTestFamily.String(),
58 cause: "unknown source kind",
64 cause: "invalid WhatsApp source",
67 name: "unknown chat kind",
68 source: "whatsapp:example@unknown",
70 cause: "invalid WhatsApp source",
73 name: "root is not a child",
74 source: "whatsapp:" + whatsappTestFamily.String(),
76 cause: "must be a child",
79 name: "unknown child",
80 source: "whatsapp:" + whatsappTestFamily.String(),
82 cause: "must be a child",
86 source: "whatsapp:" + whatsappTestFamily.String(),
88 cause: "must be a child",
92 for _, tc := range testCases {
93 t.Run(tc.name, func(t *testing.T) {
94 arguments := `{"source":"` + tc.source + `","agent":"` + tc.agent + `"}`
95 require.Contains(t, test.loops[0].tools.run(t.Context(), "route", arguments), tc.cause)
99 require.Contains(t, test.loops[0].tools.run(t.Context(), "unroute", `{"source":"mail:inbox"}`), "unknown source kind")
100 require.Equal(t, "No routes.", test.messages.routes.List())
103 func TestRouteToolsBelongOnlyToRoot(t *testing.T) {
104 test := newDaemonMessageTest(t, t.TempDir(), newModelFake(t))
105 for _, name := range []string{"route", "unroute", "routes"} {
106 require.Contains(t, promptToolNames(test.agents[0].agent.Tools()), name)
107 require.NotContains(t, promptToolNames(test.agents[1].agent.Tools()), name)
108 require.NotContains(t, promptToolNames(promptSubagentTools()), name)
109 require.Contains(t, test.loops[1].tools.run(t.Context(), name, `{}`), "unknown tool")
112 require.NotContains(t, promptChild("Garden", "OneChat", "Keep plans.", "/CHILD/instructions.md", ""), "Propose routing a source")
115 func TestWhatsAppStatusListsRoutes(t *testing.T) {
116 whatsapp, _, _ := whatsappStartTest(t, t.TempDir(), newTestClock())
117 test := newDaemonMessageTest(t, t.TempDir(), newModelFake(t))
118 whatsapp.routes = test.messages.routes
119 require.NoError(t, test.messages.routes.Set("whatsapp:"+whatsappTestFamily.String(), "Garden"))
123 whatsapp.Command("status", func(text string) {
127 require.Contains(t, answer, "WhatsApp is not linked.")
128 require.Contains(t, answer, "WhatsApp routes:\nwhatsapp:"+whatsappTestFamily.String()+" -> Garden")
131 func TestInvalidRouteFileStopsStartup(t *testing.T) {
132 testCases := []struct {
137 name: "invalid JSON",
141 name: "unknown source",
142 text: `{"mail:inbox":"Garden"}`,
145 name: "empty destination",
146 text: `{"whatsapp:example@lid":""}`,
150 for _, tc := range testCases {
151 t.Run(tc.name, func(t *testing.T) {
152 path := filepath.Join(t.TempDir(), "routes.json")
153 require.NoError(t, os.WriteFile(path, []byte(tc.text), 0o600))
155 _, err := openRoutes(path, discardLog())
156 require.Error(t, err)