Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.
| Merge branch 'worktree-agent-a1398e81ad1a64c5f' | 1 | import assert from "node:assert/strict"; |
| 2 | import { test } from "node:test"; | |
| 3 | ||
| 4 | import { type Colleague, type HandOffPorts, addressed, handOffPort } from "./handoff.ts"; | |
| 5 | import type { HandedOff } from "./surface.ts"; | |
| 6 | ||
| 7 | const mike: Colleague = { id: "agt_mike", handle: "mike", display_name: "Mike", builtin: false, status: "idle" }; | |
| 8 | const g1t: Colleague = { id: "agt_g1t", handle: "g1t", display_name: "g1t", builtin: true, status: "idle" }; | |
| 9 | const margo: Colleague = { id: "agt_margo", handle: "margo", display_name: "Margo", builtin: false, status: "paused" }; | |
| 10 | const sam: Colleague = { id: "agt_sam", handle: "sam", display_name: "Sam", builtin: false, status: "out_of_budget" }; | |
| 11 | ||
| 12 | /** A small workspace: these agents, and the person syntaqx. */ | |
| 13 | function world(over: Partial<HandOffPorts> = {}, answer: HandedOff = { ok: true, where: "group_dm", opened: true }) { | |
| 14 | const handed: { colleague: string; brief: string }[] = []; | |
| 15 | const agents = [mike, g1t, margo, sam]; | |
| 16 | const ports: HandOffPorts = { | |
| 17 | self: { id: "agt_g1t", handle: "g1t" }, | |
| 18 | chain: [], | |
| 19 | asker: { username: "syntaqx", role: "owner", can_write: true }, | |
| 20 | agent: async (handle) => agents.find((a) => a.handle === handle) ?? null, | |
| 21 | person: async (handle) => handle === "syntaqx", | |
| 22 | handOff: async (colleague, brief) => { | |
| 23 | handed.push({ colleague, brief }); | |
| 24 | return answer; | |
| 25 | }, | |
| 26 | ...over, | |
| 27 | }; | |
| 28 | return { port: handOffPort(ports), handed }; | |
| 29 | } | |
| 30 | ||
| 31 | test("g1t hands Mike the hiring work: he is woken with the brief addressed to him, and g1t is told where it went", async () => { | |
| 32 | const { port, handed } = world(); | |
| 33 | const done = await port("mike", "Help Chase hire an engineering manager: draft the role brief."); | |
| 34 | assert.equal(done.ok, true); | |
| 35 | assert.deepEqual(handed, [{ colleague: "agt_mike", brief: "@mike Help Chase hire an engineering manager: draft the role brief." }]); | |
| 36 | assert.match(done.message, /Handed to @mike in a new group message with @syntaqx, you and them/); | |
| 37 | assert.match(done.message, /a card here links to it/); | |
| 38 | }); | |
| 39 | ||
| 40 | test("handed here, or into the group message they already share", async () => { | |
| 41 | const here = await world({}, { ok: true, where: "here", opened: false }).port("mike", "x"); | |
| 42 | assert.match(here.message, /your brief is posted in this conversation/); | |
| 43 | const again = await world({}, { ok: true, where: "group_dm", opened: false }).port("mike", "x"); | |
| 44 | assert.match(again.message, /the group message you three already have/); | |
| 45 | }); | |
| 46 | ||
| 47 | test("refusals: unknown, a person, itself, @g1t, back along the chain, unavailable, an outside asker", async () => { | |
| 48 | const refused = async (handle: string, over: Partial<HandOffPorts> = {}) => { | |
| 49 | const { port, handed } = world(over); | |
| 50 | const done = await port(handle, "Do it."); | |
| 51 | assert.equal(done.ok, false, handle); | |
| 52 | assert.equal(handed.length, 0, `nothing handed to ${handle}`); | |
| 53 | return done.message; | |
| 54 | }; | |
| 55 | assert.match(await refused("nobody"), /no agent called @nobody/); | |
| 56 | assert.match(await refused("syntaqx"), /@syntaqx is a person, not an agent/); | |
| 57 | assert.match(await refused("mike", { self: { id: "agt_mike", handle: "mike" } }), /That's you/); | |
| 58 | assert.match(await refused("g1t", { self: { id: "agt_mike", handle: "mike" } }), /@g1t can't be handed work by an agent/); | |
| 59 | assert.match(await refused("mike", { self: { id: "agt_sam", handle: "sam" }, chain: ["agt_g1t", "agt_mike"] }), /already handled this request/); | |
| 60 | assert.match(await refused("margo"), /is paused/); | |
| 61 | assert.match(await refused("sam"), /out of budget/); | |
| 62 | assert.match(await refused("mike", { asker: { username: "eve", role: "outside", can_write: false } }), /isn't a member of this workspace/); | |
| 63 | }); | |
| 64 | ||
| 65 | test("chat's own refusal comes back to the agent as the tool's answer", async () => { | |
| 66 | const { port } = world({}, { ok: false, message: "This request has been passed along too many times." }); | |
| 67 | const done = await port("mike", "x"); | |
| 68 | assert.equal(done.ok, false); | |
| 69 | assert.match(done.message, /couldn't be handed over: This request has been passed along too many times/); | |
| 70 | }); | |
| 71 | ||
| 72 | test("a brief that already names the colleague isn't addressed twice", () => { | |
| 73 | assert.equal(addressed("mike", "@Mike, please draft it."), "@Mike, please draft it."); | |
| 74 | assert.equal(addressed("mike", "Please draft it, cc @mikey."), "@mike Please draft it, cc @mikey."); | |
| 75 | }); |
This file's history is long; its oldest lines are credited to the oldest commit read.