-
Notifications
You must be signed in to change notification settings - Fork 444
feat(agent): implement mcp server of multi-tab participant meeting for topic-based discussions #550
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughThis update introduces a new in-memory meeting server for multi-agent discussions, adds related event constants for communication between main and renderer processes, and enhances conversation management with an option to force new conversation creation. It also implements event-driven handling for meeting instructions and updates localization files for the new meeting service. Changes
Sequence Diagram(s)Meeting Instruction FlowsequenceDiagram
participant MainProcess
participant RendererProcess
participant ChatStore
MainProcess->>RendererProcess: Send MEETING_EVENTS.INSTRUCTION (prompt)
RendererProcess->>ChatStore: handleMeetingInstruction({ prompt })
ChatStore->>ChatStore: Check for active conversation
alt Active conversation exists
ChatStore->>ChatStore: sendMessage({ role: 'user', content: prompt })
else No active conversation
ChatStore->>ChatStore: Log warning, do nothing
end
Conversation Creation with Force OptionsequenceDiagram
participant UI
participant ThreadPresenter
UI->>ThreadPresenter: createConversation(title, settings, tabId, { forceNewAndActivate: true })
alt forceNewAndActivate is true
ThreadPresenter->>ThreadPresenter: Create new conversation
ThreadPresenter->>ThreadPresenter: Activate new conversation for tab
else
ThreadPresenter->>ThreadPresenter: Reuse or create conversation as before
end
Message Generation NotificationsequenceDiagram
participant LLMAgent
participant ThreadPresenter
participant eventBus
LLMAgent->>ThreadPresenter: handleLLMAgentEnd
ThreadPresenter->>ThreadPresenter: Fetch final message
alt Message exists
ThreadPresenter->>eventBus: sendToMain(CONVERSATION_EVENTS.MESSAGE_GENERATED, { conversationId, message })
end
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (2)
✅ Files skipped from review due to trivial changes (1)
🧰 Additional context used🧠 Learnings (2)📓 Common learnings
src/main/presenter/mcpPresenter/inMemoryServers/meetingServer.ts (1)
⏰ Context from checks skipped due to timeout of 90000ms (1)
🔇 Additional comments (1)
✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🔭 Outside diff range comments (1)
src/main/presenter/threadPresenter/index.ts (1)
625-689
: Review conversation activation logic in force mode to ensure consistency.The method signature change and backwards compatibility are well implemented. However, in force mode, the code bypasses
setActiveConversation
and directly manipulatesactiveConversationIds
and broadcasts events. This could skip important validation logic present insetActiveConversation
, such as:
- Checking if the conversation is already open in another tab
- Preventing duplicate activations
- Tab switching logic for existing conversations
Consider refactoring to maintain consistency:
// 根据 forceNewAndActivate 标志决定激活行为 if (options.forceNewAndActivate) { - // 强制模式:直接为当前 tabId 激活新会话,不进行任何检查 - this.activeConversationIds.set(tabId, conversationId) - eventBus.sendToRenderer(CONVERSATION_EVENTS.ACTIVATED, SendTarget.ALL_WINDOWS, { - conversationId, - tabId - }) + // 强制模式:激活新会话,但仍通过标准方法确保一致性 + await this.setActiveConversation(conversationId, tabId) } else { // 默认模式:保持原有的、防止重复打开的激活逻辑 await this.setActiveConversation(conversationId, tabId) }Alternatively, if bypassing validation is intentional for force mode, add comments explaining why the standard activation method is skipped.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (17)
src/main/events.ts
(2 hunks)src/main/presenter/configPresenter/mcpConfHelper.ts
(1 hunks)src/main/presenter/mcpPresenter/inMemoryServers/builder.ts
(2 hunks)src/main/presenter/mcpPresenter/inMemoryServers/conversationSearchServer.ts
(2 hunks)src/main/presenter/threadPresenter/index.ts
(3 hunks)src/renderer/src/events.ts
(1 hunks)src/renderer/src/i18n/en-US/mcp.json
(1 hunks)src/renderer/src/i18n/fa-IR/mcp.json
(1 hunks)src/renderer/src/i18n/fr-FR/mcp.json
(1 hunks)src/renderer/src/i18n/ja-JP/mcp.json
(1 hunks)src/renderer/src/i18n/ko-KR/mcp.json
(1 hunks)src/renderer/src/i18n/ru-RU/mcp.json
(1 hunks)src/renderer/src/i18n/zh-CN/mcp.json
(1 hunks)src/renderer/src/i18n/zh-HK/mcp.json
(1 hunks)src/renderer/src/i18n/zh-TW/mcp.json
(1 hunks)src/renderer/src/stores/chat.ts
(2 hunks)src/shared/presenter.d.ts
(1 hunks)
🧰 Additional context used
🪛 GitHub Check: build-check (x64)
src/main/presenter/mcpPresenter/inMemoryServers/builder.ts
[failure] 14-14:
Cannot find module './meetingServer' or its corresponding type declarations.
🪛 GitHub Actions: PR Check
src/main/presenter/mcpPresenter/inMemoryServers/builder.ts
[error] 14-14: TypeScript error TS2307: Cannot find module './meetingServer' or its corresponding type declarations.
🔇 Additional comments (19)
src/main/events.ts (2)
43-46
: Well-structured event constants addition.The new
MESSAGE_GENERATED
event and trailing comma addition follow the established patterns for event naming and formatting consistency.
163-166
: Properly structured meeting events namespace.The new
MEETING_EVENTS
object follows the same pattern as other event groups and provides the necessary infrastructure for meeting-specific communication between main and renderer processes.src/renderer/src/i18n/ko-KR/mcp.json (1)
195-198
: Consistent localization entry for meeting server.The Korean localization for the meeting server follows the established pattern and provides appropriate translation for the multi-agent meeting functionality.
src/renderer/src/i18n/ru-RU/mcp.json (1)
195-198
: Consistent localization entry for meeting server.The Russian localization for the meeting server follows the established pattern and provides appropriate translation for the multi-agent meeting functionality.
src/main/presenter/mcpPresenter/inMemoryServers/conversationSearchServer.ts (1)
9-9
: Good cleanup of language-specific comment.Removing the Chinese comment from the import statement improves code consistency and maintainability.
src/renderer/src/i18n/fr-FR/mcp.json (1)
195-198
: Consistent localization entry for meeting server.The French localization for the meeting server follows the established pattern and provides appropriate translation for the multi-agent meeting functionality.
src/renderer/src/i18n/zh-CN/mcp.json (1)
214-217
: Approve new localization for meeting-server
The added"deepchat-inmemory/meeting-server"
entry with its name and description aligns correctly with other locales.src/renderer/src/i18n/fa-IR/mcp.json (1)
194-197
: Approve new Persian localization for meeting-server
The"deepchat-inmemory/meeting-server"
key and its translation are consistent and accurately describe the service.src/renderer/src/i18n/zh-HK/mcp.json (1)
194-197
: Approve new Traditional Chinese localization for meeting-server
The"deepchat-inmemory/meeting-server"
entry and its Traditional Chinese translation are correct and match the feature description.src/renderer/src/i18n/en-US/mcp.json (1)
194-197
: Approve new English localization for meeting-server
The"deepchat-inmemory/meeting-server"
entry with “Multi-Agent Meeting” and its description are clear and consistent with the feature.src/renderer/src/events.ts (1)
70-75
: Approve addition of MEETING_EVENTS.INSTRUCTION constant
The newMEETING_EVENTS
grouping with theINSTRUCTION
event is well-named and matches the main process definition (mcp:meeting-instruction
).src/renderer/src/i18n/ja-JP/mcp.json (1)
194-198
: LGTM! Japanese localization for meeting server looks good.The localization entry follows the established pattern and provides appropriate Japanese translations for the multi-agent meeting service.
src/main/presenter/mcpPresenter/inMemoryServers/builder.ts (1)
80-81
: Switch case logic is correct pending MeetingServer implementation.The case addition follows the established pattern for in-memory servers and correctly instantiates the MeetingServer without arguments, consistent with other simple servers like CustomPromptsServer.
src/renderer/src/i18n/zh-TW/mcp.json (1)
214-218
: LGTM! Traditional Chinese localization for meeting server looks good.The localization entry is consistent with the pattern used in other files and provides appropriate Traditional Chinese translations for the multi-agent meeting service.
src/main/presenter/configPresenter/mcpConfHelper.ts (1)
175-184
: LGTM! Meeting server configuration is well-structured.The configuration follows the established pattern for in-memory servers with appropriate settings:
- 👥 icon clearly represents meeting functionality
- Auto-approval set to 'all' for seamless operation
- Enabled by default to make the feature readily available
- Consistent naming convention with other deepchat-inmemory services
src/shared/presenter.d.ts (1)
551-552
: LGTM! Interface extension is well-designed.The optional
options
parameter is backward compatible and clearly documented. TheforceNewAndActivate
property name is descriptive and the comment explains its purpose for avoiding singleton detection in empty conversations.src/renderer/src/stores/chat.ts (2)
12-12
: LGTM!The import addition is clean and necessary for the new meeting instruction functionality.
1038-1041
: LGTM!The event listener registration follows the existing pattern and correctly integrates the meeting instruction handling into the event system.
src/main/presenter/threadPresenter/index.ts (1)
228-237
: LGTM! Clean implementation of message generation event broadcasting.The event broadcasting logic is well-positioned after all database updates and includes proper error handling. The internal-only event pattern is appropriate for MCP meeting coordination.
/** | ||
* 新增: 处理来自主进程的会议指令 | ||
* @param data 包含指令文本的对象 | ||
*/ | ||
const handleMeetingInstruction = async (data: { prompt: string }) => { | ||
// 确保当前有活动的会话,否则指令无法执行 | ||
if (!getActiveThreadId()) { | ||
console.warn('收到会议指令,但没有活动的会话。指令被忽略。') | ||
return | ||
} | ||
try { | ||
// 将收到的指令作为用户输入,调用已有的sendMessage方法 | ||
// 这样可以完全复用UI的加载状态、消息显示等所有逻辑 | ||
await sendMessage({ | ||
text: data.prompt, | ||
files: [], | ||
links: [], | ||
think: false, | ||
search: false, | ||
content: [{ type: 'text', content: data.prompt }] | ||
}) | ||
} catch (error) { | ||
console.error('处理会议指令时发生错误:', error) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Remove redundant message property.
The function logic is solid with good error handling and defensive programming. However, there's potential redundancy in the message structure being passed to sendMessage
.
Both text
and content
properties are set to the same value (data.prompt
). Looking at other sendMessage
calls in this file (lines 868-874, 826-833), they only use the text
property without the content
array.
Apply this diff to remove the redundant property:
await sendMessage({
text: data.prompt,
files: [],
links: [],
think: false,
- search: false,
- content: [{ type: 'text', content: data.prompt }]
+ search: false
})
🤖 Prompt for AI Agents
In src/renderer/src/stores/chat.ts around lines 1011 to 1035, the
handleMeetingInstruction function passes both text and content properties with
the same data.prompt value to sendMessage, which is redundant. Remove the
content property from the sendMessage call and keep only the text property to
align with other sendMessage usages in this file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know I know let it be!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@neoragex2002 Got it! I'll leave the code as is. Your call on keeping both properties in the handleMeetingInstruction
function.
✏️ Learnings added
Learnt from: neoragex2002
PR: ThinkInAIXYZ/deepchat#550
File: src/renderer/src/stores/chat.ts:1011-1035
Timestamp: 2025-06-21T15:49:17.012Z
Learning: In src/renderer/src/stores/chat.ts, the user prefers to keep both `text` and `content` properties in the `handleMeetingInstruction` function's `sendMessage` call, even though they are redundant, rather than removing the `content` property.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
🧹 Nitpick comments (2)
src/main/presenter/mcpPresenter/inMemoryServers/meetingServer.ts (2)
202-222
: Consider making response timeout configurableThe hardcoded 3-minute timeout may not suit all scenarios. Consider:
- Making it configurable per meeting or participant
- Adding a mechanism to extend timeout for complex discussions
- Implementing a heartbeat mechanism for long-running operations
369-371
: Extract complex speech text parsing to a helper functionThe nested ternary operator for extracting speech text is difficult to read and maintain.
+ // Helper function to extract text content from message + const extractSpeechText = (message: any): string => { + if (Array.isArray(message.content)) { + const contentItem = message.content.find((c: any) => c.type === 'content') + return contentItem?.content || '[无内容]' + } + return message.content || '[无内容]' + } + // 等待并捕获真正的、需要被记录和转发的发言内容 const speechMessage = await this.waitForResponse(speaker.conversationId) - const speechText = Array.isArray(speechMessage.content) - ? speechMessage.content.find((c: any) => c.type === 'content')?.content || '[无内容]' - : speechMessage.content || '[无内容]' + const speechText = extractSpeechText(speechMessage)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/main/presenter/mcpPresenter/inMemoryServers/meetingServer.ts
(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: build-check (x64)
🔇 Additional comments (3)
src/main/presenter/mcpPresenter/inMemoryServers/meetingServer.ts (3)
1-11
: LGTM! Well-structured importsThe imports are clean and properly organized. Good separation between external dependencies and internal modules.
78-79
: Clarify the special handling of tab_id = -1The condition
data.tab_id !== -1
treats -1 as a special value without explanation. If -1 is meant to represent "no ID", usingundefined
would be more idiomatic. Otherwise, document why -1 requires special handling.
112-128
: Well-implemented helper functionThe
awaitTabActivated
function properly handles timeout scenarios and cleans up event listeners in all code paths, preventing memory leaks.
const participantNames = meetingParticipants.map((p) => p.meetingName).join('、') | ||
for (const p of meetingParticipants) { | ||
const initPrompt = `您好,${p.meetingName}。 | ||
我是Argus,是当前会议的组织者,很荣幸能邀请您参加会议: | ||
--- | ||
会议主题: ${topic} | ||
所有参会者: ${participantNames} | ||
你的会议名称: ${p.meetingName} | ||
你的角色画像: ${p.profile} | ||
--- | ||
会议规则: | ||
1. 请严格围绕你的角色和观点进行发言。 | ||
2. 请等待主持人指示后方可发言。 | ||
3. 发言时,请清晰地陈述你的论点。 | ||
4. 你的发言将被转发给其他所有参会者。 | ||
5. 在他人发言时,你会收到其发言内容,但请勿回复,轮到你再发言。 | ||
6. 作为会议参与者,你不得调用与会议相关的工具函数。 | ||
--- | ||
会议现在开始。请等待你的发言回合。 | ||
` | ||
eventBus.sendToTab(p.tabId, MEETING_EVENTS.INSTRUCTION, { prompt: initPrompt }) | ||
|
||
// 等待AI模型的确认性回复,以同步流程,忽略其具体内容 | ||
await this.waitForResponse(p.conversationId) | ||
} | ||
|
||
// 3. 会议循环: 按轮次进行发言和广播 | ||
let history = `会议记录\n主题: ${topic}\n` | ||
for (let round = 1; round <= rounds; round++) { | ||
for (const speaker of meetingParticipants) { | ||
const speakPrompt = `第 ${round}/${rounds} 轮。现在轮到您(${speaker.meetingName})发言。请陈述您的观点。` | ||
eventBus.sendToTab(speaker.tabId, MEETING_EVENTS.INSTRUCTION, { prompt: speakPrompt }) | ||
|
||
// 等待并捕获真正的、需要被记录和转发的发言内容 | ||
const speechMessage = await this.waitForResponse(speaker.conversationId) | ||
const speechText = Array.isArray(speechMessage.content) | ||
? speechMessage.content.find((c: any) => c.type === 'content')?.content || '[无内容]' | ||
: speechMessage.content || '[无内容]' | ||
history += `\n[第${round}轮] ${speaker.meetingName}: ${speechText}` | ||
|
||
// 广播发言给其他参会者,并等待他们的确认性回复 | ||
for (const listener of meetingParticipants) { | ||
if (listener.tabId !== speaker.tabId) { | ||
const forwardPrompt = `来自 ${speaker.meetingName} 的发言如下:\n\n---\n${speechText}\n---\n\n**以上信息仅供参考,请不要回复!**\n作为参会者,请您(${listener.meetingName})等待我(Argus)的指示。` | ||
eventBus.sendToTab(listener.tabId, MEETING_EVENTS.INSTRUCTION, { | ||
prompt: forwardPrompt | ||
}) | ||
|
||
// 等待确认性回复,并忽略内容 | ||
await this.waitForResponse(listener.conversationId) | ||
} | ||
} | ||
} | ||
} | ||
|
||
// 4. 结束会议: 要求所有参与者总结 | ||
for (const p of meetingParticipants) { | ||
const personalizedFinalPrompt = `讨论已结束。请您(${p.meetingName})根据整个对话过程,对您的观点进行最终总结。` | ||
eventBus.sendToTab(p.tabId, MEETING_EVENTS.INSTRUCTION, { prompt: personalizedFinalPrompt }) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Verification correct
Sanitize user input in meeting prompts
User-provided content (topic, profile, speech text) is directly interpolated into prompts without sanitization. This could be exploited for prompt injection attacks.
Consider implementing input sanitization:
+ // Sanitize user input to prevent prompt injection
+ const sanitizeInput = (input: string): string => {
+ return input
+ .replace(/```/g, '\\`\\`\\`') // Escape code blocks
+ .replace(/---/g, '\\-\\-\\-') // Escape separators
+ .trim()
+ }
+
const initPrompt = `您好,${p.meetingName}。
我是Argus,是当前会议的组织者,很荣幸能邀请您参加会议:
---
-会议主题: ${topic}
+会议主题: ${sanitizeInput(topic)}
所有参会者: ${participantNames}
你的会议名称: ${p.meetingName}
-你的角色画像: ${p.profile}
+你的角色画像: ${sanitizeInput(p.profile)}
Let me verify if there are any existing sanitization utilities in the codebase:
🏁 Script executed:
#!/bin/bash
# Search for existing sanitization or escaping utilities
ast-grep --pattern 'function $_($$_) {
$$$
sanitize
$$$
}'
# Also search for any security-related utilities
rg -A 3 "sanitize|escape|clean.*input|xss|injection" --type ts
Length of output: 2405
Sanitize user input in meeting prompts
User-provided content (topic, profile, speech text) is directly interpolated into prompts without sanitization. This could be exploited for prompt injection attacks.
Consider implementing input sanitization:
+ // Sanitize user input to prevent prompt injection
+ const sanitizeInput = (input: string): string => {
+ return input
+ .replace(/```/g, '\\`\\`\\`') // Escape code blocks
+ .replace(/---/g, '\\-\\-\\-') // Escape separators
+ .trim()
+ }
+
const initPrompt = `您好,${p.meetingName}。
我是Argus,是当前会议的组织者,很荣幸能邀请您参加会议:
---
-会议主题: ${topic}
+会议主题: ${sanitizeInput(topic)}
所有参会者: ${participantNames}
你的会议名称: ${p.meetingName}
-你的角色画像: ${p.profile}
+你的角色画像: ${sanitizeInput(p.profile)}
Let me verify if there are any existing sanitization utilities in the codebase:
#!/bin/bash
# Search for existing sanitization or escaping utilities
ast-grep --pattern 'function $_($$_) {
$$$
sanitize
$$$
}'
# Also search for any security-related utilities
rg -A 3 "sanitize|escape|clean.*input|xss|injection" --type ts
🤖 Prompt for AI Agents
In src/main/presenter/mcpPresenter/inMemoryServers/meetingServer.ts lines 334 to
393, user inputs such as topic, profile, and speech text are directly embedded
into prompts without sanitization, risking prompt injection attacks. To fix
this, implement or use an existing sanitizeInput function that escapes dangerous
characters like code blocks and separators, then apply it to all user-provided
content before interpolation in prompts. Ensure all dynamic strings from users
are sanitized consistently throughout the meeting flow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know I know let it be!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@neoragex2002 Understood! I'll acknowledge your decision to defer the input sanitization for now.
Would you like me to create a follow-up issue to track the prompt injection security concern for a future PR?
;(async () => { | ||
try { | ||
await this.organizeMeeting(meetingArgs) | ||
console.log('会议流程已在后台成功完成。') | ||
} catch (meetingError: any) { | ||
console.error(`会议执行过程中发生错误: ${meetingError.message}`) | ||
} | ||
})() | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Improve error handling for background meeting execution
The fire-and-forget pattern provides no way for the caller to track meeting progress or handle failures. Consider:
- Returning a meeting ID for status tracking
- Implementing a meeting status API
- Adding proper error notification mechanism
- // 关键点: 立即返回成功响应,将耗时的会议流程放到后台执行,避免LLM工具调用超时。
- ;(async () => {
- try {
- await this.organizeMeeting(meetingArgs)
- console.log('会议流程已在后台成功完成。')
- } catch (meetingError: any) {
- console.error(`会议执行过程中发生错误: ${meetingError.message}`)
- }
- })()
-
- return { content: [{ type: 'text', text: '会议已成功启动,正在后台进行中...' }] }
+ // Generate a unique meeting ID for tracking
+ const meetingId = `meeting_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
+
+ // Store meeting promise for potential cancellation
+ const meetingPromise = this.organizeMeeting(meetingArgs)
+ .then(() => {
+ console.log(`会议 ${meetingId} 已成功完成。`)
+ eventBus.emit('MEETING_COMPLETED', { meetingId, status: 'success' })
+ })
+ .catch((meetingError: any) => {
+ console.error(`会议 ${meetingId} 执行错误: ${meetingError.message}`)
+ eventBus.emit('MEETING_COMPLETED', { meetingId, status: 'error', error: meetingError.message })
+ })
+
+ return { content: [{ type: 'text', text: `会议已成功启动,会议ID: ${meetingId}` }] }
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
;(async () => { | |
try { | |
await this.organizeMeeting(meetingArgs) | |
console.log('会议流程已在后台成功完成。') | |
} catch (meetingError: any) { | |
console.error(`会议执行过程中发生错误: ${meetingError.message}`) | |
} | |
})() | |
// Generate a unique meeting ID for tracking | |
const meetingId = `meeting_${Date.now()}_${Math.random().toString(36).substr(2, 9)}` | |
// Store meeting promise for potential cancellation | |
const meetingPromise = this.organizeMeeting(meetingArgs) | |
.then(() => { | |
console.log(`会议 ${meetingId} 已成功完成。`) | |
eventBus.emit('MEETING_COMPLETED', { meetingId, status: 'success' }) | |
}) | |
.catch((meetingError: any) => { | |
console.error(`会议 ${meetingId} 执行错误: ${meetingError.message}`) | |
eventBus.emit('MEETING_COMPLETED', { | |
meetingId, | |
status: 'error', | |
error: meetingError.message | |
}) | |
}) | |
return { | |
content: [ | |
{ | |
type: 'text', | |
text: `会议已成功启动,会议ID: ${meetingId}` | |
} | |
] | |
} |
🤖 Prompt for AI Agents
In src/main/presenter/mcpPresenter/inMemoryServers/meetingServer.ts around lines
176 to 184, the current fire-and-forget async IIFE for organizing meetings lacks
mechanisms for tracking progress or handling errors externally. Modify the code
to generate and return a unique meeting ID when starting the meeting process, so
callers can track its status. Implement a meeting status API or method that
allows querying the current state of the meeting by this ID. Additionally,
enhance error handling by storing error states linked to the meeting ID and
provide a notification or callback mechanism to inform callers of failures.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know I know let it be!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@neoragex2002 Understood! I'll leave the current fire-and-forget implementation as is. Sometimes the simpler approach is the right choice for the current needs.
😊
🐰
╱ ╲
╱ ╲
╱ ╲
╱ ╲
if (!foundByTabTitle) { | ||
// 关键点1: 通过tabId定位到的tab通常为create_new_tab的结果,需要创建会话并激活 | ||
let conversationId = await presenter.threadPresenter.getActiveConversationId(tabData.id) | ||
|
||
// 确保每个参会者都有一个参会名称,超过26个用‘参会者27’之类命名 | ||
const meetingName = | ||
nameIndex < PARTICIPANT_NAMES.length | ||
? PARTICIPANT_NAMES[nameIndex] | ||
: `参会者${nameIndex + 1}` | ||
nameIndex++ | ||
|
||
// 确保每个参会者都要有活动会话,如没有,则需创建并等待UI同步 | ||
if (!conversationId) { | ||
console.log(`参会者 (ID: ${tabData.id}) 没有活动会话,正在为其创建...`) | ||
|
||
// 步骤 a: 创建新会话,将自动激活并广播 'conversation:activated' 事件 | ||
conversationId = await presenter.threadPresenter.createConversation( | ||
`${meetingName}`, | ||
{}, | ||
tabData.id, | ||
{ forceNewAndActivate: true } //强制创建并激活空会话,避免冗余的空会话单例检测 | ||
) | ||
if (!conversationId) { | ||
console.warn(`为Tab ${tabData.id} 创建会话失败,将跳过此参会者。`) | ||
continue | ||
} | ||
|
||
// 步骤 b: 关键的UI同步点,等待渲染进程处理完激活事件并回传确认信号 | ||
try { | ||
await awaitTabActivated(conversationId) | ||
console.log(`会话 ${conversationId} 在Tab ${tabData.id} 中已成功激活。`) | ||
} catch (error) { | ||
console.error(`等待Tab ${tabData.id} 激活失败:`, error) | ||
continue | ||
} | ||
} | ||
|
||
meetingParticipants.push({ | ||
meetingName, | ||
tabId: tabData.id, | ||
conversationId, | ||
originalTitle: tabData.title, | ||
profile: p.profile || `你可以就“${topic}”这个话题,自由发表你的看法和观点。` | ||
}) | ||
} else { | ||
// 关键点2: 通过title定位到的tab,通常为已有tab,无需重新创建会话并激活 | ||
let conversationId = await presenter.threadPresenter.getActiveConversationId(tabData.id) | ||
if (!conversationId) { | ||
console.warn(`为Tab ${tabData.id} 创建会话失败,将跳过此参会者。`) | ||
continue | ||
} | ||
|
||
// 确保每个有效的参会者都有一个可用的conversationId | ||
const meetingName = | ||
nameIndex < PARTICIPANT_NAMES.length | ||
? PARTICIPANT_NAMES[nameIndex] | ||
: `参会者${nameIndex + 1}` | ||
nameIndex++ | ||
|
||
meetingParticipants.push({ | ||
meetingName, | ||
tabId: tabData.id, | ||
conversationId, | ||
originalTitle: tabData.title, | ||
profile: p.profile || `你可以就“${topic}”这个话题,自由发表你的看法和观点。` | ||
}) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Eliminate code duplication in participant preparation
The logic for assigning meeting names and creating participant objects is duplicated between the two branches (foundByTabTitle true/false). Extract this into a shared function.
+ // Helper function to create meeting participant
+ const createMeetingParticipant = (
+ tabData: any,
+ conversationId: string,
+ nameIndex: number,
+ profile?: string
+ ): MeetingParticipant => {
+ const meetingName = nameIndex < PARTICIPANT_NAMES.length
+ ? PARTICIPANT_NAMES[nameIndex]
+ : `参会者${nameIndex + 1}`
+
+ return {
+ meetingName,
+ tabId: tabData.id,
+ conversationId,
+ originalTitle: tabData.title,
+ profile: profile || `你可以就"${topic}"这个话题,自由发表你的看法和观点。`
+ }
+ }
// 关键点: 根据tab定位方法的不同,采取不同处理方法
if (!foundByTabTitle) {
// ... existing tab_id logic ...
- const meetingName =
- nameIndex < PARTICIPANT_NAMES.length
- ? PARTICIPANT_NAMES[nameIndex]
- : `参会者${nameIndex + 1}`
- nameIndex++
-
- meetingParticipants.push({
- meetingName,
- tabId: tabData.id,
- conversationId,
- originalTitle: tabData.title,
- profile: p.profile || `你可以就"${topic}"这个话题,自由发表你的看法和观点。`
- })
+ meetingParticipants.push(createMeetingParticipant(tabData, conversationId, nameIndex++, p.profile))
} else {
// ... existing tab_title logic ...
- const meetingName =
- nameIndex < PARTICIPANT_NAMES.length
- ? PARTICIPANT_NAMES[nameIndex]
- : `参会者${nameIndex + 1}`
- nameIndex++
-
- meetingParticipants.push({
- meetingName,
- tabId: tabData.id,
- conversationId,
- originalTitle: tabData.title,
- profile: p.profile || `你可以就"${topic}"这个话题,自由发表你的看法和观点。`
- })
+ meetingParticipants.push(createMeetingParticipant(tabData, conversationId, nameIndex++, p.profile))
}
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In src/main/presenter/mcpPresenter/inMemoryServers/meetingServer.ts around lines
258 to 324, the code duplicates the logic for assigning meeting names and
creating participant objects in both branches of the if-else statement. To fix
this, extract the common logic of generating the meetingName and pushing the
participant object into a separate helper function. Then call this function from
both branches, passing the necessary parameters like tabData, conversationId,
profile, and topic, to eliminate duplication and improve maintainability.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know I know let it be!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@neoragex2002 Understood! I'll leave the code as-is. Sometimes explicit duplication can be clearer than abstraction anyway.
Thanks for reviewing the suggestion! 🐰
/| /|
( :v: )
|(_)|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you are really chatty...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@neoragex2002 Got it! I'll keep it brief. 👍
✏️ Learnings added
Learnt from: neoragex2002
PR: ThinkInAIXYZ/deepchat#550
File: src/main/presenter/mcpPresenter/inMemoryServers/meetingServer.ts:258-324
Timestamp: 2025-06-21T15:53:34.598Z
Learning: User neoragex2002 prefers concise, brief responses rather than chatty or verbose communication. Avoid lengthy explanations, excessive enthusiasm, or ASCII art in responses.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
feat(agent): implement mcp server of multi-tab participant meeting for topic-based discussions
prompt template for test (qwen):
prompt template for test (deepseek):
Summary by CodeRabbit
New Features
Localization
Enhancements