feat: discussion guide file path + initiator speaks first

1. create-discussion-channel now accepts optional discussionGuidePath
   parameter as alternative to inline discussionGuide text. Either
   one is required; file path is read at tool execution time.

2. Discussion channel speaker list now places the initiator first,
   ensuring they set context before other participants respond.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
zhi
2026-04-18 17:29:55 +00:00
parent ca7b47e683
commit 18b0180429
2 changed files with 26 additions and 5 deletions

View File

@@ -252,8 +252,13 @@ export default {
await sendModeratorMessage(live.moderatorBotToken, channelId, discussionGuide, api.logger)
.catch(() => undefined);
// Initialize speaker list
// Initialize speaker list (initiator first)
const agentIds = await fetchVisibleChannelBotAccountIds(api, channelId, identityRegistry);
const initiatorIdx = agentIds.indexOf(initiatorAgentId);
if (initiatorIdx > 0) {
agentIds.splice(initiatorIdx, 1);
agentIds.unshift(initiatorAgentId);
}
const speakers = agentIds
.map((aid) => {
const entry = identityRegistry.findByAgentId(aid);

View File

@@ -224,19 +224,35 @@ export function registerDirigentTools(deps: ToolDeps): void {
callbackGuildId: { type: "string", description: "Guild ID of your current channel (for callback after discussion)" },
callbackChannelId: { type: "string", description: "Channel ID to post the summary to after discussion completes" },
name: { type: "string", description: "Discussion channel name" },
discussionGuide: { type: "string", description: "Topic, goals, and completion criteria for the discussion" },
discussionGuide: { type: "string", description: "Topic, goals, and completion criteria for the discussion (inline text)" },
discussionGuidePath: { type: "string", description: "Path to a file containing the discussion guide (alternative to inline discussionGuide)" },
participants: { type: "array", items: { type: "string" }, description: "Discord user IDs of participating agents" },
},
required: ["callbackGuildId", "callbackChannelId", "name", "discussionGuide", "participants"],
required: ["callbackGuildId", "callbackChannelId", "name", "participants"],
},
execute: async (_toolCallId: string, params: unknown) => {
const p = params as {
callbackGuildId: string;
callbackChannelId: string;
name: string;
discussionGuide: string;
discussionGuide?: string;
discussionGuidePath?: string;
participants: string[];
};
// Resolve discussion guide: inline text or file path
let resolvedGuide = p.discussionGuide || "";
if (!resolvedGuide && p.discussionGuidePath) {
try {
const { readFileSync } = await import("node:fs");
resolvedGuide = readFileSync(p.discussionGuidePath, "utf8").trim();
} catch (err) {
return errorResult(`Failed to read discussion guide file: ${String(err)}`);
}
}
if (!resolvedGuide) {
return errorResult("Either discussionGuide or discussionGuidePath is required");
}
const initiatorAgentId = ctx?.agentId;
if (!initiatorAgentId) {
return errorResult("Cannot resolve initiator agentId from session");
@@ -291,7 +307,7 @@ export function registerDirigentTools(deps: ToolDeps): void {
initiatorAgentId,
callbackGuildId: p.callbackGuildId,
callbackChannelId: p.callbackChannelId,
discussionGuide: p.discussionGuide,
discussionGuide: resolvedGuide,
participants: p.participants,
});