fix(thread-panel): wire the scoped reply composer to real participants
The thread-panel composer was pinned to `channel="direct"` with no
`directParticipantIds` and no `replyTo`. Clicking reply in a human
review thread sent a message with no recipient and the send button
stayed disabled — a silent dead-end for the entire Co-Founder
review UX.
The fix exposes the thread's participant list to the renderer:
- `listThreadParticipantsSchema` and the matching IPC channel
(`agent-company:list-thread-participants`) return the rows from
`conversation_participants` for a given thread.
- `threadIntegration.onTaskCreated` / `onApprovalCreated` already
enrol the owning agent and the virtual user on thread creation,
so the list is populated without any backfill.
- `ThreadPanel` loads participants alongside events and forwards
the agent ids to `MessageComposer.directParticipantIds`. The
composer's existing `directRecipientId` memo picks the first
non-board agent, so replies now target the correct agent — or
surface the "no recipient" notice when the thread has none.
The Board/user member is deliberately excluded from the list the
composer consumes: the composer wants an agent to route to. All
other wiring (wait-state precision, threadId) stays untouched.
This commit is contained in:
1 parent
e53ac36176
commit
0a40c55b3c
6 files changed
+30
-3
No files matched your search
@@ -92,6 +92,7 @@ export const IPC_CHANNELS = {
|
||||
getThread: "agent-company:get-thread",
|
||||
listThreadEvents: "agent-company:list-thread-events",
|
||||
listThreadWaitStates: "agent-company:list-thread-wait-states",
|
||||
listThreadParticipants: "agent-company:list-thread-participants",
|
||||
windowMinimize: "window:minimize",
|
||||
windowMaximize: "window:maximize",
|
||||
windowClose: "window:close",
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import type { z } from "zod";
|
||||
import type { ConversationEventRecord, ConversationThreadRecord, ThreadWaitStateRecord } from "../../types";
|
||||
import type { listThreadEventsSchema, listThreadWaitStatesSchema, threadGetterSchema } from "../schemas-threads";
|
||||
import type { ConversationEventRecord, ConversationParticipantRecord, ConversationThreadRecord, ThreadWaitStateRecord } from "../../types";
|
||||
import type { listThreadEventsSchema, listThreadParticipantsSchema, listThreadWaitStatesSchema, threadGetterSchema } from "../schemas-threads";
|
||||
import type { DesktopResult } from "./common";
|
||||
|
||||
export type ThreadsApi = {
|
||||
getThread: (input: z.infer<typeof threadGetterSchema>) => Promise<DesktopResult<ConversationThreadRecord>>;
|
||||
listThreadEvents: (input: z.infer<typeof listThreadEventsSchema>) => Promise<DesktopResult<ConversationEventRecord[]>>;
|
||||
listThreadWaitStates: (input: z.infer<typeof listThreadWaitStatesSchema>) => Promise<DesktopResult<ThreadWaitStateRecord[]>>;
|
||||
listThreadParticipants: (input: z.infer<typeof listThreadParticipantsSchema>) => Promise<DesktopResult<ConversationParticipantRecord[]>>;
|
||||
};
|
||||
@@ -16,3 +16,8 @@ export const listThreadWaitStatesSchema = z.object({
|
||||
companyId: z.string().uuid(),
|
||||
resolvedOnly: z.boolean().default(false),
|
||||
});
|
||||
|
||||
export const listThreadParticipantsSchema = z.object({
|
||||
companyId: z.string().uuid(),
|
||||
threadId: z.string().uuid(),
|
||||
});
|
||||
Reference in new issue
Block a user