-
Notifications
You must be signed in to change notification settings - Fork 67
feat(meeting): add intelligent meeting booking skill and interactive form #826
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
base: main
Are you sure you want to change the base?
Conversation
…form Add a new meeting-booking skill that allows users to book meetings through natural language. The system identifies meeting intent, fetches available resources, and generates an interactive form. Backend changes: - Add meeting-booking skill with SKILL.md, provider.py, get_meeting_resources.py - Support mock data for development/testing when API is not configured - Tool fetches available rooms and participants from remote API Frontend changes: - Add MeetingBookingForm component with interactive room and participant selection - Add meeting booking form parsing in MessageBubble for automatic detection - Add meeting.ts API service for remote booking calls - Add TypeScript types for meeting booking data structures - Add i18n translations (en/zh-CN) for meeting booking UI The flow: 1. User sends natural language request (e.g., "schedule a meeting at 3pm") 2. AI calls get_meeting_resources tool to fetch available rooms/participants 3. AI generates structured Markdown form with recommendations 4. Frontend renders interactive form with pre-filled defaults 5. User confirms, frontend calls remote booking API directly 6. Result is sent back to AI for friendly confirmation message
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. 📝 WalkthroughWalkthroughAdds a meeting-booking feature: backend skill/tool/provider to fetch meeting resources, new meeting booking API and schemas, frontend API/types, an inline MeetingBookingForm React component with message parsing, i18n entries (en/zh-CN), planning docs, and an env backup file. Changes
Sequence Diagram(s)sequenceDiagram
participant User as User
participant MB as MessageBubble
participant Form as MeetingBookingForm
participant API as Frontend Meeting API
participant Backend as Meeting Service
User->>MB: receives AI message containing booking form
MB->>MB: parseMeetingBookingForm(content)
alt form detected
MB->>Form: render(parsed data, rawContent)
User->>Form: fill fields & confirm
Form->>API: POST /book (CreateMeetingRequest)
API->>Backend: forward request or use mock backend
Backend-->>API: return BookingResponse
API-->>Form: return result
Form->>User: show toast and emit formatted markdown
else no form
MB->>MB: render normal message
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ 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. Comment |
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.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1052c641e9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // Check if this booking form has been submitted | ||
| const isSubmitted = useMemo(() => { | ||
| if (!selectedTaskDetail?.subtasks || selectedTaskDetail.subtasks.length === 0) return false; | ||
|
|
||
| // Check if there's any USER message after the current message index | ||
| const subtasksAfter = selectedTaskDetail.subtasks.slice(currentMessageIndex + 1); | ||
| return subtasksAfter.some((sub: { role: string }) => sub.role === 'USER'); |
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.
Use unified messages to mark the form submitted
The submission check relies on selectedTaskDetail.subtasks, which is explicitly stale compared to the live message stream; the current message index is derived from the unified messages list, so the slice can point at the wrong offset or never see the user reply. In practice, after the user clicks “Confirm Booking,” the WebSocket message updates messages but selectedTaskDetail.subtasks may not refresh, leaving isSubmitted false and the form still enabled—allowing duplicate booking requests. Consider using the unified message source (or local submission state) instead of selectedTaskDetail.subtasks for this gating.
Useful? React with 👍 / 👎.
| const roomOptionRegex = /-\s*\[([✓xX* ]?)\]\s*`([^`]+)`\s*-\s*([^\n(]+)(?:\s*\((?:Recommended|推荐)\))?/g; | ||
| let roomMatch; |
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.
Preserve full room names when parsing options
The room/participant option regex captures names with ([^ (]+), which truncates everything after the first (. In the documented form example, names like “会议室A (101)” will be parsed as just “会议室A,” and multiple rooms with different suffixes become indistinguishable in the UI. That can lead to users selecting or booking the wrong room/participant because the displayed names no longer match the options. Consider matching the full name and stripping only the optional “(Recommended/推荐)” tag.
Useful? React with 👍 / 👎.
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: 3
🧹 Nitpick comments (5)
frontend/src/apis/meeting.ts (1)
102-111: Mock cancellation missing async delay for consistency.
mockCreateMeetingsimulates network delay withsetTimeout, but the mock path incancelMeetingreturns synchronously. Consider adding a similar delay for consistent mock behavior during testing.🔎 Suggested consistency fix
// If using mock endpoint, return mock success if (baseEndpoint === '/api/meeting/mock') { + await new Promise(resolve => setTimeout(resolve, 300)) return { success: true, message: `Meeting ${meetingId} has been cancelled.`, - }; + } }frontend/src/features/tasks/components/meeting/MeetingBookingForm.tsx (2)
79-92: Hardcoded locale bypasses i18n.The
formatDateTimeForDisplayfunction hardcodes'zh-CN'locale, which will display dates in Chinese format regardless of the user's language preference. Consider using the current locale from i18n or browser settings.🔎 Suggested fix
const formatDateTimeForDisplay = (isoString: string) => { try { const date = new Date(isoString); - return date.toLocaleString('zh-CN', { + // Use undefined to respect user's browser locale, or get from i18n + return date.toLocaleString(undefined, { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', }); } catch { return isoString; } };
141-156: Hardcoded Chinese strings in booking result messages.The result messages contain hardcoded Chinese text that bypasses the i18n system. While these messages are formatted as markdown for the AI, they are user-facing and should respect the user's language preference for consistency.
🔎 Suggested approach
Consider using translation keys for the result message construction:
if (result.success) { - resultMessage = `## ✅ 会议预约成功 (Meeting Booked Successfully)\n\n`; - resultMessage += `**会议ID**: ${result.meetingId || 'N/A'}\n`; - resultMessage += `**会议名称**: ${title}\n`; + resultMessage = `## ✅ ${t('meeting.result_success_title')}\n\n`; + resultMessage += `**${t('meeting.meeting_id')}**: ${result.meetingId || 'N/A'}\n`; + resultMessage += `**${t('meeting.meeting_name')}**: ${title}\n`; // ... continue for other fields }Add corresponding keys to your i18n locale files.
backend/init_data/skills/meeting-booking/get_meeting_resources.py (2)
142-155: Non-200 API responses are silently treated as empty arrays.When the rooms or participants endpoints return non-200 status codes, the code silently falls back to empty arrays without logging. This could mask API issues and make debugging difficult in production.
🔎 Suggested fix
rooms_data = ( rooms_response.json() if rooms_response.status_code == 200 else [] ) + if rooms_response.status_code != 200: + logger.warning( + f"[MeetingBookingTool] Rooms API returned {rooms_response.status_code}" + ) # Fetch participants list participants_response = await client.get( f"{api_base_url}/participants", headers=headers, ) participants_data = ( participants_response.json() if participants_response.status_code == 200 else [] ) + if participants_response.status_code != 200: + logger.warning( + f"[MeetingBookingTool] Participants API returned {participants_response.status_code}" + )
177-182: Unusedstart_timeandend_timeparameters in mock data method.The static analysis correctly identifies that
start_timeandend_timeare unused in_get_mock_data. Since mock data doesn't implement time-based filtering, consider prefixing with underscore to indicate intentional non-use.🔎 Suggested fix
def _get_mock_data( self, date: str, - start_time: Optional[str], - end_time: Optional[str], + _start_time: Optional[str], + _end_time: Optional[str], ) -> str:
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (10)
backend/init_data/skills/meeting-booking/SKILL.mdbackend/init_data/skills/meeting-booking/get_meeting_resources.pybackend/init_data/skills/meeting-booking/provider.pyfrontend/src/apis/meeting.tsfrontend/src/features/tasks/components/meeting/MeetingBookingForm.tsxfrontend/src/features/tasks/components/meeting/index.tsfrontend/src/features/tasks/components/message/MessageBubble.tsxfrontend/src/i18n/locales/en/chat.jsonfrontend/src/i18n/locales/zh-CN/chat.jsonfrontend/src/types/api.ts
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{py,ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{py,ts,tsx,js,jsx}: All code comments MUST be written in English
File size MUST NOT exceed 1000 lines - split into multiple sub-modules if exceeded
Function length SHOULD NOT exceed 50 lines (preferred)
Files:
frontend/src/features/tasks/components/meeting/index.tsfrontend/src/features/tasks/components/meeting/MeetingBookingForm.tsxbackend/init_data/skills/meeting-booking/provider.pyfrontend/src/apis/meeting.tsfrontend/src/types/api.tsbackend/init_data/skills/meeting-booking/get_meeting_resources.pyfrontend/src/features/tasks/components/message/MessageBubble.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
TypeScript/React MUST use strict mode, functional components, Prettier for formatting, ESLint for linting, single quotes, and no semicolons
Files:
frontend/src/features/tasks/components/meeting/index.tsfrontend/src/features/tasks/components/meeting/MeetingBookingForm.tsxfrontend/src/apis/meeting.tsfrontend/src/types/api.tsfrontend/src/features/tasks/components/message/MessageBubble.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
TypeScript MUST use
constoverlet, never usevar
Files:
frontend/src/features/tasks/components/meeting/index.tsfrontend/src/features/tasks/components/meeting/MeetingBookingForm.tsxfrontend/src/apis/meeting.tsfrontend/src/types/api.tsfrontend/src/features/tasks/components/message/MessageBubble.tsx
frontend/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
frontend/src/**/*.{ts,tsx}: MUST useuseTranslationhook imported from@/hooks/useTranslation, not fromreact-i18next
MUST use single namespace withuseTranslation()- never use array format likeuseTranslation(['common', 'groups'])
Frontend message data MUST always usemessagesfromuseUnifiedMessages()hook as the single source of truth for displaying messages - never useselectedTaskDetail.subtasks
Frontend i18n translation keys MUST use current namespace formatt('key.subkey')for keys within namespace andt('namespace:key.subkey')for cross-namespace keys
Files:
frontend/src/features/tasks/components/meeting/index.tsfrontend/src/features/tasks/components/meeting/MeetingBookingForm.tsxfrontend/src/apis/meeting.tsfrontend/src/types/api.tsfrontend/src/features/tasks/components/message/MessageBubble.tsx
frontend/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Frontend MUST only use
NEXT_PUBLIC_*environment variables for client-safe values
Files:
frontend/src/features/tasks/components/meeting/index.tsfrontend/src/features/tasks/components/meeting/MeetingBookingForm.tsxfrontend/src/apis/meeting.tsfrontend/src/types/api.tsfrontend/src/features/tasks/components/message/MessageBubble.tsx
**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
**/*.py: Python code MUST follow PEP 8, use Black formatter with line length 88, and isort for imports
Python code MUST include type hints
Python functions and classes MUST have descriptive names and docstrings for public functions/classes
Python MUST extract magic numbers to named constants
Files:
backend/init_data/skills/meeting-booking/provider.pybackend/init_data/skills/meeting-booking/get_meeting_resources.py
backend/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
backend/**/*.py: Python backend module imports MUST useuv runprefix when executing commands
Task and Workspace resources MUST use TaskResource model fromapp.models.task, not the Kind model
Ghost, Model, Shell, Bot, Team, and Skill CRDs MUST use Kind model fromapp.models.kind
Files:
backend/init_data/skills/meeting-booking/provider.pybackend/init_data/skills/meeting-booking/get_meeting_resources.py
frontend/src/types/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
TypeScript types MUST be organized in
src/types/directory
Files:
frontend/src/types/api.ts
🧠 Learnings (3)
📚 Learning: 2025-12-18T02:09:09.776Z
Learnt from: CR
Repo: wecode-ai/Wegent PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-18T02:09:09.776Z
Learning: Applies to frontend/src/**/*.tsx : Frontend component files named with CRD terms: team-list.tsx, bot-form.tsx, model-selector.tsx
Applied to files:
frontend/src/features/tasks/components/meeting/index.tsfrontend/src/features/tasks/components/meeting/MeetingBookingForm.tsx
📚 Learning: 2025-12-18T02:09:09.776Z
Learnt from: CR
Repo: wecode-ai/Wegent PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-18T02:09:09.776Z
Learning: Applies to frontend/src/components/**/*.tsx : Extract reusable UI logic: place shared business components in `src/components/common/`, and pure UI components in `src/components/ui/` (shadcn/ui)
Applied to files:
frontend/src/features/tasks/components/meeting/index.ts
📚 Learning: 2025-12-18T02:09:09.776Z
Learnt from: CR
Repo: wecode-ai/Wegent PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-18T02:09:09.776Z
Learning: Applies to frontend/src/i18n/zh-CN.json : Frontend i18n Chinese values (zh-CN) MUST use UI terms: `'智能体列表'`, `'机器人配置'`
Applied to files:
frontend/src/i18n/locales/zh-CN/chat.json
🧬 Code graph analysis (4)
backend/init_data/skills/meeting-booking/provider.py (3)
backend/app/chat_shell/skills/context.py (1)
SkillToolContext(16-49)backend/app/chat_shell/skills/provider.py (1)
SkillToolProvider(19-110)backend/init_data/skills/meeting-booking/get_meeting_resources.py (1)
GetMeetingResourcesTool(41-307)
frontend/src/apis/meeting.ts (2)
frontend/src/apis/client.ts (1)
request(57-121)frontend/src/types/api.ts (2)
CreateMeetingRequest(626-632)MeetingBookingResponse(619-624)
backend/init_data/skills/meeting-booking/get_meeting_resources.py (1)
backend/init_data/skills/wiki_submit/wiki_submit.js (1)
headers(161-164)
frontend/src/features/tasks/components/message/MessageBubble.tsx (2)
frontend/src/types/api.ts (1)
MeetingBookingFormData(596-617)frontend/src/features/tasks/components/meeting/MeetingBookingForm.tsx (1)
MeetingBookingForm(31-381)
🪛 Biome (2.1.2)
frontend/src/features/tasks/components/message/MessageBubble.tsx
[error] 1046-1046: The regular expression includes this negated empty character class.
Negated empty character classes match anything.
If you want to match against [, escape it [.
Otherwise, remove the character class or fill it.
(lint/correctness/noEmptyCharacterClassInRegex)
[error] 1068-1068: The regular expression includes this negated empty character class.
Negated empty character classes match anything.
If you want to match against [, escape it [.
Otherwise, remove the character class or fill it.
(lint/correctness/noEmptyCharacterClassInRegex)
[error] 1100-1100: The regular expression includes this negated empty character class.
Negated empty character classes match anything.
If you want to match against [, escape it [.
Otherwise, remove the character class or fill it.
(lint/correctness/noEmptyCharacterClassInRegex)
🪛 markdownlint-cli2 (0.18.1)
backend/init_data/skills/meeting-booking/SKILL.md
16-16: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
21-21: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
🪛 Ruff (0.14.10)
backend/init_data/skills/meeting-booking/provider.py
74-74: Avoid specifying long messages outside the exception class
(TRY003)
backend/init_data/skills/meeting-booking/get_meeting_resources.py
180-180: Unused method argument: start_time
(ARG002)
181-181: Unused method argument: end_time
(ARG002)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: E2E Tests (Shard 3/3)
- GitHub Check: E2E Tests (Shard 2/3)
- GitHub Check: E2E Tests (Shard 1/3)
- GitHub Check: Test wegent CLI Integration
- GitHub Check: Test Frontend
🔇 Additional comments (13)
frontend/src/features/tasks/components/meeting/index.ts (1)
1-5: LGTM!Clean barrel export following standard module organization patterns.
backend/init_data/skills/meeting-booking/SKILL.md (1)
1-128: LGTM!Comprehensive skill documentation with clear usage flow, form format specification, and error handling guidance. The markdown lint warnings about list indentation are false positives as they refer to valid YAML frontmatter syntax.
frontend/src/features/tasks/components/message/MessageBubble.tsx (2)
37-43: LGTM!Clean imports following the existing patterns in the file.
1003-1135: Well-structured parsing function with comprehensive field extraction.The
parseMeetingBookingFormfunction correctly:
- Detects the meeting booking header pattern
- Extracts title, time, duration, room options, and participants
- Sets default selections for recommended options
- Validates minimum required data before returning
frontend/src/i18n/locales/zh-CN/chat.json (1)
390-413: LGTM!Complete Chinese translations for the meeting booking feature. The keys follow existing namespace conventions and include proper interpolation syntax for dynamic values.
frontend/src/i18n/locales/en/chat.json (1)
390-413: LGTM!Complete English translations for the meeting booking feature, consistent with the Chinese locale structure.
backend/init_data/skills/meeting-booking/provider.py (1)
21-108: LGTM!Well-structured tool provider implementation that:
- Correctly implements the
SkillToolProviderabstract base class- Uses local import for dynamic loading compatibility
- Validates configuration with appropriate type and value checks
- Includes comprehensive docstrings
The Ruff TRY003 hint about the exception message on line 74 is a minor style preference and acceptable here given the message is concise.
frontend/src/apis/meeting.ts (1)
47-55: Consider adding authentication header support.The comment on line 52 suggests authentication may be needed. The existing
client.tshas authentication handling withgetToken(). Consider either:
- Using the existing API client for consistency
- Adding authentication header support here
This may be intentional if the meeting API is external/third-party, but worth verifying.
frontend/src/types/api.ts (1)
578-632: LGTM! Well-structured meeting booking types.The type definitions are clean and properly organized. The distinction between the full
MeetingRoom/MeetingParticipanttypes and the simplified versions inMeetingBookingFormData.availableRooms/availableParticipants(with justid,name,recommended) makes sense for the form's display needs. TheCreateMeetingRequestcorrectly uses snake_case to match backend API conventions.frontend/src/features/tasks/components/meeting/MeetingBookingForm.tsx (3)
256-273: Datetime string manipulation may lose timezone information.The
slice(0, 16)approach strips timezone information from ISO strings, and appending':00'creates a naive datetime. IfstartTime/endTimecontain timezone suffixes (e.g.,2026-01-04T14:00:00+08:00), this information is silently discarded.This is acceptable if the data is always in local time without timezone, but worth documenting or handling explicitly if timezone-aware strings are expected.
61-67: Verify ifselectedTaskDetail.subtasksusage aligns with guidelines.The coding guidelines state that frontend message data must use
messagesfromuseUnifiedMessages()as the single source of truth. This code accessesselectedTaskDetail.subtasksdirectly to determine if the form has been submitted.If
useUnifiedMessages()provides equivalent data for checking subsequent USER messages, consider using it for consistency. Otherwise, if this is purely for state detection (not display), the current approach may be acceptable.
31-37: Clean component structure with proper context integration.The component correctly integrates with
TaskContextandChatStreamContext, handles null cases gracefully, and properly manages form state. The props interface is well-defined with clear documentation.backend/init_data/skills/meeting-booking/get_meeting_resources.py (1)
24-76: Well-structured tool with proper documentation.The
GetMeetingResourcesInputschema has clear field descriptions, and theGetMeetingResourcesToolclass includes comprehensive docstrings. The tool follows LangChain conventions correctly with proper type hints throughout.
| def _run( | ||
| self, | ||
| date: str = "", | ||
| start_time: Optional[str] = None, | ||
| end_time: Optional[str] = None, | ||
| ) -> str: | ||
| """Synchronous execution - uses asyncio.run for compatibility.""" | ||
| import asyncio | ||
|
|
||
| return asyncio.run(self._arun(date, start_time, end_time)) |
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.
asyncio.run() will fail if called from an existing async context.
Using asyncio.run() in _run will raise RuntimeError: This event loop is already running if the tool is invoked from within an async framework (e.g., FastAPI async endpoints, async LangChain chains). Consider using asyncio.get_event_loop().run_until_complete() with proper loop detection, or check if an event loop is already running.
🔎 Suggested fix
def _run(
self,
date: str = "",
start_time: Optional[str] = None,
end_time: Optional[str] = None,
) -> str:
"""Synchronous execution - uses asyncio.run for compatibility."""
import asyncio
- return asyncio.run(self._arun(date, start_time, end_time))
+ try:
+ loop = asyncio.get_running_loop()
+ except RuntimeError:
+ # No running loop, safe to use asyncio.run
+ return asyncio.run(self._arun(date, start_time, end_time))
+ else:
+ # Already in async context, create a new task
+ import concurrent.futures
+ with concurrent.futures.ThreadPoolExecutor() as executor:
+ future = executor.submit(
+ asyncio.run, self._arun(date, start_time, end_time)
+ )
+ return future.result()📝 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.
| def _run( | |
| self, | |
| date: str = "", | |
| start_time: Optional[str] = None, | |
| end_time: Optional[str] = None, | |
| ) -> str: | |
| """Synchronous execution - uses asyncio.run for compatibility.""" | |
| import asyncio | |
| return asyncio.run(self._arun(date, start_time, end_time)) | |
| def _run( | |
| self, | |
| date: str = "", | |
| start_time: Optional[str] = None, | |
| end_time: Optional[str] = None, | |
| ) -> str: | |
| """Synchronous execution - uses asyncio.run for compatibility.""" | |
| import asyncio | |
| try: | |
| loop = asyncio.get_running_loop() | |
| except RuntimeError: | |
| # No running loop, safe to use asyncio.run | |
| return asyncio.run(self._arun(date, start_time, end_time)) | |
| else: | |
| # Already in async context, create a new task | |
| import concurrent.futures | |
| with concurrent.futures.ThreadPoolExecutor() as executor: | |
| future = executor.submit( | |
| asyncio.run, self._arun(date, start_time, end_time) | |
| ) | |
| return future.result() |
🤖 Prompt for AI Agents
In backend/init_data/skills/meeting-booking/get_meeting_resources.py around
lines 77-86, the synchronous wrapper uses asyncio.run() which raises
RuntimeError when called from an existing event loop; change it to detect a
running loop and, if none, use asyncio.run(self._arun(...)), otherwise submit
the coroutine to the running loop with
asyncio.run_coroutine_threadsafe(self._arun(...), loop).result() so the call
works both from sync code and from within async frameworks.
|
|
||
| // Check for meeting booking form | ||
| const meetingBookingData = parseMeetingBookingForm(contentToParse); | ||
| if (meetingBookingData) { | ||
| return ( | ||
| <MeetingBookingForm | ||
| data={meetingBookingData} | ||
| taskId={selectedTaskDetail?.id || 0} | ||
| currentMessageIndex={messageIndex} | ||
| rawContent={contentToParse} | ||
| onSubmit={onSendMessage} | ||
| /> | ||
| ); | ||
| } |
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.
Missing meeting booking form handling during streaming/recovery.
The meeting booking form is parsed in renderAiMessage but not in renderRecoveredContent (starting at line 1289). This inconsistency means meeting booking forms won't render correctly when content is being streamed or recovered after a page refresh.
For consistency with clarification forms and final prompts, consider adding parseMeetingBookingForm handling in renderRecoveredContent.
🔎 Suggested addition after line 1408
// Try to parse final prompt format
const markdownFinalPrompt = parseMarkdownFinalPrompt(contentToRender);
if (markdownFinalPrompt) {
return (
<FinalPromptMessage
data={markdownFinalPrompt}
selectedTeam={selectedTeam}
selectedRepo={selectedRepo}
selectedBranch={selectedBranch}
/>
);
}
+
+ // Try to parse meeting booking form
+ const meetingBookingData = parseMeetingBookingForm(contentToRender);
+ if (meetingBookingData) {
+ return (
+ <MeetingBookingForm
+ data={meetingBookingData}
+ taskId={selectedTaskDetail?.id || 0}
+ currentMessageIndex={index}
+ rawContent={contentToRender}
+ onSubmit={onSendMessage}
+ />
+ );
+ }
// Default: render as markdown📝 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.
| // Check for meeting booking form | |
| const meetingBookingData = parseMeetingBookingForm(contentToParse); | |
| if (meetingBookingData) { | |
| return ( | |
| <MeetingBookingForm | |
| data={meetingBookingData} | |
| taskId={selectedTaskDetail?.id || 0} | |
| currentMessageIndex={messageIndex} | |
| rawContent={contentToParse} | |
| onSubmit={onSendMessage} | |
| /> | |
| ); | |
| } | |
| // Try to parse final prompt format | |
| const markdownFinalPrompt = parseMarkdownFinalPrompt(contentToRender); | |
| if (markdownFinalPrompt) { | |
| return ( | |
| <FinalPromptMessage | |
| data={markdownFinalPrompt} | |
| selectedTeam={selectedTeam} | |
| selectedRepo={selectedRepo} | |
| selectedBranch={selectedBranch} | |
| /> | |
| ); | |
| } | |
| // Try to parse meeting booking form | |
| const meetingBookingData = parseMeetingBookingForm(contentToRender); | |
| if (meetingBookingData) { | |
| return ( | |
| <MeetingBookingForm | |
| data={meetingBookingData} | |
| taskId={selectedTaskDetail?.id || 0} | |
| currentMessageIndex={index} | |
| rawContent={contentToRender} | |
| onSubmit={onSendMessage} | |
| /> | |
| ); | |
| } | |
| // Default: render as markdown |
🤖 Prompt for AI Agents
In frontend/src/features/tasks/components/message/MessageBubble.tsx around lines
1227-1240 and renderRecoveredContent starting near line 1289 (suggested
insertion after line 1408), add the same meeting booking form handling that
exists in renderAiMessage: call parseMeetingBookingForm(contentToParse) inside
renderRecoveredContent and if it returns data, return the MeetingBookingForm
component with the same props (data, taskId from selectedTaskDetail?.id || 0,
currentMessageIndex: messageIndex, rawContent: contentToParse, onSubmit:
onSendMessage). This mirrors the existing handling for clarification forms/final
prompts so recovered/streamed content renders meeting booking forms
consistently.
…arsing Replace [^]* with [\s\S]* and remove 's' flag which is only available in ES2018+. The TypeScript target is ES2017, so we need to use [\s\S] pattern for cross-line matching.
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: 0
♻️ Duplicate comments (2)
frontend/src/features/tasks/components/message/MessageBubble.tsx (2)
1291-1410: Missing meeting booking form handling during streaming/recovery.The meeting booking form is parsed in
renderAiMessagebut not inrenderRecoveredContent. This inconsistency means meeting booking forms won't render correctly when content is being streamed or recovered after a page refresh.For consistency with clarification forms (lines 1300-1396) and final prompts (lines 1399-1410), add
parseMeetingBookingFormhandling inrenderRecoveredContent.🔎 Suggested addition after line 1410
// Try to parse final prompt format const markdownFinalPrompt = parseMarkdownFinalPrompt(contentToRender); if (markdownFinalPrompt) { return ( <FinalPromptMessage data={markdownFinalPrompt} selectedTeam={selectedTeam} selectedRepo={selectedRepo} selectedBranch={selectedBranch} /> ); } + + // Try to parse meeting booking form + const meetingBookingData = parseMeetingBookingForm(contentToRender); + if (meetingBookingData) { + return ( + <MeetingBookingForm + data={meetingBookingData} + taskId={selectedTaskDetail?.id || 0} + currentMessageIndex={index} + rawContent={contentToRender} + onSubmit={onSendMessage} + /> + ); + } // Default: render as markdown
1069-1070: Preserve full room names when parsing options.The room/participant option regex captures names with
([^\n(]+), which truncates everything after the first(. In the documented form example, names like "会议室A (101)" will be parsed as just "会议室A," and multiple rooms with different suffixes become indistinguishable in the UI.This was previously flagged but remains unaddressed. Consider matching the full name and stripping only the optional "(Recommended/推荐)" tag separately.
🔎 Proposed fix
const roomSection = roomSectionMatch[0]; - const roomOptionRegex = /-\s*\[([✓xX* ]?)\]\s*`([^`]+)`\s*-\s*([^\n(]+)(?:\s*\((?:Recommended|推荐)\))?/g; + const roomOptionRegex = /-\s*\[([✓xX* ]?)\]\s*`([^`]+)`\s*-\s*([^\n]+?)(?:\s*\((?:Recommended|推荐)\))?\s*$/gm; let roomMatch; while ((roomMatch = roomOptionRegex.exec(roomSection)) !== null) {Apply the same fix to the participant regex at line 1102.
Also applies to: 1102-1102
🧹 Nitpick comments (1)
frontend/src/features/tasks/components/message/MessageBubble.tsx (1)
1127-1130: Strengthen validation for meeting booking forms.The current validation only requires
titleORstartTime, meaning a meeting form with just a title and no time information would be considered valid. This could lead to incomplete booking attempts.🔎 Proposed stricter validation
// Validate we have minimum required data - if (!formData.title && !formData.startTime) { + if (!formData.title || !formData.startTime || !formData.endTime) { return null; }This ensures that a meeting has both a title and valid time range before rendering the form.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
frontend/src/features/tasks/components/message/MessageBubble.tsx
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{py,ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{py,ts,tsx,js,jsx}: All code comments MUST be written in English
File size MUST NOT exceed 1000 lines - split into multiple sub-modules if exceeded
Function length SHOULD NOT exceed 50 lines (preferred)
Files:
frontend/src/features/tasks/components/message/MessageBubble.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
TypeScript/React MUST use strict mode, functional components, Prettier for formatting, ESLint for linting, single quotes, and no semicolons
Files:
frontend/src/features/tasks/components/message/MessageBubble.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
TypeScript MUST use
constoverlet, never usevar
Files:
frontend/src/features/tasks/components/message/MessageBubble.tsx
frontend/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
frontend/src/**/*.{ts,tsx}: MUST useuseTranslationhook imported from@/hooks/useTranslation, not fromreact-i18next
MUST use single namespace withuseTranslation()- never use array format likeuseTranslation(['common', 'groups'])
Frontend message data MUST always usemessagesfromuseUnifiedMessages()hook as the single source of truth for displaying messages - never useselectedTaskDetail.subtasks
Frontend i18n translation keys MUST use current namespace formatt('key.subkey')for keys within namespace andt('namespace:key.subkey')for cross-namespace keys
Files:
frontend/src/features/tasks/components/message/MessageBubble.tsx
frontend/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Frontend MUST only use
NEXT_PUBLIC_*environment variables for client-safe values
Files:
frontend/src/features/tasks/components/message/MessageBubble.tsx
🧠 Learnings (1)
📚 Learning: 2025-12-18T02:09:09.776Z
Learnt from: CR
Repo: wecode-ai/Wegent PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-18T02:09:09.776Z
Learning: Applies to frontend/src/**/*.tsx : Frontend component files named with CRD terms: team-list.tsx, bot-form.tsx, model-selector.tsx
Applied to files:
frontend/src/features/tasks/components/message/MessageBubble.tsx
🧬 Code graph analysis (1)
frontend/src/features/tasks/components/message/MessageBubble.tsx (2)
frontend/src/types/api.ts (1)
MeetingBookingFormData(596-617)frontend/src/features/tasks/components/meeting/MeetingBookingForm.tsx (1)
MeetingBookingForm(31-381)
🪛 Biome (2.1.2)
frontend/src/features/tasks/components/message/MessageBubble.tsx
[error] 1046-1046: The regular expression includes this negated empty character class.
Negated empty character classes match anything.
If you want to match against [, escape it [.
Otherwise, remove the character class or fill it.
(lint/correctness/noEmptyCharacterClassInRegex)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: E2E Tests (Shard 2/3)
- GitHub Check: E2E Tests (Shard 1/3)
- GitHub Check: E2E Tests (Shard 3/3)
- GitHub Check: Test wegent CLI Integration
🔇 Additional comments (2)
frontend/src/features/tasks/components/message/MessageBubble.tsx (2)
1230-1242: LGTM! Meeting booking form integration in renderAiMessage.The integration follows the established pattern for clarification forms and final prompts. The parsing and rendering logic is consistent with the existing codebase.
1003-1137: Remove the code duplication verification request—no duplicateparseMeetingBookingFormfunction exists in the codebase.The codebase contains only one
parseMeetingBookingFormfunction (line 1005 in MessageBubble.tsx) with a single usage at line 1231. No similar parsing logic for meeting booking forms exists elsewhere. The original concern is not applicable.Likely an incorrect or invalid review comment.
- Fix mockCreateMeeting type annotation to properly return Promise - Handle asyncio.run in sync context when already in async event loop
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: 1
🧹 Nitpick comments (5)
backend/init_data/skills/meeting-booking/get_meeting_resources.py (2)
132-182: Consider validating API response structure.The code checks for
status_code == 200but doesn't validate the structure of the returned JSON data. If the API returns unexpected data formats, it could cause issues downstream when the AI or frontend tries to parse the response.💡 Suggested enhancement for response validation
Consider adding basic structure validation after parsing the JSON:
rooms_response = await client.get( f"{api_base_url}/rooms/available", headers=headers, params=params, ) - rooms_data = ( - rooms_response.json() if rooms_response.status_code == 200 else [] - ) + if rooms_response.status_code == 200: + rooms_data = rooms_response.json() + # Validate it's a list + if not isinstance(rooms_data, list): + logger.warning("[MeetingBookingTool] Unexpected rooms format, using fallback") + return self._get_mock_data(date, start_time, end_time) + else: + rooms_data = [] # Fetch participants list participants_response = await client.get( f"{api_base_url}/participants", headers=headers, ) - participants_data = ( - participants_response.json() - if participants_response.status_code == 200 - else [] - ) + if participants_response.status_code == 200: + participants_data = participants_response.json() + # Validate it's a list + if not isinstance(participants_data, list): + logger.warning("[MeetingBookingTool] Unexpected participants format, using fallback") + return self._get_mock_data(date, start_time, end_time) + else: + participants_data = []
189-319: Consider using time filters in mock data for consistency.The
start_timeandend_timeparameters are accepted but not used to filter the mock room availability. This creates inconsistent behavior between mock and real API modes, which could make testing less reliable.💡 Optional enhancement
While the current mock data is sufficient for basic testing, you could optionally filter or adjust room availability based on the time parameters to better simulate real API behavior. For example:
def _get_mock_data( self, date: str, start_time: Optional[str], end_time: Optional[str], ) -> str: """Return mock data for development/testing.""" query_date = date or datetime.now().strftime("%Y-%m-%d") # Optionally adjust room availability based on time filters # For simplicity, if time filters are provided, mark fewer rooms as available rooms = [ { "id": "room_101", "name": "会议室A (101)", "capacity": 10, "location": "1楼东侧", "available": True if not start_time else False, # Example logic "facilities": ["projector", "whiteboard", "video_conf"], }, # ... rest of rooms ] return json.dumps( { "success": True, "date": query_date, "rooms": rooms, "participants": [/* ... */], }, ensure_ascii=False, )Alternatively, if the current simplicity is preferred, you could remove these parameters from the mock method signature entirely and only pass
date.frontend/src/apis/meeting.ts (3)
37-74: Consider using the existing API client pattern for consistency.This function implements a custom fetch wrapper, but the codebase already has a standardized API client in
frontend/src/apis/client.ts(lines 56-120) that handles:
- Automatic Bearer token authentication via
getToken()- 401 authentication error handling
- Consistent error message extraction from response payloads
- Standardized error throwing with
ApiErrorUsing the existing client would ensure consistent authentication, error handling, and maintainability across all API calls.
💡 Consider refactoring to use the existing API client
If you have access to the API client instance (or can create one), you could simplify this to:
import { apiClient } from '@/apis/client' export async function createMeeting( request: CreateMeetingRequest ): Promise<MeetingBookingResponse> { const endpoint = getMeetingApiEndpoint() if (endpoint === '/api/meeting/mock') { return mockCreateMeeting(request) } try { return await apiClient.post<MeetingBookingResponse>(endpoint, request) } catch (error) { return { success: false, error: error instanceof Error ? error.message : 'Network error occurred', } } }Note: This assumes the API client can be configured to use a different base URL or that the meeting endpoint is relative to the main API base URL.
102-138: Same authentication and pattern concerns ascreateMeeting.This function has the same structural concerns as the
createMeetingfunction:
- Missing authentication: No authentication headers are included despite the meeting API potentially requiring them (same concern as lines 48-55).
- Pattern inconsistency: Doesn't leverage the existing API client pattern that provides standardized auth and error handling.
If the meeting API requires authentication, both
createMeetingandcancelMeetingshould be updated consistently.
58-58: Consider logging JSON parse failures for better debugging.The
.catch(() => ({}))pattern silently swallows JSON parsing errors. While this prevents crashes, it could hide useful debugging information if the API returns malformed JSON with error details.💡 Optional: Log parse failures
- const errorData = await response.json().catch(() => ({})); + const errorData = await response.json().catch((err) => { + console.warn('[MeetingAPI] Failed to parse error response:', err) + return {} + })Apply the same pattern on line 122 in
cancelMeeting.Also applies to: 122-122
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
backend/init_data/skills/meeting-booking/get_meeting_resources.pyfrontend/src/apis/meeting.ts
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{py,ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{py,ts,tsx,js,jsx}: All code comments MUST be written in English
File size MUST NOT exceed 1000 lines - split into multiple sub-modules if exceeded
Function length SHOULD NOT exceed 50 lines (preferred)
Files:
frontend/src/apis/meeting.tsbackend/init_data/skills/meeting-booking/get_meeting_resources.py
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
TypeScript/React MUST use strict mode, functional components, Prettier for formatting, ESLint for linting, single quotes, and no semicolons
Files:
frontend/src/apis/meeting.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
TypeScript MUST use
constoverlet, never usevar
Files:
frontend/src/apis/meeting.ts
frontend/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
frontend/src/**/*.{ts,tsx}: MUST useuseTranslationhook imported from@/hooks/useTranslation, not fromreact-i18next
MUST use single namespace withuseTranslation()- never use array format likeuseTranslation(['common', 'groups'])
Frontend message data MUST always usemessagesfromuseUnifiedMessages()hook as the single source of truth for displaying messages - never useselectedTaskDetail.subtasks
Frontend i18n translation keys MUST use current namespace formatt('key.subkey')for keys within namespace andt('namespace:key.subkey')for cross-namespace keys
Files:
frontend/src/apis/meeting.ts
frontend/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Frontend MUST only use
NEXT_PUBLIC_*environment variables for client-safe values
Files:
frontend/src/apis/meeting.ts
**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
**/*.py: Python code MUST follow PEP 8, use Black formatter with line length 88, and isort for imports
Python code MUST include type hints
Python functions and classes MUST have descriptive names and docstrings for public functions/classes
Python MUST extract magic numbers to named constants
Files:
backend/init_data/skills/meeting-booking/get_meeting_resources.py
backend/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
backend/**/*.py: Python backend module imports MUST useuv runprefix when executing commands
Task and Workspace resources MUST use TaskResource model fromapp.models.task, not the Kind model
Ghost, Model, Shell, Bot, Team, and Skill CRDs MUST use Kind model fromapp.models.kind
Files:
backend/init_data/skills/meeting-booking/get_meeting_resources.py
🧬 Code graph analysis (2)
frontend/src/apis/meeting.ts (3)
frontend/src/apis/client.ts (1)
request(57-121)frontend/src/types/api.ts (2)
CreateMeetingRequest(626-632)MeetingBookingResponse(619-624)frontend/public/mockServiceWorker.js (1)
response(123-123)
backend/init_data/skills/meeting-booking/get_meeting_resources.py (2)
frontend/src/features/tasks/components/meeting/index.ts (1)
default(5-5)backend/init_data/skills/wiki_submit/wiki_submit.js (1)
headers(161-164)
🪛 Ruff (0.14.10)
backend/init_data/skills/meeting-booking/get_meeting_resources.py
192-192: Unused method argument: start_time
(ARG002)
193-193: Unused method argument: end_time
(ARG002)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: E2E Tests (Shard 1/3)
- GitHub Check: E2E Tests (Shard 3/3)
- GitHub Check: E2E Tests (Shard 2/3)
- GitHub Check: Test wegent CLI Integration
- GitHub Check: Test Frontend
🔇 Additional comments (5)
backend/init_data/skills/meeting-booking/get_meeting_resources.py (3)
1-39: LGTM! Clean imports and well-documented input schema.The module structure follows best practices with proper licensing, descriptive docstrings, organized imports, and a well-defined Pydantic input schema with clear field descriptions.
41-76: LGTM! Proper LangChain tool setup with good configurability.The tool class is well-structured with descriptive metadata, proper dependency injection fields, and configurable timeout. The
arbitrary_types_allowedconfig is appropriate for thews_emitterfield.
77-98: Excellent fix for async context handling!The implementation correctly addresses the previous review concern about
asyncio.run()failing in existing async contexts. By detecting a running loop withasyncio.get_running_loop()and usingThreadPoolExecutorwhen needed, the method now works correctly in both synchronous and asynchronous contexts.frontend/src/apis/meeting.ts (2)
17-26: LGTM!The endpoint resolution logic is clean and correctly falls back to a mock endpoint when the environment variable is not configured.
80-94: LGTM! Previous issue resolved.The function signature now correctly returns
Promise<MeetingBookingResponse>and the unsafe type assertion has been removed. The implementation properly simulates a delayed response and generates a deterministic meeting ID.
| const response = await fetch(endpoint, { | ||
| method: 'POST', | ||
| headers: { | ||
| 'Content-Type': 'application/json', | ||
| // Add additional headers as needed (e.g., authentication) | ||
| }, | ||
| body: JSON.stringify(request), | ||
| }); |
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.
🧩 Analysis chain
🏁 Script executed:
# Check if the files exist and examine the meeting API
ls -la frontend/src/apis/ 2>/dev/null || echo "Directory not found"Repository: wecode-ai/Wegent
Length of output: 1959
🏁 Script executed:
# Read the meeting.ts file if it exists
if [ -f "frontend/src/apis/meeting.ts" ]; then
wc -l frontend/src/apis/meeting.ts
echo "---"
sed -n '37,74p' frontend/src/apis/meeting.ts
else
echo "frontend/src/apis/meeting.ts not found"
fiRepository: wecode-ai/Wegent
Length of output: 1155
🏁 Script executed:
# Read the client.ts file if it exists to see the authentication pattern
if [ -f "frontend/src/apis/client.ts" ]; then
wc -l frontend/src/apis/client.ts
echo "---"
sed -n '56,120p' frontend/src/apis/client.ts
else
echo "frontend/src/apis/client.ts not found"
fiRepository: wecode-ai/Wegent
Length of output: 2336
🏁 Script executed:
# Search for authentication patterns across all API files
echo "=== Searching for Authorization headers ==="
rg "Authorization" frontend/src/apis/ -n -A 2 -B 2
echo ""
echo "=== Searching for getToken usage ==="
rg "getToken" frontend/src/apis/ -n -A 2 -B 2
echo ""
echo "=== List all API files ==="
fd -e ts -e tsx frontend/src/apis/Repository: wecode-ai/Wegent
Length of output: 22178
🏁 Script executed:
# Check if meeting endpoint is documented or if there's any indication whether auth is required
grep -r "meeting" frontend/src/ --include="*.ts" --include="*.tsx" | grep -i "api\|endpoint\|auth" | head -20Repository: wecode-ai/Wegent
Length of output: 1751
🏁 Script executed:
# Check the getMeetingApiEndpoint function to see if it provides any context
grep -n "getMeetingApiEndpoint" frontend/src/apis/meeting.ts -A 10 -B 5Repository: wecode-ai/Wegent
Length of output: 1591
🏁 Script executed:
# Look for any mock or test files for meeting API
find frontend -name "*meeting*" -type fRepository: wecode-ai/Wegent
Length of output: 88
Add Bearer token authentication to match the established API pattern.
The fetch request includes a comment about adding authentication headers but doesn't implement any. This is inconsistent with the codebase pattern—all other API functions (chat.ts, tasks.ts, skills.ts, attachments.ts, etc.) implement Bearer token authentication using getToken(). Follow the established pattern by importing getToken from ./user and adding the Authorization header:
headers: {
'Content-Type': 'application/json',
...(token && { Authorization: `Bearer ${token}` }),
}
where token = getToken() is retrieved before the fetch call.
🤖 Prompt for AI Agents
In frontend/src/apis/meeting.ts around lines 48 to 55, the POST fetch call is
missing Bearer token authentication; import getToken from ./user, call const
token = getToken() before the fetch, and add the Authorization header to the
request headers using the established pattern (e.g., include 'Content-Type':
'application/json' and spread ...(token && { Authorization: `Bearer ${token}` })
so the token is only sent when present).
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: 4
Fix all issues with AI Agents 🤖
In @backend/.env.bak:
- Line 89: Remove the extra blank line in the .env.bak file (the stray empty
line near the end) so there are no consecutive or trailing blank lines; simply
delete that blank line to keep the file consistent.
- Around line 1-164: Add a new documented env section describing the
meeting-booking feature by declaring MEETING_API_BASE_URL, MEETING_API_TOKEN,
and NEXT_PUBLIC_MEETING_API_ENDPOINT with example values, a short comment for
each explaining purpose and default/fallback behavior (e.g., service base URL,
auth token kept secret, and public frontend endpoint exposed via NEXT_PUBLIC
prefix), and a security note that MEETING_API_TOKEN must be kept secret while
NEXT_PUBLIC_* is exposed to clients; place this block near other third-party
integration/webhook configs for consistency.
- Around line 155-164: This file contains duplicate environment definitions for
CHAT_MCP_ENABLED, CHAT_MCP_SERVERS, WEB_SEARCH_ENABLED, and WEB_SEARCH_ENGINES;
remove the duplicated blocks or move these overrides into a separate
.env.production (or clearly labeled production) file, and if keeping them in an
example section mark it with a comment explaining they are production overrides;
also ensure the JSON values for CHAT_MCP_SERVERS and WEB_SEARCH_ENGINES are
wrapped in quotes so they are treated as single string values by env parsers.
In @frontend/src/features/settings/components/BotEdit.tsx:
- Around line 348-353: Variable _shellType is computed but unused and the
predicate always returns true despite the comment claiming "Skills are supported
for ClaudeCode shell type only"; fix by either removing _shellType and updating
the comment to reflect that skills are currently unconditionally enabled, or
implement the intended check: obtain selectedShell (using agentName and shells
as currently referenced) and return whether selectedShell.shellType ===
'ClaudeCode' so the boolean matches the comment; ensure you update or remove the
explanatory comment to match the new behavior and keep references to _shellType,
agentName, selectedShell, shells, or BotEdit as appropriate.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
frontend/src/features/settings/components/BotEdit.tsx (2)
40-40: Incorrect import source foruseTranslationhook.The import violates the coding guidelines. According to the guidelines: "Frontend src/**/*.{ts,tsx}: MUST use
useTranslationhook imported from@/hooks/useTranslation, not fromreact-i18next"🔎 Proposed fix
-import { useTranslation } from 'react-i18next'; +import { useTranslation } from '@/hooks/useTranslation';As per coding guidelines.
1-1658: File size exceeds the 1000-line limit.This file is 1658 lines, which exceeds the mandatory limit of 1000 lines specified in the coding guidelines. Consider splitting this component into multiple sub-modules to improve maintainability.
Suggested refactoring approach:
- Extract template handling logic into a separate module
- Extract model configuration UI into a separate component
- Extract skills management UI into a separate component
- Extract MCP configuration UI into a separate component
As per coding guidelines.
🧹 Nitpick comments (1)
backend/init_data/skills/meeting-booking/get_meeting_resources.py (1)
189-208: Consider using or explicitly marking unused parameters.The
start_timeandend_timeparameters are currently unused in the mock data generation. Consider either:
- Implementing basic filtering logic to make the mock data more realistic
- Prefixing with underscore (
_start_time,_end_time) to indicate intentional non-use🔎 Option 1: Implement basic filtering (more realistic)
def _get_mock_data( self, date: str, - start_time: Optional[str], - end_time: Optional[str], + start_time: Optional[str] = None, + end_time: Optional[str] = None, ) -> str: """Return mock data for development/testing. This provides realistic sample data for testing the meeting booking flow without requiring an actual meeting service API. + + The start_time and end_time parameters can be used to filter room + availability in future enhancements. Args: date: Query date🔎 Option 2: Mark as intentionally unused
def _get_mock_data( self, date: str, - start_time: Optional[str], - end_time: Optional[str], + _start_time: Optional[str], + _end_time: Optional[str], ) -> str: """Return mock data for development/testing. This provides realistic sample data for testing the meeting booking flow without requiring an actual meeting service API. + + Note: start_time and end_time parameters are currently unused but + reserved for future filtering logic.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
backend/.env.bakbackend/init_data/skills/meeting-booking/get_meeting_resources.pyfrontend/src/features/settings/components/BotEdit.tsxfrontend/src/features/tasks/components/meeting/MeetingBookingForm.tsxfrontend/src/i18n/locales/en/chat.jsonfrontend/src/i18n/locales/zh-CN/chat.jsonfrontend/src/types/api.tsplans/meeting-booking-intent-form-plan.mdplans/meeting-booking-manual-participants-plan.md
🚧 Files skipped from review as they are similar to previous changes (2)
- frontend/src/features/tasks/components/meeting/MeetingBookingForm.tsx
- frontend/src/types/api.ts
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{py,ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{py,ts,tsx,js,jsx}: All code comments MUST be written in English
File size MUST NOT exceed 1000 lines - split into multiple sub-modules if exceeded
Function length SHOULD NOT exceed 50 lines (preferred)
Files:
frontend/src/features/settings/components/BotEdit.tsxbackend/init_data/skills/meeting-booking/get_meeting_resources.py
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
TypeScript/React MUST use strict mode, functional components, Prettier for formatting, ESLint for linting, single quotes, and no semicolons
Files:
frontend/src/features/settings/components/BotEdit.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
TypeScript MUST use
constoverlet, never usevar
Files:
frontend/src/features/settings/components/BotEdit.tsx
frontend/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
frontend/src/**/*.{ts,tsx}: MUST useuseTranslationhook imported from@/hooks/useTranslation, not fromreact-i18next
MUST use single namespace withuseTranslation()- never use array format likeuseTranslation(['common', 'groups'])
Frontend message data MUST always usemessagesfromuseUnifiedMessages()hook as the single source of truth for displaying messages - never useselectedTaskDetail.subtasks
Frontend i18n translation keys MUST use current namespace formatt('key.subkey')for keys within namespace andt('namespace:key.subkey')for cross-namespace keys
Files:
frontend/src/features/settings/components/BotEdit.tsx
frontend/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Frontend MUST only use
NEXT_PUBLIC_*environment variables for client-safe values
Files:
frontend/src/features/settings/components/BotEdit.tsx
**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
**/*.py: Python code MUST follow PEP 8, use Black formatter with line length 88, and isort for imports
Python code MUST include type hints
Python functions and classes MUST have descriptive names and docstrings for public functions/classes
Python MUST extract magic numbers to named constants
Files:
backend/init_data/skills/meeting-booking/get_meeting_resources.py
backend/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
backend/**/*.py: Python backend module imports MUST useuv runprefix when executing commands
Task and Workspace resources MUST use TaskResource model fromapp.models.task, not the Kind model
Ghost, Model, Shell, Bot, Team, and Skill CRDs MUST use Kind model fromapp.models.kind
Files:
backend/init_data/skills/meeting-booking/get_meeting_resources.py
🧠 Learnings (4)
📚 Learning: 2025-12-18T02:09:09.776Z
Learnt from: CR
Repo: wecode-ai/Wegent PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-18T02:09:09.776Z
Learning: Applies to frontend/src/i18n/zh-CN.json : Frontend i18n Chinese values (zh-CN) MUST use UI terms: `'智能体列表'`, `'机器人配置'`
Applied to files:
frontend/src/i18n/locales/zh-CN/chat.json
📚 Learning: 2025-12-18T02:09:09.776Z
Learnt from: CR
Repo: wecode-ai/Wegent PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-18T02:09:09.776Z
Learning: Applies to frontend/src/**/*.tsx : Frontend component files named with CRD terms: team-list.tsx, bot-form.tsx, model-selector.tsx
Applied to files:
frontend/src/features/settings/components/BotEdit.tsx
📚 Learning: 2025-12-18T02:09:09.776Z
Learnt from: CR
Repo: wecode-ai/Wegent PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-18T02:09:09.776Z
Learning: Applies to backend/app/services/chat/**/*.py : Backend Chat Shell MUST support MCP (Model Context Protocol) configuration via `CHAT_MCP_*` environment variables
Applied to files:
backend/.env.bak
📚 Learning: 2025-12-18T02:09:09.776Z
Learnt from: CR
Repo: wecode-ai/Wegent PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-18T02:09:09.776Z
Learning: Applies to backend/app/services/search/**/*.py : Backend MUST support web search feature configuration via `WEB_SEARCH_*` environment variables with adapter configuration
Applied to files:
backend/.env.bak
🪛 dotenv-linter (4.0.0)
backend/.env.bak
[warning] 18-18: [UnorderedKey] The ALGORITHM key should go before the SECRET_KEY key
(UnorderedKey)
[warning] 19-19: [UnorderedKey] The ACCESS_TOKEN_EXPIRE_MINUTES key should go before the ALGORITHM key
(UnorderedKey)
[warning] 50-50: [UnorderedKey] The TASK_SHARE_BASE_URL key should go before the TEAM_SHARE_BASE_URL key
(UnorderedKey)
[warning] 66-66: [UnorderedKey] The WEBHOOK_AUTH_TYPE key should go before the WEBHOOK_ENABLED key
(UnorderedKey)
[warning] 68-68: [UnorderedKey] The WEBHOOK_AUTH_TOKEN key should go before the WEBHOOK_AUTH_TYPE key
(UnorderedKey)
[warning] 70-70: [UnorderedKey] The WEBHOOK_HEADERS key should go before the WEBHOOK_HTTP_METHOD key
(UnorderedKey)
[warning] 81-81: [UnorderedKey] The SHARE_TOKEN_AES_IV key should go before the SHARE_TOKEN_AES_KEY key
(UnorderedKey)
[warning] 89-89: [ExtraBlankLine] Extra blank line detected
(ExtraBlankLine)
[warning] 94-94: [UnorderedKey] The MAX_EXTRACTED_TEXT_LENGTH key should go before the MAX_UPLOAD_FILE_SIZE_MB key
(UnorderedKey)
[warning] 135-135: [UnorderedKey] The WIKI_DEFAULT_TEAM_NAME key should go before the WIKI_ENABLED key
(UnorderedKey)
[warning] 137-137: [UnorderedKey] The WIKI_DEFAULT_AGENT_TYPE key should go before the WIKI_DEFAULT_TEAM_NAME key
(UnorderedKey)
[warning] 140-140: [UnorderedKey] The WIKI_DEFAULT_LANGUAGE key should go before the WIKI_DEFAULT_TEAM_NAME key
(UnorderedKey)
[warning] 143-143: [UnorderedKey] The WIKI_DEFAULT_USER_ID key should go before the WIKI_ENABLED key
(UnorderedKey)
[warning] 149-149: [UnorderedKey] The WIKI_RESULT_POLL_BATCH_SIZE key should go before the WIKI_RESULT_POLL_INTERVAL_SECONDS key
(UnorderedKey)
[warning] 151-151: [UnorderedKey] The WIKI_MAX_CONTENT_SIZE key should go before the WIKI_RESULT_POLL_BATCH_SIZE key
(UnorderedKey)
[warning] 153-153: [UnorderedKey] The WIKI_CONTENT_WRITE_BASE_URL key should go before the WIKI_DEFAULT_AGENT_TYPE key
(UnorderedKey)
[warning] 155-155: [DuplicatedKey] The CHAT_MCP_ENABLED key is duplicated
(DuplicatedKey)
[warning] 158-158: [DuplicatedKey] The CHAT_MCP_SERVERS key is duplicated
(DuplicatedKey)
[warning] 158-158: [ValueWithoutQuotes] This value needs to be surrounded in quotes
(ValueWithoutQuotes)
[warning] 160-160: [DuplicatedKey] The WEB_SEARCH_ENABLED key is duplicated
(DuplicatedKey)
[warning] 164-164: [DuplicatedKey] The WEB_SEARCH_ENGINES key is duplicated
(DuplicatedKey)
[warning] 164-164: [ValueWithoutQuotes] This value needs to be surrounded in quotes
(ValueWithoutQuotes)
🪛 LanguageTool
plans/meeting-booking-intent-form-plan.md
[uncategorized] ~201-~201: 动词的修饰一般为‘形容词(副词)+地+动词’。您的意思是否是:精细"地"控制
Context: ... ### 方案二:添加专用的会议预约模式(类似智能追问模式) 如果需要更精细的控制,可以添加一个专用的会议预约模式。 #### 实现步骤 ##### 1....
(wb4)
🪛 markdownlint-cli2 (0.18.1)
plans/meeting-booking-intent-form-plan.md
74-74: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🪛 Ruff (0.14.10)
backend/init_data/skills/meeting-booking/get_meeting_resources.py
192-192: Unused method argument: start_time
(ARG002)
193-193: Unused method argument: end_time
(ARG002)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
- GitHub Check: Test Backend (3.11)
- GitHub Check: Test wegent CLI Integration
- GitHub Check: Test Backend (3.10)
- GitHub Check: Test Frontend
- GitHub Check: E2E Tests (Shard 2/3)
- GitHub Check: E2E Tests (Shard 3/3)
- GitHub Check: E2E Tests (Shard 1/3)
🔇 Additional comments (10)
plans/meeting-booking-manual-participants-plan.md (1)
1-326: Documentation is comprehensive and well-structured.The planning document provides a thorough implementation plan for the manual participants feature, including:
- Clear requirement analysis and existing implementation review
- Detailed data structure changes with TypeScript examples
- UI design mockups and component changes
- Complete implementation checklist
- Data flow diagrams and risk assessment
The document effectively guides the implementation of this feature enhancement.
backend/init_data/skills/meeting-booking/get_meeting_resources.py (3)
1-76: LGTM: Class definitions and configuration.The tool classes are well-documented with:
- Comprehensive docstrings describing functionality
- Proper type hints throughout
- Clear field descriptions using Pydantic
- Appropriate configuration for dependency injection
77-98: Properly handles async context detection.The synchronous wrapper now correctly detects whether an event loop is already running and handles both scenarios appropriately:
- If in an async context: runs the coroutine in a thread pool to avoid blocking
- If not in an async context: safely uses
asyncio.run()This resolves the previous concern about
RuntimeError: This event loop is already running.
100-187: Well-implemented async execution with proper error handling.The async execution path includes:
- Appropriate timeout configuration
- Clean fallback to mock data when API is not configured
- Comprehensive error handling with logging
- Proper HTTP request handling with authorization
frontend/src/i18n/locales/en/chat.json (1)
390-416: LGTM: Complete and well-structured English translations.The new meeting booking translations are:
- Grammatically correct and user-friendly
- Comprehensive, covering all UI elements
- Consistent with existing translation patterns
- Include support for manual participant input
frontend/src/i18n/locales/zh-CN/chat.json (1)
390-416: LGTM: Complete and accurate Chinese translations.The Chinese translations are:
- Accurate and natural
- Consistent with existing translation patterns
- Properly mirror the English translations
- Use appropriate UI terminology
plans/meeting-booking-intent-form-plan.md (1)
1-369: Excellent planning document with clear implementation guidance.This comprehensive planning document provides:
- Clear requirement analysis and existing component overview
- Three implementation approaches with detailed pros/cons
- Complete system prompt template ready for copy-paste
- Step-by-step configuration instructions for the Wegent UI
- Data flow diagrams and example dialogues
- Recommended approach with clear rationale
The document will be very helpful for implementing and configuring the meeting booking feature.
frontend/src/features/settings/components/BotEdit.tsx (3)
638-652: LGTM - Dependency array correctly updated.The addition of
selectedModelNamespaceto thegetBotDatadependency array is correct, as this value is used within the function at line 618 when callingcreatePredefinedModelConfig.
655-700: LGTM - Dependency array correctly updated.The addition of
scopeandgroupNameto thesaveBotdependency array is correct, as these values are used within the function at line 679 to determine the namespace for bot creation/update.
348-353: Remove outdated comments about ClaudeCode-only support; the implementation correctly supports skills for all shell types.The change to
return trueunconditionally is correct and safe. Skills filtering is properly delegated to individual skills via theirbindShellsproperty, which specifies compatibility with shell types like 'ClaudeCode', 'Agno', 'Dify', and 'Chat'. However, the comments at lines 349-350 stating "Skills are supported for ClaudeCode shell type only" and "Chat shell skills selection is hidden" are now outdated and misleading. Remove these comments since the implementation enables skills UI for all shell types, with per-skill filtering happening downstream viabindShells.
backend/.env.bak
Outdated
| # SPDX-FileCopyrightText: 2025 Weibo, Inc. | ||
| # | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| # Environment configuration | ||
| # Set to "development" for auto migrations, "production" for manual control | ||
| ENVIRONMENT=development | ||
|
|
||
| # Alembic auto-upgrade configuration | ||
| # Enable/disable automatic database migration on startup (only works in development mode) | ||
| DB_AUTO_MIGRATE=True | ||
|
|
||
| # Database configuration | ||
| DATABASE_URL=mysql+pymysql://root:123456@localhost:3306/task_manager | ||
|
|
||
| # JWT configuration | ||
| SECRET_KEY=your-secret-key-here | ||
| ALGORITHM=HS256 | ||
| ACCESS_TOKEN_EXPIRE_MINUTES=10080 | ||
|
|
||
| # EXECUTOR | ||
| EXECUTOR_CANCEL_TASK_URL=http://localhost:8001/executor-manager/tasks/cancel | ||
| EXECUTOR_DELETE_TASK_URL=http://localhost:8001/executor-manager/executor/delete | ||
|
|
||
| # Cache configuration, 2 hour in seconds | ||
| REPO_CACHE_EXPIRED_TIME=7200 | ||
|
|
||
| # Redis configuration | ||
| REDIS_URL=redis://127.0.0.1:6379/0 | ||
|
|
||
| # Task limits | ||
| MAX_RUNNING_TASKS_PER_USER=10 | ||
|
|
||
| # Task append expiration (hours) | ||
| APPEND_CHAT_TASK_EXPIRE_HOURS=2 | ||
| APPEND_CODE_TASK_EXPIRE_HOURS=24 | ||
|
|
||
| # Subtask executor cleanup configuration | ||
| # After a subtask is COMPLETED or FAILED, if executor_name/executor_namespace are set | ||
| # and updated_at exceeds this threshold, the executor task will be deleted automatically. | ||
| CHAT_TASK_EXECUTOR_DELETE_AFTER_HOURS=2 | ||
| CODE_TASK_EXECUTOR_DELETE_AFTER_HOURS=24 | ||
| # Cleanup scanning interval (seconds) | ||
| TASK_EXECUTOR_CLEANUP_INTERVAL_SECONDS=600 | ||
|
|
||
| ENABLE_API_DOCS=True | ||
|
|
||
| # Team sharing configuration | ||
| TEAM_SHARE_BASE_URL=http://localhost:3000/chat | ||
| TASK_SHARE_BASE_URL=http://localhost:3000 | ||
| TEAM_SHARE_QUERY_PARAM=teamShare | ||
|
|
||
| # Group chat history configuration | ||
| # In group chat mode, AI-bot sees: first N messages + last M messages (no duplicates) | ||
| # If total messages < N + M, all messages are kept | ||
| GROUP_CHAT_HISTORY_FIRST_MESSAGES=10 | ||
| GROUP_CHAT_HISTORY_LAST_MESSAGES=20 | ||
|
|
||
| # Webhook notification configuration | ||
| WEBHOOK_ENABLED=False | ||
| # Webhook endpoint | ||
| WEBHOOK_ENDPOINT_URL= | ||
| # POST、PUT | ||
| WEBHOOK_HTTP_METHOD=POST | ||
| # brearer、basic、token | ||
| WEBHOOK_AUTH_TYPE= | ||
| # token | ||
| WEBHOOK_AUTH_TOKEN= | ||
| # '{"key": "value"}' | ||
| WEBHOOK_HEADERS= | ||
| # 30 | ||
| WEBHOOK_TIMEOUT=30 | ||
|
|
||
| # AES encryption configuration for share tokens and git tokens | ||
| # IMPORTANT: These keys are used for encrypting sensitive data including git tokens | ||
| # SHARE_TOKEN_AES_KEY must be exactly 32 bytes (32 characters) for AES-256 | ||
| # SHARE_TOKEN_AES_IV must be exactly 16 bytes (16 characters) for AES IV | ||
| # SECURITY WARNING: Change these default values in production! | ||
| # Generate secure random keys using: openssl rand -hex 32 (for key) and openssl rand -hex 16 (for IV) | ||
| SHARE_TOKEN_AES_KEY=12345678901234567890123456789012 | ||
| SHARE_TOKEN_AES_IV=1234567890123456 | ||
|
|
||
| # YAML initialization configuration | ||
| # Directory containing YAML files for initial data (default: /app/init_data) | ||
| INIT_DATA_DIR=/app/init_data | ||
| # Enable/disable YAML initialization on startup (default: True) | ||
| INIT_DATA_ENABLED=True | ||
|
|
||
|
|
||
| # File upload configuration | ||
| # Maximum file size in MB (default: 20) | ||
| MAX_UPLOAD_FILE_SIZE_MB=50 | ||
| # Maximum extracted text length (default: 1000000) | ||
| MAX_EXTRACTED_TEXT_LENGTH=1000000 | ||
|
|
||
| # Web search configuration | ||
| # Enable/disable web search feature (default: False) | ||
| WEB_SEARCH_ENABLED=False | ||
| # Search API configuration as JSON string (adapter for different search engines) | ||
| # WEB_SEARCH_ENGINES={"engines":{"google":{"query_param":"q","limit_param":"limit","extra_params":{"format":"json"},"response_path":"results","title_field":"title","url_field":"url","snippet_field":"content"}}} | ||
| WEB_SEARCH_ENGINES={} | ||
|
|
||
| # MCP (Model Context Protocol) configuration for Chat Shell | ||
| # Enable/disable MCP tools in Chat Shell mode (default: False) | ||
| CHAT_MCP_ENABLED=False | ||
| # MCP server configurations as JSON string (similar to Claude Desktop format) | ||
| # Supported server types: stdio, sse, streamable-http | ||
| # Example configurations: | ||
| # - SSE server: {"mcpServers":{"image-gen":{"type":"sse","url":"http://localhost:8080/sse","headers":{"Authorization":"Bearer xxx"}}}} | ||
| # - stdio server: {"mcpServers":{"ppt-gen":{"type":"stdio","command":"npx","args":["-y","@example/ppt-mcp-server"],"env":{"API_KEY":"xxx"}}}} | ||
| # - Multiple servers: {"mcpServers":{"server1":{"type":"sse","url":"http://localhost:8080/sse"},"server2":{"type":"stdio","command":"npx","args":["-y","@example/mcp-server"]}}} | ||
| # See backend/app/services/chat/mcp_client/README.md for detailed documentation | ||
| CHAT_MCP_SERVERS={} | ||
|
|
||
| # Tool calling flow limits for Chat Shell | ||
| # Maximum LLM requests in tool calling flow (default: 5) | ||
| CHAT_TOOL_MAX_REQUESTS=5 | ||
| # Maximum time for tool calling flow in seconds (default: 30.0) | ||
| CHAT_TOOL_MAX_TIME_SECONDS=30.0 | ||
| # Maximum time to wait for active streaming requests to complete (seconds) | ||
| # Default: 600 seconds (10 minutes) to allow long-running streaming requests to complete | ||
| GRACEFUL_SHUTDOWN_TIMEOUT=600 | ||
| # Whether to reject new requests during shutdown (503 Service Unavailable) | ||
| # Set to False if you want to allow requests during shutdown (not recommended) | ||
| SHUTDOWN_REJECT_NEW_REQUESTS=True | ||
|
|
||
| # Wiki feature configuration (System-level) | ||
| # Wiki tables are now stored in the main database (task_manager) | ||
| # Wiki generation is system-level: team and model are configured here, not selected by users | ||
| # Feature toggle | ||
| WIKI_ENABLED=True | ||
| # Default team name for wiki task execution (matches init_data/01-default-resources.yaml) | ||
| # The team's bot MUST have a model configured (bind_model or custom config) | ||
| # If no model is configured, wiki generation will be disabled in the frontend | ||
| WIKI_DEFAULT_TEAM_NAME=wiki-team | ||
| # Default agent type for wiki generation | ||
| WIKI_DEFAULT_AGENT_TYPE=ClaudeCode | ||
| # Default language for wiki documentation generation (en = English, zh = Chinese) | ||
| # This is a system-level configuration, users cannot change it in the frontend | ||
| WIKI_DEFAULT_LANGUAGE=en | ||
| # User ID for wiki task creation (0 = use current user ID, set to specific user ID for system-level tasks) | ||
| # When set to a specific user ID, all wiki tasks will be created under that user | ||
| WIKI_DEFAULT_USER_ID=1 | ||
| # Maximum concurrent wiki generations | ||
| WIKI_MAX_CONCURRENT_GENERATIONS=5 | ||
| # Background polling interval (seconds) | ||
| WIKI_RESULT_POLL_INTERVAL_SECONDS=30 | ||
| # Background polling batch size | ||
| WIKI_RESULT_POLL_BATCH_SIZE=20 | ||
| # Maximum content size (bytes, default 10MB) | ||
| WIKI_MAX_CONTENT_SIZE=10485760 | ||
| # Base URL for internal wiki content writer | ||
| WIKI_CONTENT_WRITE_BASE_URL=http://backend:8000 | ||
|
|
||
| CHAT_MCP_ENABLED=True | ||
| # MCP servers configuration (JSON format, similar to Claude Desktop) | ||
| # This example configures Bing CN MCP for web search | ||
| CHAT_MCP_SERVERS={"mcpServers":{"wegentFetchServer":{"type":"streamable-http","transport":"streamable_http","url": "http://mcp.intra.weibo.com/2/mcp/internal/server/wegent-fetch","headers": {"Authorization": "Bearer mcp_eyJhbGciOiJIUzI1NiJ9.eyJjYSI6MTc2NTc3MDgyMiwibyI6ImppYW5neWFuZzcifQ._P5D-A7eF2ahUmZJtb1K2Qmll6I-kyKJcJPQBUvxRng"}},"webpageFetchServer":{"type":"streamable-http","transport": "streamable_http","url": "https://ai.intra.weibo.com/api/v1/dify/mcp/server/DUET0RCW4iLLmQ7v/mcp"}}} | ||
|
|
||
| WEB_SEARCH_ENABLED=True | ||
| # Search API configuration as JSON string (adapter for different search engines) | ||
| # Example for SearXNG (DuckDuckGo-compatible): | ||
| # WEB_SEARCH_CONFIG={"query_param":"q","limit_param":"limit","extra_params":{"format":"json"},"response_path":"results","title_field":"title","url_field":"url","snippet_field":"content"} | ||
| WEB_SEARCH_ENGINES={"engines":{"petal":{"display_name":"网页综合搜索","base_url":"http://paas.api.weibo.com/2/aigc/backend/generic-search/petal-search","max_results":20,"query_param":"query","limit_param":"count","auth_header":{"Authorization":"Basic ZGVlci1mbG93OkRKTGo5OWM4RDRrbjdVcXY="},"response_path":"data.results","title_field":"title","url_field":"url","snippet_field":"content"},"quark":{"display_name":"新闻搜索","base_url":"http://paas.api.weibo.com/2/aigc/backend/generic-search/linked-retrieval/linked-retrieval-entry/v2/linkedRetrieval/commands/genericSearch","max_results":20,"query_param":"query","limit_param":"limit","auth_header":{"Authorization":"Basic ZGVlci1mbG93OkRKTGo5OWM4RDRrbjdVcXY="},"response_path":"pageItems","title_field":"title","url_field":"link","snippet_field":"snippet","content_field":"mainText"}}} |
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.
Add documentation for the new meeting-booking feature configuration.
The PR adds a meeting-booking skill with optional configuration via MEETING_API_BASE_URL, MEETING_API_TOKEN, and NEXT_PUBLIC_MEETING_API_ENDPOINT (per PR summary). These environment variables should be documented in .env.bak along with example values, comments explaining their purpose, and default/fallback behavior.
For consistency with the file's existing style, add a new section like:
+# Meeting booking configuration
+# Base URL for meeting booking API
+MEETING_API_BASE_URL=http://localhost:8080/meeting-api
+# Authentication token for meeting booking API (optional)
+MEETING_API_TOKEN=your-meeting-api-token
+# Frontend-accessible meeting API endpoint
+NEXT_PUBLIC_MEETING_API_ENDPOINT=http://localhost:8080/meeting-apiCommittable suggestion skipped: line range outside the PR's diff.
🧰 Tools
🪛 dotenv-linter (4.0.0)
[warning] 18-18: [UnorderedKey] The ALGORITHM key should go before the SECRET_KEY key
(UnorderedKey)
[warning] 19-19: [UnorderedKey] The ACCESS_TOKEN_EXPIRE_MINUTES key should go before the ALGORITHM key
(UnorderedKey)
[warning] 50-50: [UnorderedKey] The TASK_SHARE_BASE_URL key should go before the TEAM_SHARE_BASE_URL key
(UnorderedKey)
[warning] 66-66: [UnorderedKey] The WEBHOOK_AUTH_TYPE key should go before the WEBHOOK_ENABLED key
(UnorderedKey)
[warning] 68-68: [UnorderedKey] The WEBHOOK_AUTH_TOKEN key should go before the WEBHOOK_AUTH_TYPE key
(UnorderedKey)
[warning] 70-70: [UnorderedKey] The WEBHOOK_HEADERS key should go before the WEBHOOK_HTTP_METHOD key
(UnorderedKey)
[warning] 81-81: [UnorderedKey] The SHARE_TOKEN_AES_IV key should go before the SHARE_TOKEN_AES_KEY key
(UnorderedKey)
[warning] 89-89: [ExtraBlankLine] Extra blank line detected
(ExtraBlankLine)
[warning] 94-94: [UnorderedKey] The MAX_EXTRACTED_TEXT_LENGTH key should go before the MAX_UPLOAD_FILE_SIZE_MB key
(UnorderedKey)
[warning] 135-135: [UnorderedKey] The WIKI_DEFAULT_TEAM_NAME key should go before the WIKI_ENABLED key
(UnorderedKey)
[warning] 137-137: [UnorderedKey] The WIKI_DEFAULT_AGENT_TYPE key should go before the WIKI_DEFAULT_TEAM_NAME key
(UnorderedKey)
[warning] 140-140: [UnorderedKey] The WIKI_DEFAULT_LANGUAGE key should go before the WIKI_DEFAULT_TEAM_NAME key
(UnorderedKey)
[warning] 143-143: [UnorderedKey] The WIKI_DEFAULT_USER_ID key should go before the WIKI_ENABLED key
(UnorderedKey)
[warning] 149-149: [UnorderedKey] The WIKI_RESULT_POLL_BATCH_SIZE key should go before the WIKI_RESULT_POLL_INTERVAL_SECONDS key
(UnorderedKey)
[warning] 151-151: [UnorderedKey] The WIKI_MAX_CONTENT_SIZE key should go before the WIKI_RESULT_POLL_BATCH_SIZE key
(UnorderedKey)
[warning] 153-153: [UnorderedKey] The WIKI_CONTENT_WRITE_BASE_URL key should go before the WIKI_DEFAULT_AGENT_TYPE key
(UnorderedKey)
[warning] 155-155: [DuplicatedKey] The CHAT_MCP_ENABLED key is duplicated
(DuplicatedKey)
[warning] 158-158: [DuplicatedKey] The CHAT_MCP_SERVERS key is duplicated
(DuplicatedKey)
[warning] 158-158: [ValueWithoutQuotes] This value needs to be surrounded in quotes
(ValueWithoutQuotes)
[warning] 160-160: [DuplicatedKey] The WEB_SEARCH_ENABLED key is duplicated
(DuplicatedKey)
[warning] 164-164: [DuplicatedKey] The WEB_SEARCH_ENGINES key is duplicated
(DuplicatedKey)
[warning] 164-164: [ValueWithoutQuotes] This value needs to be surrounded in quotes
(ValueWithoutQuotes)
🤖 Prompt for AI Agents
In @backend/.env.bak around lines 1-164, Add a new documented env section
describing the meeting-booking feature by declaring MEETING_API_BASE_URL,
MEETING_API_TOKEN, and NEXT_PUBLIC_MEETING_API_ENDPOINT with example values, a
short comment for each explaining purpose and default/fallback behavior (e.g.,
service base URL, auth token kept secret, and public frontend endpoint exposed
via NEXT_PUBLIC prefix), and a security note that MEETING_API_TOKEN must be kept
secret while NEXT_PUBLIC_* is exposed to clients; place this block near other
third-party integration/webhook configs for consistency.
backend/.env.bak
Outdated
| # Enable/disable YAML initialization on startup (default: True) | ||
| INIT_DATA_ENABLED=True | ||
|
|
||
|
|
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.
Remove extra blank line.
There is an extra blank line that can be removed for consistency.
🧰 Tools
🪛 dotenv-linter (4.0.0)
[warning] 89-89: [ExtraBlankLine] Extra blank line detected
(ExtraBlankLine)
🤖 Prompt for AI Agents
In @backend/.env.bak around line 89, Remove the extra blank line in the .env.bak
file (the stray empty line near the end) so there are no consecutive or trailing
blank lines; simply delete that blank line to keep the file consistent.
backend/.env.bak
Outdated
| CHAT_MCP_ENABLED=True | ||
| # MCP servers configuration (JSON format, similar to Claude Desktop) | ||
| # This example configures Bing CN MCP for web search | ||
| CHAT_MCP_SERVERS={"mcpServers":{"wegentFetchServer":{"type":"streamable-http","transport":"streamable_http","url": "http://mcp.intra.weibo.com/2/mcp/internal/server/wegent-fetch","headers": {"Authorization": "Bearer mcp_eyJhbGciOiJIUzI1NiJ9.eyJjYSI6MTc2NTc3MDgyMiwibyI6ImppYW5neWFuZzcifQ._P5D-A7eF2ahUmZJtb1K2Qmll6I-kyKJcJPQBUvxRng"}},"webpageFetchServer":{"type":"streamable-http","transport": "streamable_http","url": "https://ai.intra.weibo.com/api/v1/dify/mcp/server/DUET0RCW4iLLmQ7v/mcp"}}} | ||
|
|
||
| WEB_SEARCH_ENABLED=True | ||
| # Search API configuration as JSON string (adapter for different search engines) | ||
| # Example for SearXNG (DuckDuckGo-compatible): | ||
| # WEB_SEARCH_CONFIG={"query_param":"q","limit_param":"limit","extra_params":{"format":"json"},"response_path":"results","title_field":"title","url_field":"url","snippet_field":"content"} | ||
| WEB_SEARCH_ENGINES={"engines":{"petal":{"display_name":"网页综合搜索","base_url":"http://paas.api.weibo.com/2/aigc/backend/generic-search/petal-search","max_results":20,"query_param":"query","limit_param":"count","auth_header":{"Authorization":"Basic ZGVlci1mbG93OkRKTGo5OWM4RDRrbjdVcXY="},"response_path":"data.results","title_field":"title","url_field":"url","snippet_field":"content"},"quark":{"display_name":"新闻搜索","base_url":"http://paas.api.weibo.com/2/aigc/backend/generic-search/linked-retrieval/linked-retrieval-entry/v2/linkedRetrieval/commands/genericSearch","max_results":20,"query_param":"query","limit_param":"limit","auth_header":{"Authorization":"Basic ZGVlci1mbG93OkRKTGo5OWM4RDRrbjdVcXY="},"response_path":"pageItems","title_field":"title","url_field":"link","snippet_field":"snippet","content_field":"mainText"}}} |
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.
🧩 Analysis chain
🏁 Script executed:
# First, check if the file exists and get its size
wc -l backend/.env.bakRepository: wecode-ai/Wegent
Length of output: 80
🏁 Script executed:
# Read the entire file to understand structure
cat -n backend/.env.bakRepository: wecode-ai/Wegent
Length of output: 9296
🏁 Script executed:
# Search for meeting-booking related configuration mentions
rg -i "meeting" backend/.env.bakRepository: wecode-ai/Wegent
Length of output: 42
🏁 Script executed:
# Check for duplicated key patterns
rg "^(CHAT_MCP_ENABLED|CHAT_MCP_SERVERS|WEB_SEARCH_ENABLED|WEB_SEARCH_ENGINES)" backend/.env.bakRepository: wecode-ai/Wegent
Length of output: 1518
🏁 Script executed:
# Search for how environment variables are loaded in the backend
rg -l "load_dotenv|environ|getenv" backend/ --type py | head -5Repository: wecode-ai/Wegent
Length of output: 292
🏁 Script executed:
# Check for any documentation about .env.bak file purpose
rg -i "\.env\.bak|environment.*override" backend/ --type py --type md | head -20Repository: wecode-ai/Wegent
Length of output: 42
🏁 Script executed:
# Verify if this pattern (defaults followed by overrides) is documented anywhere
find backend -name "*.md" -o -name "*.txt" | xargs grep -l "environment" 2>/dev/null | head -5Repository: wecode-ai/Wegent
Length of output: 211
🏁 Script executed:
# Check if there's a README explaining the .env.bak structure
cat -n backend/.env.bak | head -10Repository: wecode-ai/Wegent
Length of output: 469
🏁 Script executed:
# Check the config test to understand env loading
cat backend/tests/core/test_config.pyRepository: wecode-ai/Wegent
Length of output: 4417
🏁 Script executed:
# Check backend README for .env.bak documentation
cat backend/README.md | head -100Repository: wecode-ai/Wegent
Length of output: 2527
🏁 Script executed:
# Look for config.py or settings.py to see how env vars are loaded
fd "config|settings" backend/app --type py | head -10Repository: wecode-ai/Wegent
Length of output: 229
🏁 Script executed:
# Check how CHAT_MCP_SERVERS and WEB_SEARCH_ENGINES are actually used/parsed
rg "CHAT_MCP_SERVERS|WEB_SEARCH_ENGINES" backend/app --type py -A 3 | head -40Repository: wecode-ai/Wegent
Length of output: 2639
🏁 Script executed:
# Check the config.py to see how env vars are actually loaded and parsed
cat backend/app/core/config.py | head -150Repository: wecode-ai/Wegent
Length of output: 5763
🏁 Script executed:
# Verify how dotenv loads the .env.bak file
fd "dotenv|pydantic" backend --type f | xargs grep -l "BaseSettings\|load_dotenv" | head -3Repository: wecode-ai/Wegent
Length of output: 42
🏁 Script executed:
# Check the specific JSON parsing in search factory to see how the unquoted JSON is handled
cat backend/app/services/search/factory.py | head -50Repository: wecode-ai/Wegent
Length of output: 1446
🏁 Script executed:
# Verify that pydantic-settings handles unquoted JSON strings correctly
cat backend/app/core/config.py | grep -A 5 "WEB_SEARCH_ENGINES\|CHAT_MCP_SERVERS"Repository: wecode-ai/Wegent
Length of output: 636
🏁 Script executed:
# Search for meeting-booking feature documentation in PR or codebase
find backend -type f \( -name "*.md" -o -name "*.py" \) | xargs grep -l "meeting.*booking" 2>/dev/null | head -5Repository: wecode-ai/Wegent
Length of output: 228
🏁 Script executed:
# Check meeting-booking feature to see what env vars it needs
cat backend/init_data/skills/meeting-booking/SKILL.mdRepository: wecode-ai/Wegent
Length of output: 4176
🏁 Script executed:
# Check the provider for meeting-booking feature configuration
cat backend/init_data/skills/meeting-booking/provider.pyRepository: wecode-ai/Wegent
Length of output: 3226
🏁 Script executed:
# Check the main python script for meeting-booking
cat backend/init_data/skills/meeting-booking/get_meeting_resources.py | head -80Repository: wecode-ai/Wegent
Length of output: 146
Remove duplicate environment variable definitions or relocate them to a separate production configuration file.
Lines 155, 158, 160, and 164 redefine CHAT_MCP_ENABLED, CHAT_MCP_SERVERS, WEB_SEARCH_ENABLED, and WEB_SEARCH_ENGINES that are already defined at lines 105, 113, 98, and 101 respectively. While most env parsers apply the last definition, this creates ambiguity and is difficult to maintain.
If these represent production overrides, move them to a separate .env.production file or clearly mark this section as a production example with a comment explaining its intent.
Additionally, for consistency with best practices, wrap the JSON values on lines 158 and 164 in quotes:
Diff
-CHAT_MCP_SERVERS={"mcpServers":{...}}
+CHAT_MCP_SERVERS='{"mcpServers":{...}}'
-WEB_SEARCH_ENGINES={"engines":{...}}
+WEB_SEARCH_ENGINES='{"engines":{...}}'Committable suggestion skipped: line range outside the PR's diff.
🧰 Tools
🪛 dotenv-linter (4.0.0)
[warning] 155-155: [DuplicatedKey] The CHAT_MCP_ENABLED key is duplicated
(DuplicatedKey)
[warning] 158-158: [DuplicatedKey] The CHAT_MCP_SERVERS key is duplicated
(DuplicatedKey)
[warning] 158-158: [ValueWithoutQuotes] This value needs to be surrounded in quotes
(ValueWithoutQuotes)
[warning] 160-160: [DuplicatedKey] The WEB_SEARCH_ENABLED key is duplicated
(DuplicatedKey)
[warning] 164-164: [DuplicatedKey] The WEB_SEARCH_ENGINES key is duplicated
(DuplicatedKey)
[warning] 164-164: [ValueWithoutQuotes] This value needs to be surrounded in quotes
(ValueWithoutQuotes)
🤖 Prompt for AI Agents
In @backend/.env.bak around lines 155-164, This file contains duplicate
environment definitions for CHAT_MCP_ENABLED, CHAT_MCP_SERVERS,
WEB_SEARCH_ENABLED, and WEB_SEARCH_ENGINES; remove the duplicated blocks or move
these overrides into a separate .env.production (or clearly labeled production)
file, and if keeping them in an example section mark it with a comment
explaining they are production overrides; also ensure the JSON values for
CHAT_MCP_SERVERS and WEB_SEARCH_ENGINES are wrapped in quotes so they are
treated as single string values by env parsers.
| const _shellType = selectedShell?.shellType || agentName; | ||
| // Skills are supported for ClaudeCode shell type only | ||
| // Chat shell skills selection is hidden (but skills still work if configured) | ||
| return shellType === 'ClaudeCode'; | ||
| // Note: _shellType is kept for future use when we need to filter by shell type | ||
| return true; | ||
| }, [agentName, shells]); |
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.
Inconsistent comment and unused variable.
The comment on line 349-350 states "Skills are supported for ClaudeCode shell type only", but the implementation unconditionally returns true for all shell types. This inconsistency is misleading.
Additionally, the _shellType variable is computed but never used. If it's truly needed for future use as the comment suggests, consider removing it until that future implementation to reduce code noise.
🔎 Proposed fix
const supportsSkills = useMemo(() => {
- // Get shell type from the selected shell
- const selectedShell = shells.find(s => s.name === agentName);
- const _shellType = selectedShell?.shellType || agentName;
- // Skills are supported for ClaudeCode shell type only
- // Chat shell skills selection is hidden (but skills still work if configured)
- // Note: _shellType is kept for future use when we need to filter by shell type
+ // Skills are now supported for all shell types
return true;
}, [agentName, shells]);Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In @frontend/src/features/settings/components/BotEdit.tsx around lines 348-353,
Variable _shellType is computed but unused and the predicate always returns true
despite the comment claiming "Skills are supported for ClaudeCode shell type
only"; fix by either removing _shellType and updating the comment to reflect
that skills are currently unconditionally enabled, or implement the intended
check: obtain selectedShell (using agentName and shells as currently referenced)
and return whether selectedShell.shellType === 'ClaudeCode' so the boolean
matches the comment; ensure you update or remove the explanatory comment to
match the new behavior and keep references to _shellType, agentName,
selectedShell, shells, or BotEdit as appropriate.
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
Fix all issues with AI Agents 🤖
In @plans/meeting-booking-api-plan.md:
- Around line 195-207: The health endpoint returns a raw dict without a response
model; define a MeetingHealthResponse Pydantic model (e.g., in
backend/app/schemas/meeting.py) with fields status, mode, and message, import it
into the router file, and update the meeting_service_health endpoint to declare
response_model=MeetingHealthResponse on the @router.get decorator and return a
value matching that schema so FastAPI performs validation/serialization.
- Around line 141-169: The mock delay in mock_create_meeting currently uses
time.time() % 0.2 which yields unpredictable jitter; replace that with a proper
random sleep (e.g., use random.uniform to pick a delay between 0.3 and 0.5
seconds) and import the random module, updating the await asyncio.sleep call in
mock_create_meeting and removing the time.time() usage.
♻️ Duplicate comments (2)
frontend/src/features/tasks/components/message/MessageBubble.tsx (2)
1075-1075: Preserve full room names when parsing options.The room/participant option regex captures names with
([^\n(]+), which truncates everything after the first(. Room names like "会议室A (101)" will be parsed as just "会议室A," causing multiple rooms with different suffixes to become indistinguishable in the UI.Also applies to: 1108-1108
1297-1416: Missing meeting booking form handling during streaming/recovery.The meeting booking form is parsed in
renderAiMessagebut not inrenderRecoveredContent. This means meeting booking forms won't render correctly when content is being streamed or recovered after a page refresh. For consistency with clarification forms and final prompts, addparseMeetingBookingFormhandling inrenderRecoveredContentafter the final prompt check.
🧹 Nitpick comments (5)
backend/app/api/endpoints/meeting.py (2)
84-86: Consider i18n or document hardcoded Chinese messages.The success messages are hardcoded in Chinese (lines 84, 86, 115, 130). Since the codebase has i18n support (evidenced by frontend translations), consider either:
- Accepting a language parameter and returning localized messages
- Returning message keys that the frontend can translate
- Adding a comment documenting why Chinese is hardcoded for this mock service
Also applies to: 115-115, 130-130
72-72: Mock delay calculation could be clearer.The expression
0.3 + (time.time() % 0.2)produces a delay between 0.3-0.5 seconds, but usingtime.time() % 0.2for randomness is unconventional. Consider usingrandom.uniform(0.3, 0.5)for clarity, or add a comment explaining the approach.🔎 Alternative implementation
+import random + async def mock_create_meeting( request: CreateMeetingRequest, current_user: User, ) -> MeetingBookingResponse: """ Mock implementation for meeting creation. Simulates a successful booking with realistic delay. """ # Simulate network delay (300-500ms) - await asyncio.sleep(0.3 + (time.time() % 0.2)) + await asyncio.sleep(random.uniform(0.3, 0.5))plans/meeting-booking-api-plan.md (3)
27-69: Schemas look sound overall; field constraints are well-defined.The Pydantic models follow best practices with proper validation (min/max length, required fields). However, ensure that start_time/end_time validation (lines 44-45) includes format checking. Consider adding
@field_validatorto enforce ISO 8601 format strictly, or rely on external parsing libraries likedateutil.parser. As written, these are just strings and could accept any format.
288-320: Consider documenting error handling and validation edge cases.The API documentation shows the happy path clearly but lacks explicit error scenarios. The implementation plan should clarify:
- How the mock endpoint handles invalid inputs (e.g., overlapping meetings, invalid room IDs)?
- Should the mock ever simulate failures (e.g., 50% success rate) for testing error UI?
- Are there plans to validate participant/room existence before booking?
Currently, the mock always succeeds, which limits realistic end-to-end testing.
381-387: Future extensions are reasonable; clarify prioritization and prerequisites.The roadmap items are well-thought-out (database persistence, calendar integration, conflict detection). However, the plan could better explain:
- Priority order: Should database storage come before calendar integration?
- Dependencies: Does conflict detection require database schema changes?
- Timeline: Are these targeted for the next sprint or a later release?
Consider adding a brief "Implementation Roadmap" section with phases (MVP → Phase 2 → Phase 3) to guide development sequencing.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
backend/app/api/api.pybackend/app/api/endpoints/meeting.pybackend/app/schemas/meeting.pyfrontend/src/apis/meeting.tsfrontend/src/features/tasks/components/message/MessageBubble.tsxplans/meeting-booking-api-plan.md
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{py,ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{py,ts,tsx,js,jsx}: All code comments MUST be written in English
File size MUST NOT exceed 1000 lines - split into multiple sub-modules if exceeded
Function length SHOULD NOT exceed 50 lines (preferred)
Files:
frontend/src/features/tasks/components/message/MessageBubble.tsxfrontend/src/apis/meeting.tsbackend/app/schemas/meeting.pybackend/app/api/api.pybackend/app/api/endpoints/meeting.py
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
TypeScript/React MUST use strict mode, functional components, Prettier for formatting, ESLint for linting, single quotes, and no semicolons
Files:
frontend/src/features/tasks/components/message/MessageBubble.tsxfrontend/src/apis/meeting.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
TypeScript MUST use
constoverlet, never usevar
Files:
frontend/src/features/tasks/components/message/MessageBubble.tsxfrontend/src/apis/meeting.ts
frontend/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
frontend/src/**/*.{ts,tsx}: MUST useuseTranslationhook imported from@/hooks/useTranslation, not fromreact-i18next
MUST use single namespace withuseTranslation()- never use array format likeuseTranslation(['common', 'groups'])
Frontend message data MUST always usemessagesfromuseUnifiedMessages()hook as the single source of truth for displaying messages - never useselectedTaskDetail.subtasks
Frontend i18n translation keys MUST use current namespace formatt('key.subkey')for keys within namespace andt('namespace:key.subkey')for cross-namespace keys
Files:
frontend/src/features/tasks/components/message/MessageBubble.tsxfrontend/src/apis/meeting.ts
frontend/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Frontend MUST only use
NEXT_PUBLIC_*environment variables for client-safe values
Files:
frontend/src/features/tasks/components/message/MessageBubble.tsxfrontend/src/apis/meeting.ts
**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
**/*.py: Python code MUST follow PEP 8, use Black formatter with line length 88, and isort for imports
Python code MUST include type hints
Python functions and classes MUST have descriptive names and docstrings for public functions/classes
Python MUST extract magic numbers to named constants
Files:
backend/app/schemas/meeting.pybackend/app/api/api.pybackend/app/api/endpoints/meeting.py
backend/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
backend/**/*.py: Python backend module imports MUST useuv runprefix when executing commands
Task and Workspace resources MUST use TaskResource model fromapp.models.task, not the Kind model
Ghost, Model, Shell, Bot, Team, and Skill CRDs MUST use Kind model fromapp.models.kind
Files:
backend/app/schemas/meeting.pybackend/app/api/api.pybackend/app/api/endpoints/meeting.py
backend/app/api/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
API routes MUST use CRD names (Team, Bot) in path names and database models
Files:
backend/app/api/api.pybackend/app/api/endpoints/meeting.py
🧠 Learnings (2)
📚 Learning: 2025-12-31T03:47:12.173Z
Learnt from: CR
Repo: wecode-ai/Wegent PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-31T03:47:12.173Z
Learning: Applies to frontend/src/**/*.{ts,tsx} : Frontend message data MUST always use `messages` from `useUnifiedMessages()` hook as the single source of truth for displaying messages - never use `selectedTaskDetail.subtasks`
Applied to files:
frontend/src/features/tasks/components/message/MessageBubble.tsx
📚 Learning: 2025-12-18T02:09:09.776Z
Learnt from: CR
Repo: wecode-ai/Wegent PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-18T02:09:09.776Z
Learning: Applies to frontend/src/**/*.tsx : Frontend component files named with CRD terms: team-list.tsx, bot-form.tsx, model-selector.tsx
Applied to files:
frontend/src/features/tasks/components/message/MessageBubble.tsx
🧬 Code graph analysis (2)
frontend/src/features/tasks/components/message/MessageBubble.tsx (2)
frontend/src/types/api.ts (1)
MeetingBookingFormData(596-619)frontend/src/features/tasks/components/meeting/MeetingBookingForm.tsx (1)
MeetingBookingForm(44-499)
backend/app/api/endpoints/meeting.py (2)
backend/app/core/security.py (1)
get_current_user(42-64)backend/app/schemas/meeting.py (4)
CancelMeetingResponse(38-43)CreateMeetingRequest(14-26)MeetingBookingResponse(29-35)MeetingHealthResponse(46-51)
🪛 Biome (2.1.2)
frontend/src/features/tasks/components/message/MessageBubble.tsx
[error] 1051-1051: The regular expression includes this negated empty character class.
Negated empty character classes match anything.
If you want to match against [, escape it [.
Otherwise, remove the character class or fill it.
(lint/correctness/noEmptyCharacterClassInRegex)
🪛 Ruff (0.14.10)
backend/app/api/endpoints/meeting.py
40-40: Do not perform function call Depends in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable
(B008)
65-65: Unused function argument: current_user
(ARG001)
98-98: Unused function argument: current_user
(ARG001)
98-98: Do not perform function call Depends in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable
(B008)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: E2E Tests (Shard 2/3)
- GitHub Check: E2E Tests (Shard 3/3)
- GitHub Check: E2E Tests (Shard 1/3)
- GitHub Check: Test wegent CLI Integration
- GitHub Check: Test Frontend
🔇 Additional comments (12)
frontend/src/features/tasks/components/message/MessageBubble.tsx (2)
37-37: LGTM!The imports are clean and properly organized, following the established pattern in the file.
Also applies to: 43-48
1236-1248: LGTM!The meeting booking form detection and rendering follows the same pattern as clarification forms and final prompts, maintaining consistency in the codebase.
backend/app/schemas/meeting.py (1)
14-51: LGTM!The Pydantic schemas are well-defined with proper type hints, field descriptions, and validation constraints. The structure aligns cleanly with the frontend types and API requirements.
backend/app/api/api.py (1)
12-12: LGTM!The meeting router is properly imported and included with the correct prefix and tags, following the established pattern in the file.
Also applies to: 82-82
frontend/src/apis/meeting.ts (3)
44-88: LGTM!The
createMeetingfunction properly includes authentication headers, handles errors gracefully, and correctly maps snake_case backend responses to camelCase frontend types.
96-143: LGTM!The
cancelMeetingfunction correctly constructs the endpoint based on whether it's using the backend API or an external service, and includes proper authentication and error handling.
150-178: LGTM!The
checkMeetingHealthfunction provides robust error handling with sensible defaults, ensuring the UI can gracefully handle network failures or service unavailability.backend/app/api/endpoints/meeting.py (4)
31-34: LGTM!The meeting ID generation using hex-encoded timestamps is simple and effective for mock/development scenarios.
37-60: LGTM!The endpoint structure is clean with proper type hints, docstrings, and dependency injection. The TODO comment appropriately documents the mock nature and future production plans.
95-116: LGTM!The cancel endpoint follows the same clean pattern as create, with proper typing and mock implementation suitable for development.
119-131: LGTM!The health check endpoint provides useful status information, clearly indicating the mock mode for development awareness.
plans/meeting-booking-api-plan.md (1)
228-282: Frontend API logic is well-structured with good error handling.The endpoint fallback pattern (env variable → backend default) and error handling are sound. The snake_case to camelCase mapping correctly adapts the Python backend response to TypeScript conventions.
plans/meeting-booking-api-plan.md
Outdated
| async def mock_create_meeting( | ||
| request: CreateMeetingRequest, | ||
| current_user: User, | ||
| ) -> MeetingBookingResponse: | ||
| """ | ||
| Mock implementation for meeting creation. | ||
| Simulates a successful booking with realistic delay. | ||
| """ | ||
| # Simulate network delay (300-500ms) | ||
| await asyncio.sleep(0.3 + (time.time() % 0.2)) | ||
|
|
||
| # Generate mock meeting ID | ||
| meeting_id = generate_meeting_id() | ||
|
|
||
| # Build participant info for message | ||
| participant_count = len(request.participant_ids) | ||
| manual_count = len(request.manual_participants) if request.manual_participants else 0 | ||
| total_participants = participant_count + manual_count | ||
|
|
||
| message = f'会议 "{request.title}" 已成功预约。' | ||
| if total_participants > 0: | ||
| message += f" 已邀请 {total_participants} 位参会人员。" | ||
|
|
||
| return MeetingBookingResponse( | ||
| success=True, | ||
| meeting_id=meeting_id, | ||
| message=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.
Fix mock delay calculation to use proper randomization.
Line 150 uses time.time() % 0.2 which is unreliable. Since time.time() returns a large float (seconds since epoch), the modulo operation produces unpredictable values rather than uniform jitter.
🔎 Proposed fix for reliable mock delay
import time
import asyncio
+import random
from typing import Optional
async def mock_create_meeting(
request: CreateMeetingRequest,
current_user: User,
) -> MeetingBookingResponse:
"""
Mock implementation for meeting creation.
Simulates a successful booking with realistic delay.
"""
- # Simulate network delay (300-500ms)
- await asyncio.sleep(0.3 + (time.time() % 0.2))
+ # Simulate network delay (300-500ms)
+ await asyncio.sleep(0.3 + random.uniform(0, 0.2))📝 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 def mock_create_meeting( | |
| request: CreateMeetingRequest, | |
| current_user: User, | |
| ) -> MeetingBookingResponse: | |
| """ | |
| Mock implementation for meeting creation. | |
| Simulates a successful booking with realistic delay. | |
| """ | |
| # Simulate network delay (300-500ms) | |
| await asyncio.sleep(0.3 + (time.time() % 0.2)) | |
| # Generate mock meeting ID | |
| meeting_id = generate_meeting_id() | |
| # Build participant info for message | |
| participant_count = len(request.participant_ids) | |
| manual_count = len(request.manual_participants) if request.manual_participants else 0 | |
| total_participants = participant_count + manual_count | |
| message = f'会议 "{request.title}" 已成功预约。' | |
| if total_participants > 0: | |
| message += f" 已邀请 {total_participants} 位参会人员。" | |
| return MeetingBookingResponse( | |
| success=True, | |
| meeting_id=meeting_id, | |
| message=message, | |
| ) | |
| async def mock_create_meeting( | |
| request: CreateMeetingRequest, | |
| current_user: User, | |
| ) -> MeetingBookingResponse: | |
| """ | |
| Mock implementation for meeting creation. | |
| Simulates a successful booking with realistic delay. | |
| """ | |
| # Simulate network delay (300-500ms) | |
| await asyncio.sleep(0.3 + random.uniform(0, 0.2)) | |
| # Generate mock meeting ID | |
| meeting_id = generate_meeting_id() | |
| # Build participant info for message | |
| participant_count = len(request.participant_ids) | |
| manual_count = len(request.manual_participants) if request.manual_participants else 0 | |
| total_participants = participant_count + manual_count | |
| message = f'会议 "{request.title}" 已成功预约。' | |
| if total_participants > 0: | |
| message += f" 已邀请 {total_participants} 位参会人员。" | |
| return MeetingBookingResponse( | |
| success=True, | |
| meeting_id=meeting_id, | |
| message=message, | |
| ) |
🤖 Prompt for AI Agents
In @plans/meeting-booking-api-plan.md around lines 141-169, The mock delay in
mock_create_meeting currently uses time.time() % 0.2 which yields unpredictable
jitter; replace that with a proper random sleep (e.g., use random.uniform to
pick a delay between 0.3 and 0.5 seconds) and import the random module, updating
the await asyncio.sleep call in mock_create_meeting and removing the time.time()
usage.
plans/meeting-booking-api-plan.md
Outdated
| @router.get("/health") | ||
| async def meeting_service_health(): | ||
| """ | ||
| Check meeting service health status. | ||
| Returns: | ||
| Health status of the meeting service | ||
| """ | ||
| return { | ||
| "status": "healthy", | ||
| "mode": "mock", # Will be "production" when external service is configured | ||
| "message": "Meeting service is running in mock mode", | ||
| } |
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 | 🟠 Major
Define and use a response schema for the health endpoint.
The health endpoint returns a dict literal without a response_model. This is inconsistent with other endpoints (which use response_model=...) and bypasses automatic Pydantic validation and serialization. The plan should define a MeetingHealthResponse schema in the schemas section.
🔎 Proposed addition to schemas section
Add this class to backend/app/schemas/meeting.py:
class MeetingHealthResponse(BaseModel):
"""Response schema for meeting service health check."""
status: str = Field(..., description="Health status (healthy/unhealthy)")
mode: str = Field(..., description="Service mode (mock/production)")
message: str = Field(..., description="Status message")Then update the endpoint:
-@router.get("/health")
-async def meeting_service_health():
+@router.get("/health", response_model=MeetingHealthResponse)
+async def meeting_service_health() -> MeetingHealthResponse:
"""
Check meeting service health status.
Returns:
Health status of the meeting service
"""
return MeetingHealthResponse(
status="healthy",
mode="mock",
message="Meeting service is running in mock mode",
)Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In @plans/meeting-booking-api-plan.md around lines 195-207, The health endpoint
returns a raw dict without a response model; define a MeetingHealthResponse
Pydantic model (e.g., in backend/app/schemas/meeting.py) with fields status,
mode, and message, import it into the router file, and update the
meeting_service_health endpoint to declare response_model=MeetingHealthResponse
on the @router.get decorator and return a value matching that schema so FastAPI
performs validation/serialization.
Summary
meeting-bookingskill that allows users to book meetings through natural languageget_meeting_resourcestool to fetch available rooms and participantsMeetingBookingFormcomponent with interactive selection UIMessageBubblefor automatic detection and renderingKey Changes
Backend (Skill)
GetMeetingResourcesToolinstancesFrontend
User Flow
meeting-bookingskill and callsget_meeting_resourcestoolMeetingBookingFormConfiguration
Environment variables (optional):
MEETING_API_BASE_URL: Remote meeting service API base URLMEETING_API_TOKEN: API authentication tokenNEXT_PUBLIC_MEETING_API_ENDPOINT: Frontend meeting API endpointIf not configured, the system uses mock data for development/testing.
Test plan
get_meeting_resourcestool returns mock data correctlyMeetingBookingFormcorrectlySummary by CodeRabbit
New Features
Documentation
Localization
✏️ Tip: You can customize this high-level summary in your review settings.