Skip to content

Conversation

@joyway1978
Copy link
Collaborator

@joyway1978 joyway1978 commented Jan 4, 2026

Summary

  • Add a new meeting-booking skill that allows users to book meetings through natural language
  • Implement backend skill with get_meeting_resources tool to fetch available rooms and participants
  • Create frontend MeetingBookingForm component with interactive selection UI
  • Add form parsing in MessageBubble for automatic detection and rendering
  • Add i18n translations for both English and Chinese

Key Changes

Backend (Skill)

  • SKILL.md: Defines the skill with usage instructions and Markdown form format
  • provider.py: Tool provider for creating GetMeetingResourcesTool instances
  • get_meeting_resources.py: Fetches available rooms and participants from remote API (or mock data)

Frontend

  • MeetingBookingForm.tsx: Interactive form component with room/participant selection
  • meeting.ts: API service for calling remote meeting booking service
  • MessageBubble.tsx: Parse and render meeting booking forms from AI responses
  • api.ts: TypeScript types for meeting booking data structures
  • i18n: English and Chinese translations for meeting UI

User Flow

  1. User sends: "帮忙拉一个关于AIGC平台的会,下午15点的,会议时长30分钟"
  2. AI loads meeting-booking skill and calls get_meeting_resources tool
  3. AI generates structured Markdown form with meeting details and recommendations
  4. Frontend detects and renders interactive MeetingBookingForm
  5. User reviews/modifies and clicks "Confirm Booking"
  6. Frontend directly calls remote booking API
  7. Result is sent to AI for friendly confirmation message

Configuration

Environment variables (optional):

  • MEETING_API_BASE_URL: Remote meeting service API base URL
  • MEETING_API_TOKEN: API authentication token
  • NEXT_PUBLIC_MEETING_API_ENDPOINT: Frontend meeting API endpoint

If not configured, the system uses mock data for development/testing.

Test plan

  • Verify skill loads correctly when user mentions meeting booking
  • Verify get_meeting_resources tool returns mock data correctly
  • Verify AI generates properly formatted Markdown booking form
  • Verify frontend parses and renders MeetingBookingForm correctly
  • Verify form interactions (room selection, participant checkboxes)
  • Verify booking submission sends result back to AI
  • Verify i18n translations display correctly in both languages

Summary by CodeRabbit

  • New Features

    • Inline AI-driven meeting booking form in chats (title, time, room, participants) with "show raw" toggle and recommended badges.
    • Create, cancel and health-check meetings from the UI with backend integration and mock fallbacks; submission feedback and user-facing recovery messages.
    • Frontend types and API for meeting operations and a backend resource-fetch capability to populate rooms/participants.
  • Documentation

    • Planning and usage docs describing form schema, time parsing, and integration notes.
  • Localization

    • English and Chinese UI strings for meeting booking.

✏️ Tip: You can customize this high-level summary in your review settings.

…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
@coderabbitai
Copy link

coderabbitai bot commented Jan 4, 2026

Note

Other AI code review bot(s) detected

CodeRabbit 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.

📝 Walkthrough

Walkthrough

Adds 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

Cohort / File(s) Summary
Backend: Skill Doc
backend/init_data/skills/meeting-booking/SKILL.md
New skill documentation describing tools, required Markdown form format, time parsing, usage flow, and error handling.
Backend: Tool Implementation
backend/init_data/skills/meeting-booking/get_meeting_resources.py
New GetMeetingResourcesTool (sync/async), env-driven API with httpx or mock fallback, date/time filtering, logging, and JSON-string output.
Backend: Tool Provider
backend/init_data/skills/meeting-booking/provider.py
New MeetingBookingToolProvider exposing provider_name, supported tools, config validation, and create_tool instantiating GetMeetingResourcesTool with context and timeout.
Backend: API & Schemas
backend/app/api/endpoints/meeting.py, backend/app/schemas/meeting.py, backend/app/api/api.py
New meeting router registered under /meeting; POST /book, DELETE /{meeting_id}, GET /health; Pydantic request/response schemas and mock implementations.
Frontend: Meeting API
frontend/src/apis/meeting.ts
Adds createMeeting, cancelMeeting, checkMeetingHealth, endpoint resolution via env, token handling, and standardized response mapping.
Frontend: UI Component
frontend/src/features/tasks/components/meeting/MeetingBookingForm.tsx, frontend/src/features/tasks/components/meeting/index.ts
New MeetingBookingForm component (title, times, room, participants, manual participants support), validation, submission via createMeeting, markdown result generation, toasts, and re-export.
Frontend: Message Rendering
frontend/src/features/tasks/components/message/MessageBubble.tsx
Detects meeting-booking Markdown, parses into MeetingBookingFormData, and renders MeetingBookingForm inline; note: duplicated parser implementation present.
Frontend: Types & i18n
frontend/src/types/api.ts, frontend/src/i18n/locales/en/chat.json, frontend/src/i18n/locales/zh-CN/chat.json
Adds MeetingRoom, MeetingParticipant, MeetingBookingFormData, CreateMeetingRequest, MeetingBookingResponse types (duplicate block exists) and new meeting translation blocks in EN and ZH-CN.
Plans / Docs
plans/meeting-booking-intent-form-plan.md, plans/meeting-booking-manual-participants-plan.md, plans/meeting-booking-api-plan.md
New planning documents describing output schema, integration options, manual participant UX, API design, and implementation steps.
Misc / Env
backend/.env.bak
Added environment backup file with many runtime and feature toggle defaults.
Settings UI wiring
frontend/src/features/settings/components/BotEdit.tsx
Internal wiring changes enabling skills support and propagating selectedModelNamespace in save/get flows (no public API 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
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I hopped through docs and UI bright,
Rooms and times in gentle light,
Backend fetches, frontend shows,
Tiny form—your meeting grows.
Hop—confirm and calendar’s right!

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main feature: adding a meeting booking skill with an interactive form for the frontend.
Docstring Coverage ✅ Passed Docstring coverage is 94.12% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a 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".

Comment on lines +60 to +66
// 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');

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

Comment on lines 1068 to 1069
const roomOptionRegex = /-\s*\[([xX* ]?)\]\s*`([^`]+)`\s*-\s*([^\n(]+)(?:\s*\((?:Recommended|)\))?/g;
let roomMatch;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

Copy link

@coderabbitai coderabbitai bot left a 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.

mockCreateMeeting simulates network delay with setTimeout, but the mock path in cancelMeeting returns 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 formatDateTimeForDisplay function 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: Unused start_time and end_time parameters in mock data method.

The static analysis correctly identifies that start_time and end_time are 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

📥 Commits

Reviewing files that changed from the base of the PR and between 1eddd46 and 1052c64.

📒 Files selected for processing (10)
  • backend/init_data/skills/meeting-booking/SKILL.md
  • backend/init_data/skills/meeting-booking/get_meeting_resources.py
  • backend/init_data/skills/meeting-booking/provider.py
  • frontend/src/apis/meeting.ts
  • frontend/src/features/tasks/components/meeting/MeetingBookingForm.tsx
  • frontend/src/features/tasks/components/meeting/index.ts
  • frontend/src/features/tasks/components/message/MessageBubble.tsx
  • frontend/src/i18n/locales/en/chat.json
  • frontend/src/i18n/locales/zh-CN/chat.json
  • frontend/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.ts
  • frontend/src/features/tasks/components/meeting/MeetingBookingForm.tsx
  • backend/init_data/skills/meeting-booking/provider.py
  • frontend/src/apis/meeting.ts
  • frontend/src/types/api.ts
  • backend/init_data/skills/meeting-booking/get_meeting_resources.py
  • 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/meeting/index.ts
  • frontend/src/features/tasks/components/meeting/MeetingBookingForm.tsx
  • frontend/src/apis/meeting.ts
  • frontend/src/types/api.ts
  • frontend/src/features/tasks/components/message/MessageBubble.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

TypeScript MUST use const over let, never use var

Files:

  • frontend/src/features/tasks/components/meeting/index.ts
  • frontend/src/features/tasks/components/meeting/MeetingBookingForm.tsx
  • frontend/src/apis/meeting.ts
  • frontend/src/types/api.ts
  • frontend/src/features/tasks/components/message/MessageBubble.tsx
frontend/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

frontend/src/**/*.{ts,tsx}: MUST use useTranslation hook imported from @/hooks/useTranslation, not from react-i18next
MUST use single namespace with useTranslation() - never use array format like useTranslation(['common', 'groups'])
Frontend message data MUST always use messages from useUnifiedMessages() hook as the single source of truth for displaying messages - never use selectedTaskDetail.subtasks
Frontend i18n translation keys MUST use current namespace format t('key.subkey') for keys within namespace and t('namespace:key.subkey') for cross-namespace keys

Files:

  • frontend/src/features/tasks/components/meeting/index.ts
  • frontend/src/features/tasks/components/meeting/MeetingBookingForm.tsx
  • frontend/src/apis/meeting.ts
  • frontend/src/types/api.ts
  • 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/meeting/index.ts
  • frontend/src/features/tasks/components/meeting/MeetingBookingForm.tsx
  • frontend/src/apis/meeting.ts
  • frontend/src/types/api.ts
  • frontend/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.py
  • backend/init_data/skills/meeting-booking/get_meeting_resources.py
backend/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

backend/**/*.py: Python backend module imports MUST use uv run prefix when executing commands
Task and Workspace resources MUST use TaskResource model from app.models.task, not the Kind model
Ghost, Model, Shell, Bot, Team, and Skill CRDs MUST use Kind model from app.models.kind

Files:

  • backend/init_data/skills/meeting-booking/provider.py
  • backend/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.ts
  • frontend/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 parseMeetingBookingForm function 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 SkillToolProvider abstract 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.ts has authentication handling with getToken(). Consider either:

  1. Using the existing API client for consistency
  2. 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/MeetingParticipant types and the simplified versions in MeetingBookingFormData.availableRooms/availableParticipants (with just id, name, recommended) makes sense for the form's display needs. The CreateMeetingRequest correctly 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. If startTime/endTime contain 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 if selectedTaskDetail.subtasks usage aligns with guidelines.

The coding guidelines state that frontend message data must use messages from useUnifiedMessages() as the single source of truth. This code accesses selectedTaskDetail.subtasks directly 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 TaskContext and ChatStreamContext, 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 GetMeetingResourcesInput schema has clear field descriptions, and the GetMeetingResourcesTool class includes comprehensive docstrings. The tool follows LangChain conventions correctly with proper type hints throughout.

Comment on lines 77 to 86
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))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

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.

Suggested change
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.

Comment on lines +1227 to +1240

// 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}
/>
);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

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.

Suggested change
// 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.
Copy link

@coderabbitai coderabbitai bot left a 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 renderAiMessage but not in renderRecoveredContent. 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 parseMeetingBookingForm handling in renderRecoveredContent.

🔎 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 title OR startTime, 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

📥 Commits

Reviewing files that changed from the base of the PR and between 1052c64 and 24cf617.

📒 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 const over let, never use var

Files:

  • frontend/src/features/tasks/components/message/MessageBubble.tsx
frontend/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

frontend/src/**/*.{ts,tsx}: MUST use useTranslation hook imported from @/hooks/useTranslation, not from react-i18next
MUST use single namespace with useTranslation() - never use array format like useTranslation(['common', 'groups'])
Frontend message data MUST always use messages from useUnifiedMessages() hook as the single source of truth for displaying messages - never use selectedTaskDetail.subtasks
Frontend i18n translation keys MUST use current namespace format t('key.subkey') for keys within namespace and t('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 duplicate parseMeetingBookingForm function exists in the codebase.

The codebase contains only one parseMeetingBookingForm function (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
Copy link

@coderabbitai coderabbitai bot left a 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 == 200 but 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_time and end_time parameters 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 ApiError

Using 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 as createMeeting.

This function has the same structural concerns as the createMeeting function:

  1. Missing authentication: No authentication headers are included despite the meeting API potentially requiring them (same concern as lines 48-55).
  2. Pattern inconsistency: Doesn't leverage the existing API client pattern that provides standardized auth and error handling.

If the meeting API requires authentication, both createMeeting and cancelMeeting should 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

📥 Commits

Reviewing files that changed from the base of the PR and between 24cf617 and 074f48a.

📒 Files selected for processing (2)
  • backend/init_data/skills/meeting-booking/get_meeting_resources.py
  • frontend/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.ts
  • backend/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 const over let, never use var

Files:

  • frontend/src/apis/meeting.ts
frontend/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

frontend/src/**/*.{ts,tsx}: MUST use useTranslation hook imported from @/hooks/useTranslation, not from react-i18next
MUST use single namespace with useTranslation() - never use array format like useTranslation(['common', 'groups'])
Frontend message data MUST always use messages from useUnifiedMessages() hook as the single source of truth for displaying messages - never use selectedTaskDetail.subtasks
Frontend i18n translation keys MUST use current namespace format t('key.subkey') for keys within namespace and t('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 use uv run prefix when executing commands
Task and Workspace resources MUST use TaskResource model from app.models.task, not the Kind model
Ghost, Model, Shell, Bot, Team, and Skill CRDs MUST use Kind model from app.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_allowed config is appropriate for the ws_emitter field.


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 with asyncio.get_running_loop() and using ThreadPoolExecutor when 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.

Comment on lines 48 to 55
const response = await fetch(endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
// Add additional headers as needed (e.g., authentication)
},
body: JSON.stringify(request),
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 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"
fi

Repository: 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"
fi

Repository: 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 -20

Repository: 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 5

Repository: wecode-ai/Wegent

Length of output: 1591


🏁 Script executed:

# Look for any mock or test files for meeting API
find frontend -name "*meeting*" -type f

Repository: 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).

Copy link

@coderabbitai coderabbitai bot left a 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 for useTranslation hook.

The import violates the coding guidelines. According to the guidelines: "Frontend src/**/*.{ts,tsx}: MUST use useTranslation hook imported from @/hooks/useTranslation, not from react-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_time and end_time parameters are currently unused in the mock data generation. Consider either:

  1. Implementing basic filtering logic to make the mock data more realistic
  2. 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

📥 Commits

Reviewing files that changed from the base of the PR and between 074f48a and 24421c6.

📒 Files selected for processing (9)
  • backend/.env.bak
  • backend/init_data/skills/meeting-booking/get_meeting_resources.py
  • frontend/src/features/settings/components/BotEdit.tsx
  • frontend/src/features/tasks/components/meeting/MeetingBookingForm.tsx
  • frontend/src/i18n/locales/en/chat.json
  • frontend/src/i18n/locales/zh-CN/chat.json
  • frontend/src/types/api.ts
  • plans/meeting-booking-intent-form-plan.md
  • plans/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.tsx
  • backend/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 const over let, never use var

Files:

  • frontend/src/features/settings/components/BotEdit.tsx
frontend/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

frontend/src/**/*.{ts,tsx}: MUST use useTranslation hook imported from @/hooks/useTranslation, not from react-i18next
MUST use single namespace with useTranslation() - never use array format like useTranslation(['common', 'groups'])
Frontend message data MUST always use messages from useUnifiedMessages() hook as the single source of truth for displaying messages - never use selectedTaskDetail.subtasks
Frontend i18n translation keys MUST use current namespace format t('key.subkey') for keys within namespace and t('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 use uv run prefix when executing commands
Task and Workspace resources MUST use TaskResource model from app.models.task, not the Kind model
Ghost, Model, Shell, Bot, Team, and Skill CRDs MUST use Kind model from app.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 selectedModelNamespace to the getBotData dependency array is correct, as this value is used within the function at line 618 when calling createPredefinedModelConfig.


655-700: LGTM - Dependency array correctly updated.

The addition of scope and groupName to the saveBot dependency 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 true unconditionally is correct and safe. Skills filtering is properly delegated to individual skills via their bindShells property, 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 via bindShells.

backend/.env.bak Outdated
Comment on lines 1 to 164
# 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"}}}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

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-api

Committable 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


Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

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
Comment on lines 155 to 164
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"}}}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, check if the file exists and get its size
wc -l backend/.env.bak

Repository: wecode-ai/Wegent

Length of output: 80


🏁 Script executed:

# Read the entire file to understand structure
cat -n backend/.env.bak

Repository: wecode-ai/Wegent

Length of output: 9296


🏁 Script executed:

# Search for meeting-booking related configuration mentions
rg -i "meeting" backend/.env.bak

Repository: 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.bak

Repository: 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 -5

Repository: 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 -20

Repository: 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 -5

Repository: 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 -10

Repository: wecode-ai/Wegent

Length of output: 469


🏁 Script executed:

# Check the config test to understand env loading
cat backend/tests/core/test_config.py

Repository: wecode-ai/Wegent

Length of output: 4417


🏁 Script executed:

# Check backend README for .env.bak documentation
cat backend/README.md | head -100

Repository: 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 -10

Repository: 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 -40

Repository: 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 -150

Repository: 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 -3

Repository: 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 -50

Repository: 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 -5

Repository: 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.md

Repository: 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.py

Repository: 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 -80

Repository: 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.

Comment on lines +348 to 353
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]);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

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.

Copy link

@coderabbitai coderabbitai bot left a 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 renderAiMessage but not in renderRecoveredContent. 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, add parseMeetingBookingForm handling in renderRecoveredContent after 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:

  1. Accepting a language parameter and returning localized messages
  2. Returning message keys that the frontend can translate
  3. 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 using time.time() % 0.2 for randomness is unconventional. Consider using random.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_validator to enforce ISO 8601 format strictly, or rely on external parsing libraries like dateutil.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:

  1. How the mock endpoint handles invalid inputs (e.g., overlapping meetings, invalid room IDs)?
  2. Should the mock ever simulate failures (e.g., 50% success rate) for testing error UI?
  3. 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:

  1. Priority order: Should database storage come before calendar integration?
  2. Dependencies: Does conflict detection require database schema changes?
  3. 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

📥 Commits

Reviewing files that changed from the base of the PR and between 24421c6 and 6a77ad2.

📒 Files selected for processing (6)
  • backend/app/api/api.py
  • backend/app/api/endpoints/meeting.py
  • backend/app/schemas/meeting.py
  • frontend/src/apis/meeting.ts
  • frontend/src/features/tasks/components/message/MessageBubble.tsx
  • plans/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.tsx
  • frontend/src/apis/meeting.ts
  • backend/app/schemas/meeting.py
  • backend/app/api/api.py
  • backend/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.tsx
  • frontend/src/apis/meeting.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

TypeScript MUST use const over let, never use var

Files:

  • frontend/src/features/tasks/components/message/MessageBubble.tsx
  • frontend/src/apis/meeting.ts
frontend/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

frontend/src/**/*.{ts,tsx}: MUST use useTranslation hook imported from @/hooks/useTranslation, not from react-i18next
MUST use single namespace with useTranslation() - never use array format like useTranslation(['common', 'groups'])
Frontend message data MUST always use messages from useUnifiedMessages() hook as the single source of truth for displaying messages - never use selectedTaskDetail.subtasks
Frontend i18n translation keys MUST use current namespace format t('key.subkey') for keys within namespace and t('namespace:key.subkey') for cross-namespace keys

Files:

  • frontend/src/features/tasks/components/message/MessageBubble.tsx
  • 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/features/tasks/components/message/MessageBubble.tsx
  • 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/app/schemas/meeting.py
  • backend/app/api/api.py
  • backend/app/api/endpoints/meeting.py
backend/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

backend/**/*.py: Python backend module imports MUST use uv run prefix when executing commands
Task and Workspace resources MUST use TaskResource model from app.models.task, not the Kind model
Ghost, Model, Shell, Bot, Team, and Skill CRDs MUST use Kind model from app.models.kind

Files:

  • backend/app/schemas/meeting.py
  • backend/app/api/api.py
  • backend/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.py
  • backend/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 createMeeting function properly includes authentication headers, handles errors gracefully, and correctly maps snake_case backend responses to camelCase frontend types.


96-143: LGTM!

The cancelMeeting function 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 checkMeetingHealth function 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.

Comment on lines 141 to 169
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,
)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

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.

Suggested change
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.

Comment on lines 195 to 207
@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",
}
Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants