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.
| Chat and workspace agents: channels, DMs and named agents you talk to | 1 | import assert from "node:assert/strict"; |
| 2 | import { test } from "node:test"; | |
| 3 | ||
| 4 | import type { AgentDelivery } from "@g1t/contracts"; | |
| 5 | ||
| 6 | import { g1tSurface } from "./surface.ts"; | |
| 7 | ||
| 8 | const delivery: AgentDelivery = { | |
| 9 | workspace: "acme", | |
| 10 | workspace_id: "wsp_1", | |
| 11 | channel_id: "chn_1", | |
| 12 | channel_kind: "channel", | |
| 13 | channel_name: "releases", | |
| 14 | agent_id: "agt_ship", | |
| 15 | message_id: "msg_1", | |
| 16 | thread_root: "msg_0", | |
| 17 | asked_by: "usr_dana", | |
| 18 | hops: 2, | |
| 19 | asker: { username: "dana", role: "member", can_write: false }, | |
| 20 | surface: "g1t", | |
| 21 | }; | |
| 22 | ||
| 23 | /** A chat binding that records each call and answers `answers[method]`. */ | |
| 24 | function fakeChat(answers: Record<string, unknown>) { | |
| 25 | const calls: { method: string; body: any }[] = []; | |
| 26 | const binding = { | |
| 27 | async fetch(url: string, init: { body: string }) { | |
| 28 | const method = new URL(url).pathname.replace("/rpc/", ""); | |
| 29 | calls.push({ method, body: JSON.parse(init.body) }); | |
| 30 | return Response.json(answers[method] ?? { ok: true, value: null }); | |
| 31 | }, | |
| 32 | }; | |
| 33 | return { binding: binding as any, calls }; | |
| 34 | } | |
| 35 | ||
| 36 | test("the g1t adapter posts in the thread, handing on hops, asked_by and the asker's access", async () => { | |
| 37 | const chat = fakeChat({ post_as_agent: { ok: true, value: { id: "msg_2" } } }); | |
| 38 | const id = await g1tSurface(chat.binding, delivery).post("Tagged 1.4."); | |
| 39 | assert.equal(id, "msg_2"); | |
| 40 | const [call] = chat.calls; | |
| 41 | assert.equal(call.method, "post_as_agent"); | |
| 42 | assert.equal(call.body.agent_id, "agt_ship"); | |
| 43 | assert.equal(call.body.channel_id, "chn_1"); | |
| 44 | assert.deepEqual(call.body.message, { | |
| 45 | body: "Tagged 1.4.", | |
| 46 | thread_root: "msg_0", | |
| 47 | hops: 2, | |
| 48 | asked_by: "usr_dana", | |
| 49 | asker: { username: "dana", role: "member", can_write: false }, | |
| 50 | }); | |
| 51 | }); | |
| 52 | ||
| 53 | test("the g1t adapter reads the thread as the agent, and leaves out deleted messages", async () => { | |
| 54 | const message = (id: string, deleted: string | null) => ({ | |
| 55 | id, | |
| 56 | channel_id: "chn_1", | |
| 57 | author: { kind: "user", id: "usr_dana", name: "dana", display_name: "Dana", avatar: null, role: null }, | |
| 58 | kind: "text", | |
| 59 | body: "hi", | |
| 60 | card: null, | |
| 61 | thread_root: "msg_0", | |
| 62 | reply_count: 0, | |
| 63 | last_reply_at: null, | |
| 64 | created_at: "2026-10-08T12:00:00Z", | |
| 65 | edited_at: null, | |
| 66 | deleted_at: deleted, | |
| 67 | }); | |
| 68 | const chat = fakeChat({ history_for_agent: { ok: true, value: [message("msg_0", null), message("msg_1", "2026-10-08T12:01:00Z")] } }); | |
| 69 | const history = await g1tSurface(chat.binding, delivery).history(30); | |
| 70 | assert.deepEqual(chat.calls[0].body, { workspace: "acme", channel_id: "chn_1", agent_id: "agt_ship", thread_root: "msg_0", limit: 30 }); | |
| 71 | assert.deepEqual(history.map((m) => m.id), ["msg_0"]); | |
| 72 | assert.equal(history[0].author.name, "dana"); | |
| 73 | }); | |
| 74 | ||
| 75 | test("a failed post is an error the reply loop records; typing never throws", async () => { | |
| 76 | const chat = fakeChat({ post_as_agent: { ok: false, error: { code: "forbidden", message: "not a member" } } }); | |
| 77 | await assert.rejects(g1tSurface(chat.binding, delivery).post("x"), /not a member/); | |
| 78 | const broken = { fetch: async () => new Response("down", { status: 500 }) } as any; | |
| 79 | await g1tSurface(broken, delivery).typing(); | |
| 80 | }); |