a spawned session says who started it

The other half of making a spawned agent visible. The commander's pane now lists
its children; opening one gave no way back — no link to the conversation that owns
it, and nothing to tell it apart from a chat somebody had started themselves and
forgotten.

`parentCommanderOf` is the row `ingestSpawnedChildren` already writes, read from
the other end. So this needed no table and no write path: a commander's children
were recorded because deleting one has to take them with it, and that record
answers "who is my parent" for free. Nothing had asked.

`GET /chat/sessions/:id` carries `spawnedBy`, and the chat panel renders one line
above the transcript linking back to the commander. Null for almost every session,
which is the normal case rather than a miss — a chat somebody opened has no parent
— so the bar renders nothing at all rather than saying so. Never fatal: a session
must open when this lookup will not.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-23 05:09:28 +00:00
co-authored by Claude Opus 5
parent 44f5246e38
commit f6b9ddc877
5 changed files with 85 additions and 0 deletions
+10
View File
@@ -13,6 +13,7 @@ import {
getChatNotifyPreferences,
setChatNotifyPreference,
forgetChatSessions,
parentCommanderOf,
} from 'officerdb';
import type { NotifyPreference } from 'officerdb/types';
import { setNudge, getNudge, cancelNudge } from 'officerdb';
@@ -273,6 +274,15 @@ chatRouter.get('/sessions/:id', async (ctx) => {
travels with the conversation.
*/
isCommander: (await listCommandHqSessionIds(user.id)).has(id),
/*
Which commander spawned this, if any — the row `ingestSpawnedChildren` writes, read from the other
end. A spawned agent has always been fully readable here; what it could never say was who started
it, so opening one gave no way back to the conversation that owns it.
Null for almost every session and that is the normal case, not a miss: a chat somebody opened
themselves has no parent. Never fatal — a session must render when this lookup will not.
*/
spawnedBy: await parentCommanderOf(id).catch(() => null),
});
});