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 | ||
| An agent is on teams the way a person is: through team membership, with no team or department of its own. Add it to teams when you create it, from its profile or from the team's page; the Agents sidebar groups agents by the teams they're on, with those on none last; what an agent is told about its teammates, team budgets, skills reach, Spend's By team and the People pages all read memberships. Agents with an old team name matching a team are moved onto it once; the rest are left off a team. Templates name a role only. The agents, teams and people guides say how. | 4 | import { clampRouting, cleanHandle, dollarsField, microsFromDollars, readAgentForm, readTeams } from "./agent-form.ts"; |
| Chat and workspace agents: channels, DMs and named agents you talk to | 5 | |
| 6 | function form(fields: Record<string, string>): FormData { | |
| 7 | const data = new FormData(); | |
| 8 | for (const [key, value] of Object.entries(fields)) data.set(key, value); | |
| 9 | return data; | |
| 10 | } | |
| 11 | ||
| 12 | test("handles are cleaned as typed", () => { | |
| 13 | assert.equal(cleanHandle("@Release Manager!"), "release-manager"); | |
| 14 | assert.equal(cleanHandle("--ship--"), "ship"); | |
| 15 | }); | |
| 16 | ||
| 17 | test("the agent form becomes what the service takes, in micro-dollars", () => { | |
| 18 | const read = readAgentForm( | |
| 19 | form({ | |
| 20 | display_name: "Ship", | |
| 21 | handle: "", | |
| Merge the workspace shell: navigation and phone shell, g1t as orchestrator, agents in roles with audience-checked reads, reactions and custom emoji, live notifications and browser push, the homepage tour (agents 0002, chat 0002) | 22 | title: "Release Manager", |
| 23 | department: "Engineering", | |
| An agent is on teams the way a person is: through team membership, with no team or department of its own. Add it to teams when you create it, from its profile or from the team's page; the Agents sidebar groups agents by the teams they're on, with those on none last; what an agent is told about its teammates, team budgets, skills reach, Spend's By team and the People pages all read memberships. Agents with an old team name matching a team are moved onto it once; the rest are left off a team. Templates name a role only. The agents, teams and people guides say how. | 24 | team: "ops", |
| Merge the workspace shell: navigation and phone shell, g1t as orchestrator, agents in roles with audience-checked reads, reactions and custom emoji, live notifications and browser push, the homepage tour (agents 0002, chat 0002) | 25 | responsibility: "Cut releases", |
| Chat and workspace agents: channels, DMs and named agents you talk to | 26 | instructions: "Cut a release on Tuesdays.", |
| 27 | personality_preset: "terse", | |
| 28 | floor: "large", | |
| 29 | ceiling: "none", | |
| 30 | providers: "g1t", | |
| 31 | monthly: "40", | |
| 32 | daily: "", | |
| 33 | task: "2.50", | |
| 34 | merge: "never", | |
| 35 | capacity: "2", | |
| 36 | }), | |
| 37 | ); | |
| 38 | assert.ok(read.ok); | |
| 39 | assert.equal(read.input.handle, "ship"); | |
| 40 | assert.equal(read.input.personality_preset, "terse"); | |
| 41 | assert.deepEqual(read.input.routing, { floor: "large", ceiling: null, providers: ["g1t"], pinned: null }); | |
| 42 | assert.deepEqual(read.input.budget, { monthly_micros: 40_000_000, daily_micros: null, task_micros: 2_500_000 }); | |
| 43 | assert.equal(read.input.autonomy?.merge, "never"); | |
| 44 | assert.equal(read.input.autonomy?.open_pull_requests, "alone"); | |
| 45 | assert.equal(read.input.capacity, 2); | |
| Merge the workspace shell: navigation and phone shell, g1t as orchestrator, agents in roles with audience-checked reads, reactions and custom emoji, live notifications and browser push, the homepage tour (agents 0002, chat 0002) | 46 | assert.equal(read.input.title, "Release Manager"); |
| 47 | assert.deepEqual(read.input.responsibilities, ["Cut releases"]); | |
| An agent is on teams the way a person is: through team membership, with no team or department of its own. Add it to teams when you create it, from its profile or from the team's page; the Agents sidebar groups agents by the teams they're on, with those on none last; what an agent is told about its teammates, team budgets, skills reach, Spend's By team and the People pages all read memberships. Agents with an old team name matching a team are moved onto it once; the rest are left off a team. Templates name a role only. The agents, teams and people guides say how. | 48 | assert.ok(!("team" in read.input) && !("department" in read.input), "teams are memberships, never part of the agent"); |
| 49 | }); | |
| 50 | ||
| 51 | test("Add to teams reads the teams chosen, by slug, once each", () => { | |
| 52 | const data = new FormData(); | |
| 53 | for (const slug of ["qa", " Web ", "qa", "not a slug!"]) data.append("teams", slug); | |
| 54 | assert.deepEqual(readTeams(data), ["qa", "web"]); | |
| 55 | assert.deepEqual(readTeams(new FormData()), []); | |
| Chat and workspace agents: channels, DMs and named agents you talk to | 56 | }); |
| 57 | ||
| 58 | test("the agent form says what to fix", () => { | |
| 59 | const read = readAgentForm(form({ display_name: "", handle: "g1t", floor: "frontier", ceiling: "small", monthly: "lots", capacity: "0" })); | |
| 60 | assert.ok(!read.ok); | |
| Merge the workspace shell: navigation and phone shell, g1t as orchestrator, agents in roles with audience-checked reads, reactions and custom emoji, live notifications and browser push, the homepage tour (agents 0002, chat 0002) | 61 | assert.deepEqual(Object.keys(read.errors).sort(), ["capacity", "ceiling", "display_name", "handle", "instructions", "monthly", "title"]); |
| Chat and workspace agents: channels, DMs and named agents you talk to | 62 | }); |
| 63 | ||
| 64 | test("dollars and micro-dollars", () => { | |
| 65 | assert.equal(microsFromDollars("$12.50"), 12_500_000); | |
| 66 | assert.equal(microsFromDollars(""), null); | |
| 67 | assert.ok(Number.isNaN(microsFromDollars("lots"))); | |
| 68 | assert.equal(dollarsField(2_500_000), "2.50"); | |
| 69 | assert.equal(dollarsField(50_000_000), "50"); | |
| 70 | }); | |
| Merge the workspace shell: navigation and phone shell, g1t as orchestrator, agents in roles with audience-checked reads, reactions and custom emoji, live notifications and browser push, the homepage tour (agents 0002, chat 0002) | 71 | |
| 72 | test("a subagent's routing stays within its agent's", () => { | |
| 73 | assert.deepEqual(clampRouting({ floor: "small", ceiling: "frontier" }, { floor: "large", ceiling: "large" }), { floor: "large", ceiling: "large" }); | |
| 74 | assert.deepEqual(clampRouting({ floor: null, ceiling: null }, { floor: null, ceiling: "large" }), { floor: null, ceiling: "large" }); | |
| 75 | assert.deepEqual(clampRouting({ floor: "frontier", ceiling: null }, { floor: null, ceiling: "large" }), { floor: "large", ceiling: "large" }); | |
| 76 | }); |
This file's history is long; its oldest lines are credited to the oldest commit read.