Gateway: show subagent requests on the parent's card, and settle threads
Gateway / check (push) Successful in 8s
Gateway / image (push) Successful in 21s

This commit is contained in:
gib committed 2026-11-01 20:15:22 -05:00
1 parent a8b6375afe
commit a4754b65b0
7 files changed
+183 -21

No files matched your search

+53 -1
View File
@@ -2,7 +2,7 @@ import { describe, expect, it } from "bun:test";
import type { BoundedThread, ThreadShell } from "../src/t3/types.ts";
import type { T3Host } from "../src/t3/host.ts";
import { buildSummary, routeKind, summarize, trimText } from "../src/views.ts";
import { buildFeed, buildSummary, routeKind, summarize, SummaryCache, trimText } from "../src/views.ts";
const thread = (overrides: Partial<ThreadShell> = {}): ThreadShell => ({
id: "thread-1",
@@ -138,3 +138,55 @@ describe("routeKind", () => {
expect(routeKind("https://t3laptopvpn.gbrown.org")).toBe("public");
});
});
describe("buildFeed", () => {
const now = Date.parse("2026-11-01T09:30:00.000Z");
const host = (label: string, threads: ThreadShell[]) =>
({
id: label,
label,
status: "online",
config: { environmentId: `env-${label}` },
projects: new Map(),
threads: new Map(threads.map((t) => [t.id, t])),
bounded: () => Promise.reject(new Error("not needed")),
}) as unknown as T3Host;
const ask = (id: string, minute: number) => ({ id, kind: "command", createdAt: `2026-11-01T09:${minute}:00.000Z` });
const delegatedFrom = { environmentId: "env-Desktop", threadId: "parent", title: "HomeLab Stats" };
it("shows a waiting subagent's request on the card of the thread that delegated it", async () => {
const feed = await buildFeed(
[
host("Desktop", [thread({ id: "parent", title: "HomeLab Stats" })]),
host("Mac mini", [
thread({ id: "child", title: "Check PATH", delegatedFrom, pendingRuntimeRequest: ask("r1", 10) }),
thread({ id: "busy", title: "Survey setup", delegatedFrom }),
]),
],
new SummaryCache(),
now,
);
expect(feed.working).toEqual([]);
expect(feed.needsYou.map((item) => [item.threadId, item.phase, item.via])).toEqual([
["parent", "waiting_for_approval", { hostId: "Mac mini", threadId: "child", title: "Check PATH" }],
]);
});
it("keeps a second waiting subagent on its own card", async () => {
const feed = await buildFeed(
[
host("Desktop", [thread({ id: "parent", title: "HomeLab Stats" })]),
host("Mac mini", [
thread({ id: "later", delegatedFrom, pendingRuntimeRequest: ask("r2", 20) }),
thread({ id: "first", delegatedFrom, pendingRuntimeRequest: ask("r1", 10) }),
]),
],
new SummaryCache(),
now,
);
expect(feed.needsYou.map((item) => [item.threadId, item.via?.threadId ?? null])).toEqual([
["parent", "first"],
["later", null],
]);
});
});