a commander's children stay out of the chat list
/chat already hid commanders. it did not hid their spawned agents, and a commander that fires once an hour spawns one per run — each with its own transcript, titled after whatever its first message happened to be. one commander had thirteen sessions under its directory, twelve of them reading "Read /home/.../procedures/classify-t…". a loop's bookkeeping, filling the list you keep conversations in. listCommandHqOwnedSessionIds is the union: commanders plus their children. kept separate from listCommandHqSessionIds rather than replacing it, because a CHILD is not a commander — isCommander has to stay false for one or the composer would offer it the handoff watcher. /chat/live is deliberately untouched. it is the "what is running right now" panel, and a spawned agent that is still going belongs there — hiding it would mean an agent running with nowhere showing it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Officer-Session: 656f5c85-e49a-4f1f-b9f3-042a04b4d043
This commit is contained in:
@@ -8,6 +8,7 @@ export {
|
|||||||
getCommandHqSessionById,
|
getCommandHqSessionById,
|
||||||
listCommandHqSessions,
|
listCommandHqSessions,
|
||||||
listCommandHqSessionIds,
|
listCommandHqSessionIds,
|
||||||
|
listCommandHqOwnedSessionIds,
|
||||||
getCommandHqSession,
|
getCommandHqSession,
|
||||||
setCommandHqSessionCategory,
|
setCommandHqSessionCategory,
|
||||||
deleteCommandHqSession,
|
deleteCommandHqSession,
|
||||||
|
|||||||
@@ -186,6 +186,30 @@ export async function listCommandHqSessionIds(userId: number): Promise<Set<strin
|
|||||||
return new Set(rows.map((r) => r.sessionId!));
|
return new Set(rows.map((r) => r.sessionId!));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Every transcript that belongs to a commander: the commanders themselves AND the agents they spawned.
|
||||||
|
*
|
||||||
|
* What `/chat`'s list hides. The set above is not enough — it holds the commanders, and a commander that
|
||||||
|
* fires once an hour spawns a child per run, each with its own transcript titled after whatever its first
|
||||||
|
* message happened to be. Thirteen of them under one directory was what made this obvious: twelve reading
|
||||||
|
* `Read /home/.../procedures/classify-t…`, filling the conversation list with a loop's bookkeeping.
|
||||||
|
*
|
||||||
|
* Separate from `listCommandHqSessionIds` rather than replacing it, because a CHILD is not a commander —
|
||||||
|
* `isCommander` on a session must stay false for one, or the composer would offer it the handoff watcher.
|
||||||
|
*/
|
||||||
|
export async function listCommandHqOwnedSessionIds(userId: number): Promise<Set<string>> {
|
||||||
|
const [commanders, children] = await Promise.all([
|
||||||
|
listCommandHqSessionIds(userId),
|
||||||
|
db
|
||||||
|
.select({ id: commandHqSpawned.spawnedSessionId })
|
||||||
|
.from(commandHqSpawned)
|
||||||
|
.innerJoin(commandHqSessions, eq(commandHqSessions.id, commandHqSpawned.sessionRowId))
|
||||||
|
.where(eq(commandHqSessions.userId, userId)),
|
||||||
|
]);
|
||||||
|
for (const row of children) commanders.add(row.id);
|
||||||
|
return commanders;
|
||||||
|
}
|
||||||
|
|
||||||
// drizzle's `eq` cannot express `IS NOT NULL` either.
|
// drizzle's `eq` cannot express `IS NOT NULL` either.
|
||||||
const isNotNullSessionId = () => sql`${commandHqSessions.sessionId} is not null`;
|
const isNotNullSessionId = () => sql`${commandHqSessions.sessionId} is not null`;
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
getChatSessionModel,
|
getChatSessionModel,
|
||||||
getChatSessionModels,
|
getChatSessionModels,
|
||||||
listCommandHqSessionIds,
|
listCommandHqSessionIds,
|
||||||
|
listCommandHqOwnedSessionIds,
|
||||||
getChatNotifyPreference,
|
getChatNotifyPreference,
|
||||||
getChatNotifyPreferences,
|
getChatNotifyPreferences,
|
||||||
setChatNotifyPreference,
|
setChatNotifyPreference,
|
||||||
@@ -156,7 +157,7 @@ chatRouter.get('/sessions', async (ctx) => {
|
|||||||
that excludes commanders has nothing to say about which of its rows is one. `/chat/live` is where the
|
that excludes commanders has nothing to say about which of its rows is one. `/chat/live` is where the
|
||||||
flag is real, because that route keeps both kinds.
|
flag is real, because that route keeps both kinds.
|
||||||
*/
|
*/
|
||||||
const filed = await listCommandHqSessionIds(user.id).catch(() => new Set<string>());
|
const filed = await listCommandHqOwnedSessionIds(user.id).catch(() => new Set<string>());
|
||||||
const sessions = merged.filter((s) => !filed.has(s.id));
|
const sessions = merged.filter((s) => !filed.has(s.id));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
Reference in New Issue
Block a user