nearle admin agent

This commit is contained in:
2026-09-28 11:26:18 +05:30
parent 090e9c0c2f
commit b18080d429
8 changed files with 271 additions and 3 deletions

View File

@@ -236,3 +236,83 @@ func TestHelpNeedsNoTenant(t *testing.T) {
t.Fatal("staff got no answer")
}
}
/* ── The platform passages ──────────────────────────────────────────────── */
// Nearle's own staff, whose questions are about the platform rather than about
// a shop.
//
// These exist because the `platform` agent holds ONE tool — `help` — and can
// hold no other: a staff account carries no tenant, so every tool that reads a
// shop's data refuses it. The corpus is therefore the entire capability of the
// assistant in the Nearle Admin workspace, and a passage that cannot be
// retrieved is a question that has no answer at all there.
func TestThePlatformQuestionsFindTheirOwnEntry(t *testing.T) {
for question, wantEntry := range map[string]string{
"new outlet cannot sign in": "What does creating a branch actually create?",
"do I need a user before I add a branch": "What does creating a branch actually create?",
"how does a shop get riders": "What does assigning a delivery partner to a merchant do?",
"what does partnerid zero mean": "What does assigning a delivery partner to a merchant do?",
"riders not showing in a new city": "What is a district, and what happens when a partner is onboarded in a new one?",
"nearle admin cannot see sales": "Why can I not see a shop's orders or stock from the platform workspace?",
"how do I check what is stuck for a tenant": "Why can I not see a shop's orders or stock from the platform workspace?",
} {
answers := ask(t, question)
if len(answers) == 0 {
t.Fatalf("no answer for %q", question)
}
if answers[0].Question != wantEntry {
t.Fatalf("%q was answered with %q, wanted %q", question, answers[0].Question, wantEntry)
}
}
}
func TestThePlatformPassagesDoNotSwallowTheMerchantOnes(t *testing.T) {
// Four passages were added at once, and they share vocabulary with the
// merchant ones — branches, riders, partners, shops. A new passage that
// outranks an existing answer breaks a question that used to work, silently,
// and the person sees a confident answer to something they did not ask.
for question, wantEntry := range map[string]string{
"how do I add a cashier": "How do I add a cashier?",
"what happens when I assign a rider": "What happens when I assign a rider?",
"till login not working on the website": "What is the difference between a till account and a console login?",
"re-import from the global catalogue": "What does re-importing a product do?",
} {
answers := ask(t, question)
if len(answers) == 0 || answers[0].Question != wantEntry {
got := "nothing"
if len(answers) > 0 {
got = answers[0].Question
}
t.Fatalf("%q now answers with %q, wanted %q", question, got, wantEntry)
}
}
}
func TestEveryChipOnThePlatformPagesHasAnAnswer(t *testing.T) {
// The console's own chips, verbatim from `assistantContext.ts`.
//
// The rule that file states: a page is only given an agent when that agent
// can answer every chip on it, because a chip coming back "I cannot look
// that up" reads as a broken assistant rather than an unbuilt feature. In
// the platform workspace the corpus IS the assistant, so a chip with no
// passage behind it is a dead button.
//
// Duplicated here rather than imported because the two repositories deploy
// separately: this is the half that can fail on its own.
for _, chip := range []string{
"What does creating a branch actually create?",
"Why can I not see a shop's orders from here?",
"How does a shop get riders?",
"What is the difference between a till account and a console login?",
"New outlet cannot sign in",
"What is a district?",
"What does re-importing a product do?",
"Why is a product in my catalogue but not on the shelf?",
"Why can I not see a shop's stock from here?",
} {
if answers := ask(t, chip); len(answers) == 0 {
t.Fatalf("the chip %q has no passage behind it — it is a dead button", chip)
}
}
}