orchard
mirrorEvery site I host, in one repo, along with the Cloudflare Tunnel and Caddy that front them. It's all Go, Vite, and SQLite, and it runs on a desktop at home with nothing listening on an inbound port.
blogbuncaddycloudflare-tunneldockergogolanghomelabhtml-templatemonorepoself-hostedseosqlitestatic-sitetypstuptime-monitoringviteweb-analytics
1package skills
2
3import (
4 "context"
5 "strings"
6 "testing"
7)
8
9func TestURLsIn(t *testing.T) {
10 cases := []struct {
11 q string
12 want []string
13 }{
14 {"summary of this https://cloudinabottle.org/blog/launch-post",
15 []string{"https://cloudinabottle.org/blog/launch-post"}},
16 {"what does https://example.com/a say, and is it right?",
17 []string{"https://example.com/a"}},
18 {"read (https://example.com/a) and http://example.org/b",
19 []string{"https://example.com/a", "http://example.org/b"}},
20 {"the same one twice https://example.com/a https://example.com/a",
21 []string{"https://example.com/a"}},
22 {"how many people live in http land", nil},
23 {"what is https://localhost about", nil},
24 {"a query string survives https://example.com/a?b=c&d=e#f",
25 []string{"https://example.com/a?b=c&d=e#f"}},
26 {"summarise https://en.wikipedia.org/wiki/Go_(programming_language)",
27 []string{"https://en.wikipedia.org/wiki/Go_(programming_language)"}},
28 {"summarise (https://en.wikipedia.org/wiki/Go_(programming_language)).",
29 []string{"https://en.wikipedia.org/wiki/Go_(programming_language)"}},
30 }
31 for _, c := range cases {
32 got := URLsIn(c.q)
33 if strings.Join(got, "|") != strings.Join(c.want, "|") {
34 t.Errorf("%q: got %v, want %v", c.q, got, c.want)
35 }
36 }
37}
38
39// The claim is the whole routing decision for this one, so it has to hold
40// without a model. Decide is handed a nil model on purpose: reaching for it
41// would panic, which is the assertion.
42func TestPageClaimsWithoutTheModel(t *testing.T) {
43 r := Default()
44 route := r.Decide(context.Background(), nil, "summary of this https://cloudinabottle.org/blog/launch-post")
45 if route.Skill != "page" {
46 t.Fatalf("got %s, want page (%s)", route.Skill, route.Why())
47 }
48 if got := r.match("tl;dr https://example.com/post"); got != "page" {
49 t.Errorf("offline matcher got %s, want page", got)
50 }
51}
52
53// A claiming skill is kept out of the prompt the model reads, since it can
54// never be the answer to a question with no address in it.
55func TestPageIsNotInTheRoutingPrompt(t *testing.T) {
56 r := Default()
57 if strings.Contains(r.systemPrompt(), "page:") {
58 t.Error("the page card is in the routing prompt, which is noise on every other question")
59 }
60 for _, n := range r.routable() {
61 if n == "page" {
62 t.Error("page is in the enum the model chooses from")
63 }
64 }
65}
66
67func TestPageRun(t *testing.T) {
68 res, err := (Page{}).Run(context.Background(), "summary of this https://example.com/post", Deps{})
69 if err != nil {
70 t.Fatal(err)
71 }
72 if res == nil || len(res.URLs) != 1 || res.URLs[0] != "https://example.com/post" {
73 t.Fatalf("got %+v", res)
74 }
75 if res.Text != "" {
76 t.Error("it gathers rather than answers, so it must not write text")
77 }
78 if res.Shape != "summary" {
79 t.Errorf("shape is %q, want summary", res.Shape)
80 }
81
82 // The router can only send it a question with an address in it, but a
83 // skill that trusts the router has no way of declining.
84 if res, _ := (Page{}).Run(context.Background(), "what is a summary", Deps{}); res != nil {
85 t.Error("claimed a question with no address in it")
86 }
87}
88
89func TestWantsProbability(t *testing.T) {
90 for _, q := range []string{
91 "what are the odds on the us open",
92 "who is favoured to win the election",
93 "chances of a rate cut this month",
94 "is trump going to win",
95 } {
96 if !wantsProbability(q) {
97 t.Errorf("%q should read as a question about how likely something is", q)
98 }
99 }
100 for _, q := range []string{
101 "how is the us open going",
102 "what's the score in the us open",
103 "who won the us open",
104 "when is the election",
105 } {
106 if wantsProbability(q) {
107 t.Errorf("%q is not asking for a price", q)
108 }
109 }
110}