-
-
Notifications
You must be signed in to change notification settings - Fork 7
feat: Add Manus AI integration as specialized tool #392
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
- Add Manus tool with Zod schema for parameter validation - Create ManusSection UI component for displaying task results - Register Manus tool conditionally based on MANUS_API_KEY - Add MANUS_API_KEY to environment configuration - Include comprehensive documentation in MANUS_INTEGRATION.md The integration follows QCX's existing tool-based architecture, allowing the Researcher Agent to delegate complex multi-step tasks to the Manus AI platform for advanced reasoning, research, and workflow automation.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
WalkthroughAdds Manus AI integration: environment variable example, Zod schema, a new Manus tool implementing POST /v1/tasks with validation, UI component to display task results, and conditional registration of the tool when Changes
Sequence Diagram(s)sequenceDiagram
actor ResearcherAgent as Researcher Agent
participant Tool as Manus Tool
participant API as Manus API
participant UI as UI Stream
participant Component as ManusSection
ResearcherAgent->>Tool: execute(manusTool, params)
activate Tool
rect rgb(240,248,255)
note right of Tool: Init UI & validate config
Tool->>UI: render(SearchSkeleton)
Tool->>Tool: check process.env.MANUS_API_KEY
end
rect rgb(240,255,240)
note right of Tool: API request (abortable)
Tool->>API: POST /v1/tasks (body: prompt, agentProfile, taskMode, interactiveMode)
alt API 200
API-->>Tool: { task_id, task_title, task_url, [share_url] }
Tool->>Tool: validate response schema and URLs
else API error / non-OK
API-->>Tool: error
Tool->>Tool: sanitize error
end
end
rect rgb(255,250,240)
note right of UI: UI update
alt success
Tool->>Component: pass taskResult
UI->>Component: render ManusSection
Tool->>ResearcherAgent: return taskResult
else failure
Tool->>UI: render error Card (sanitized)
Tool->>ResearcherAgent: return null
end
end
deactivate Tool
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Suggested labels
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
PR Compliance Guide 🔍Below is a summary of compliance checks for this PR:
Compliance status legend🟢 - Fully Compliant🟡 - Partial Compliant 🔴 - Not Compliant ⚪ - Requires Further Human Verification 🏷️ - Compliance label |
|||||||||||||||||||||||||||
PR Code Suggestions ✨Explore these optional code suggestions:
|
|||||||||||||||||
|
@coderabbitai how do we run the playwright testing |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (6)
.env.local.exampleMANUS_INTEGRATION.mdcomponents/manus-section.tsxlib/agents/tools/index.tsxlib/agents/tools/manus.tsxlib/schema/manus.tsx
🧰 Additional context used
🧬 Code graph analysis (2)
lib/agents/tools/manus.tsx (2)
lib/schema/manus.tsx (1)
manusSchema(4-24)components/search-skeleton.tsx (1)
SearchSkeleton(6-30)
lib/agents/tools/index.tsx (1)
lib/agents/tools/manus.tsx (1)
manusTool(7-108)
🪛 dotenv-linter (4.0.0)
.env.local.example
[warning] 16-16: [QuoteCharacter] The value has quote characters (', ")
(QuoteCharacter)
🪛 LanguageTool
MANUS_INTEGRATION.md
[style] ~70-~70: Consider a different adjective to strengthen your wording.
Context: ...uire: - Complex multi-step workflows - Deep research across multiple sources - Code...
(DEEP_PROFOUND)
🔇 Additional comments (7)
.env.local.example (1)
14-16: LGTM!The Manus API key entry follows the established pattern in this file. The static analysis warning about quote characters is a false positive since all placeholder values in this example file use the same format.
lib/schema/manus.tsx (1)
4-24: LGTM!The Zod schema is well-structured with clear descriptions for each field. The enum values, defaults, and optional fields are appropriately defined.
components/manus-section.tsx (1)
15-66: LGTM!The component is well-structured with proper security attributes on external links (
rel="noopener noreferrer"). The conditional rendering for the optionalshare_urland the clear UI hierarchy follow good React patterns.lib/agents/tools/index.tsx (1)
39-44: LGTM!The conditional registration of the Manus tool follows the established pattern used by
videoSearchTool. The environment variable check ensures the tool is only available when properly configured.lib/agents/tools/manus.tsx (2)
7-10: LGTM!The tool description clearly explains Manus capabilities, and the schema integration provides proper parameter validation.
42-46: The headerAPI_KEYis correct and matches the Manus API documentation — no changes needed. The Manus API expects authentication via theAPI_KEYheader with the raw key as the value, which is exactly how it's implemented here.MANUS_INTEGRATION.md (1)
1-187: LGTM!The documentation is comprehensive, well-organized, and accurately reflects the implementation. It covers architecture decisions, configuration, usage, API reference, and troubleshooting effectively.
| let hasError = false | ||
| // Show loading state | ||
| uiStream.append(<SearchSkeleton />) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Consider a more specific loading skeleton.
SearchSkeleton is reused for loading state, but Manus tasks may take significantly longer than search operations. Consider adding text indicating a longer operation or using a different skeleton that sets appropriate expectations.
🤖 Prompt for AI Agents
In lib/agents/tools/manus.tsx around lines 22 to 24, the component uses a
generic SearchSkeleton for loading but Manus tasks are longer-running; replace
or augment the skeleton with a Manus-specific loading UI (e.g., a
longer-operation skeleton or one with explanatory text and progress indicator)
so users understand this is a lengthy task. Update the uiStream.append call to
render the new ManusLoading/LongRunningSkeleton component or to render
SearchSkeleton plus a descriptive message like "Processing manuscript — this may
take several minutes" and, if available, add an indeterminate progress spinner
or estimated time text.
lib/agents/tools/manus.tsx
Outdated
|
|
||
| const errorMessage = | ||
| error instanceof Error ? error.message : 'Unknown error occurred' | ||
| fullResponse += `\nAn error occurred while executing Manus task: ${errorMessage}` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
# First, let's check the structure of manus.tsx around the mentioned lines
cat -n lib/agents/tools/manus.tsx | head -150 | tail -100Repository: QueueLab/QCX
Length of output: 3650
🏁 Script executed:
# Also run the provided verification script to see how fullResponse is used
rg -n "fullResponse" lib/agents/tools/ -A2 -B2Repository: QueueLab/QCX
Length of output: 5567
String mutations on fullResponse have no effect and are silently discarded.
fullResponse is passed as a parameter of type string (ToolProps, line 10 in index.tsx). The += operations on lines 74, 85, and 98–104 create new local strings without updating the original variable. Since the function returns taskResult instead of the modified fullResponse, the accumulated response content is lost to the caller.
This pattern exists across all tools (searchTool, retrieveTool, videoSearchTool, manusTool). Either return the updated fullResponse string or use a mutable wrapper object to propagate response updates to the caller.
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 824 🏁 Script executed: Length of output: 491 🏁 Script executed: Length of output: 1009 @ngoiyaeric Here's how to run Playwright testing in the QCX repository: PrerequisitesStart the development server first (the webServer config is commented out in playwright.config.ts): npm run dev
# or
bun devKeep this running in a separate terminal. Running TestsOnce the dev server is running on 1. Run all tests (headless mode)npm run test:e2eThis runs all tests in the background across all configured browsers (Chromium, Firefox, WebKit, Mobile Chrome, Mobile Safari). 2. Run tests with UI mode (Recommended for development)npm run test:e2e:uiOpens Playwright's interactive UI where you can:
3. Run tests in headed modenpm run test:e2e:headedRuns tests with browser windows visible, useful for seeing what's happening. 4. Debug modenpm run test:e2e:debugRuns tests with Playwright Inspector for step-by-step debugging. Test FilesThe repository includes 8 test suites in the
Test ReportsAfter running tests, an HTML report is generated. If tests fail, the report should open automatically. You can also view it manually: npx playwright show-report |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The biggest blocker is that fullResponse += ... in manusTool likely does not update the caller’s context, so the agent won’t retain Manus task details for follow-up (correctness issue). The schema module exports a misleading PartialManus type based on the Zod schema object rather than its inferred shape. The tool registry’s any tool map increases drift risk for tool names/contracts. Finally, the Manus API call lacks a timeout and may surface overly verbose error bodies to downstream consumers.
Additional notes (1)
- Maintainability |
lib/agents/tools/index.tsx:9-9
The tool registry usesconst tools: any = { ... }, which defeats the benefit of registering tools conditionally while keeping tool names consistent and discoverable. In particular,manusTaskbecomes an untyped string key and increases the risk of mismatches between the tool name the agent is instructed to call and the actual registered name.
Even if the surrounding codebase is currently permissive, this is a maintainability footgun—new tools will keep piling into an any bag with no central contract.
Summary of changes
Summary of changes
✅ Added Manus AI integration
- Introduced a new tool
manusToolthat creates tasks viaPOST https://api.manus.ai/v1/tasksand streams UI updates. - Added a Zod schema (
lib/schema/manus.tsx) describing tool parameters (prompt,agentProfile,taskMode,interactiveMode). - Added a UI component (
components/manus-section.tsx) to render the Manus task metadata and external links.
🔧 Tool registry & configuration updates
- Registered the Manus tool conditionally in
lib/agents/tools/index.tsxwhenprocess.env.MANUS_API_KEYis present. - Documented
MANUS_API_KEYin.env.local.example.
📚 Documentation
- Added
MANUS_INTEGRATION.mdwith architecture rationale, setup, usage, and troubleshooting.
lib/agents/tools/manus.tsx
Outdated
| export const manusTool = ({ uiStream, fullResponse }: ToolProps) => ({ | ||
| description: | ||
| 'Execute complex tasks using the Manus AI agent platform. Use this for multi-step tasks requiring planning, research across multiple sources, code execution, file manipulation, or advanced reasoning. Manus can browse the web, analyze data, write code, and perform complex workflows.', | ||
| parameters: manusSchema, | ||
| execute: async ({ | ||
| prompt, | ||
| agentProfile, | ||
| taskMode, | ||
| interactiveMode | ||
| }: { | ||
| prompt: string | ||
| agentProfile: 'manus-1.6' | 'manus-1.6-lite' | 'manus-1.6-max' | ||
| taskMode?: 'chat' | 'adaptive' | 'agent' | ||
| interactiveMode: boolean | ||
| }) => { | ||
| let hasError = false | ||
| // Show loading state | ||
| uiStream.append(<SearchSkeleton />) | ||
|
|
||
| let taskResult: { | ||
| task_id: string | ||
| task_title: string | ||
| task_url: string | ||
| share_url?: string | ||
| } | null = null | ||
|
|
||
| try { | ||
| const apiKey = process.env.MANUS_API_KEY | ||
| if (!apiKey) { | ||
| throw new Error('MANUS_API_KEY is not configured') | ||
| } | ||
|
|
||
| // Create task | ||
| const response = await fetch('https://api.manus.ai/v1/tasks', { | ||
| method: 'POST', | ||
| headers: { | ||
| accept: 'application/json', | ||
| 'content-type': 'application/json', | ||
| API_KEY: apiKey | ||
| }, | ||
| body: JSON.stringify({ | ||
| prompt, | ||
| agentProfile, | ||
| taskMode, | ||
| interactiveMode, | ||
| createShareableLink: true | ||
| }) | ||
| }) | ||
|
|
||
| if (!response.ok) { | ||
| const errorText = await response.text() | ||
| throw new Error( | ||
| `Manus API error: ${response.status} - ${errorText}` | ||
| ) | ||
| } | ||
|
|
||
| taskResult = await response.json() | ||
|
|
||
| if (!taskResult) { | ||
| hasError = true | ||
| } | ||
| } catch (error) { | ||
| hasError = true | ||
| console.error('Manus API error:', error) | ||
|
|
||
| const errorMessage = | ||
| error instanceof Error ? error.message : 'Unknown error occurred' | ||
| fullResponse += `\nAn error occurred while executing Manus task: ${errorMessage}` | ||
|
|
||
| uiStream.update( | ||
| <Card className="p-4 mt-2 text-sm"> | ||
| {`An error occurred while executing Manus task: ${errorMessage}`} | ||
| </Card> | ||
| ) | ||
| return null | ||
| } | ||
|
|
||
| if (hasError || !taskResult) { | ||
| fullResponse += `\nAn error occurred while executing the Manus task.` | ||
| uiStream.update( | ||
| <Card className="p-4 mt-2 text-sm"> | ||
| An error occurred while executing the Manus task. | ||
| </Card> | ||
| ) | ||
| return null | ||
| } | ||
|
|
||
| // Update UI with task result | ||
| uiStream.update(<ManusSection data={taskResult} />) | ||
|
|
||
| // Add task information to the response context | ||
| fullResponse += `\n\nManus task created successfully: | ||
| - Task ID: ${taskResult.task_id} | ||
| - Title: ${taskResult.task_title} | ||
| - Task URL: ${taskResult.task_url} | ||
| ${taskResult.share_url ? `- Share URL: ${taskResult.share_url}` : ''} | ||
|
|
||
| You can view the task progress and results at the provided URL.` | ||
|
|
||
| return taskResult |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fullResponse is treated like a mutable accumulator (fullResponse += ...) but it’s passed in as a string prop. This won’t mutate the caller’s value (strings are immutable and this is just rebinding a local variable), so the Manus task details/errors likely never make it back into the agent’s context. This is a correctness issue: the tool may appear to work in UI, but the agent won’t “remember” the task URL/ID for follow-up reasoning.
You already stream UI via uiStream; for textual context you likely need either (a) to return a string payload the agent can incorporate, or (b) accept a mutable/streamable reference (e.g., fullResponseStream.append(...)) rather than a plain string.
Suggestion
Change the contract so the tool can actually add to the model-visible context.
Option A (recommended): remove fullResponse mutation and return a structured result with a summary string that the caller appends.
// tools/manus.tsx
export const manusTool = ({ uiStream }: ToolProps) => ({
// ...
execute: async (args) => {
// ...
return {
...taskResult,
summary: `Manus task created successfully:\n- Task ID: ${taskResult.task_id}\n- Title: ${taskResult.task_title}\n- Task URL: ${taskResult.task_url}`
}
}
})Then in the agent/tool runner layer, append result.summary into the conversation context.
Option B: change ToolProps.fullResponse to be a mutable container (e.g., { value: string }) or a streamable text primitive and append to it.
Reply with "@CharlieHelps yes please" if you’d like me to add a commit implementing Option A end-to-end (including updating the tool runner/registry call sites).
lib/agents/tools/manus.tsx
Outdated
| const response = await fetch('https://api.manus.ai/v1/tasks', { | ||
| method: 'POST', | ||
| headers: { | ||
| accept: 'application/json', | ||
| 'content-type': 'application/json', | ||
| API_KEY: apiKey | ||
| }, | ||
| body: JSON.stringify({ | ||
| prompt, | ||
| agentProfile, | ||
| taskMode, | ||
| interactiveMode, | ||
| createShareableLink: true | ||
| }) | ||
| }) | ||
|
|
||
| if (!response.ok) { | ||
| const errorText = await response.text() | ||
| throw new Error( | ||
| `Manus API error: ${response.status} - ${errorText}` | ||
| ) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The API error handling includes await response.text() and embeds it directly in the thrown error message. Many APIs return verbose bodies that may include request correlation IDs, internal details, or even echoed inputs. This becomes risky if fullResponse (or any other output) is later shown to users or logged upstream.
Also, there is no timeout/abort for fetch, so a hung Manus request can stall the tool execution indefinitely.
Suggestion
- Add a timeout via
AbortController. - Sanitize error propagation: log full body server-side, but surface only status + a capped snippet (or a generic message) to the agent/user.
Example:
const controller = new AbortController()
const timeout = setTimeout(() => controller.abort(), 30_000)
let errorBody: string | undefined
try {
const response = await fetch(url, { ...opts, signal: controller.signal })
if (!response.ok) {
errorBody = await response.text()
throw new Error(`Manus API error: ${response.status}`)
}
return await response.json()
} finally {
clearTimeout(timeout)
if (errorBody) console.error('Manus API error body:', errorBody)
}Reply with "@CharlieHelps yes please" if you’d like me to add a commit implementing the timeout + safer error surfacing.
lib/agents/tools/manus.tsx
Outdated
| // Create task | ||
| const response = await fetch('https://api.manus.ai/v1/tasks', { | ||
| method: 'POST', | ||
| headers: { | ||
| accept: 'application/json', | ||
| 'content-type': 'application/json', | ||
| API_KEY: apiKey | ||
| }, | ||
| body: JSON.stringify({ | ||
| prompt, | ||
| agentProfile, | ||
| taskMode, | ||
| interactiveMode, | ||
| createShareableLink: true | ||
| }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The request headers use API_KEY, but many APIs expect an Authorization: Bearer ... header (or a vendor-specific header like X-API-Key). Since this integration hardcodes API_KEY, if Manus expects a different header name, the tool will fail at runtime.
Given this is an external integration, it’s worth aligning the header with Manus docs and/or supporting both to reduce fragility.
Suggestion
Confirm the required auth header from Manus docs and update accordingly. If docs are ambiguous or subject to change, consider sending both headers:
headers: {
accept: 'application/json',
'content-type': 'application/json',
'X-API-Key': apiKey,
Authorization: `Bearer ${apiKey}`
}(Use only what Manus supports; don’t ship both unless confirmed acceptable.)
Reply with "@CharlieHelps yes please" if you’d like me to add a commit once you confirm the expected header.
lib/agents/tools/manus.tsx
Outdated
| execute: async ({ | ||
| prompt, | ||
| agentProfile, | ||
| taskMode, | ||
| interactiveMode | ||
| }: { | ||
| prompt: string | ||
| agentProfile: 'manus-1.6' | 'manus-1.6-lite' | 'manus-1.6-max' | ||
| taskMode?: 'chat' | 'adaptive' | 'agent' | ||
| interactiveMode: boolean | ||
| }) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The tool declares its execute args as a custom inline type that diverges from the Zod schema defaults:
agentProfileis required in the inline type, but schema provides a default.interactiveModeis required in the inline type, but schema provides a default.
Even if the runtime tool framework fills defaults from Zod, keeping the execute signature stricter than the schema increases the chance of call-site mismatch and makes maintenance harder.
Suggestion
Derive the execute parameter type directly from the schema to keep schema + implementation aligned:
import { z } from 'zod'
execute: async (params: z.infer<typeof manusSchema>) => {
const { prompt, agentProfile, taskMode, interactiveMode } = params
...
}If you want to keep an explicit type, make fields with schema defaults optional in the type.
Reply with "@CharlieHelps yes please" if you’d like me to add a commit with this refactor.
- Fix PartialManus type to use z.infer correctly - Add fetch timeout with AbortController (30s) - Sanitize error messages to prevent info leakage - Validate URLs before rendering to prevent injection - Filter undefined fields from request body - Validate API response structure with Zod - Add aria-labels for accessibility - Disable shareable links by default for privacy - Add audit logging for task creation - Update documentation with security features Addresses all review comments from CodeRabbit and qodo-code-review.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (4)
MANUS_INTEGRATION.mdcomponents/manus-section.tsxlib/agents/tools/manus.tsxlib/schema/manus.tsx
🧰 Additional context used
🧬 Code graph analysis (2)
components/manus-section.tsx (2)
components/section.tsx (1)
Section(24-75)components/ui/card.tsx (3)
props(8-17)props(35-44)props(50-56)
lib/agents/tools/manus.tsx (3)
lib/agents/tools/index.tsx (2)
ToolProps(8-12)ToolProps(14-39)lib/schema/manus.tsx (2)
manusSchema(3-23)ManusInput(25-25)components/search-skeleton.tsx (1)
SearchSkeleton(6-30)
🪛 LanguageTool
MANUS_INTEGRATION.md
[style] ~107-~107: Consider a different adjective to strengthen your wording.
Context: ...uire: - Complex multi-step workflows - Deep research across multiple sources - Code...
(DEEP_PROFOUND)
[grammar] ~235-~235: Ensure spelling is correct
Context: ...tivity ### Timeout Errors If requests timeout: - Check your network connection - Verify t...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
🪛 markdownlint-cli2 (0.18.1)
MANUS_INTEGRATION.md
54-54: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
59-59: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
64-64: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
68-68: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
73-73: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
78-78: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
🔇 Additional comments (4)
components/manus-section.tsx (1)
1-70: LGTM! Well-implemented component with strong accessibility and security practices.The ManusSection component is well-structured and follows best practices:
- Proper accessibility with descriptive
aria-labelattributes andaria-hiddenon decorative icons- Secure external links with
rel="noopener noreferrer"- Clean conditional rendering for optional share URL
- Consistent with QCX design patterns (Section, Card components)
- URL validation is handled upstream in the tool (lib/agents/tools/manus.tsx lines 110-117)
lib/schema/manus.tsx (1)
1-26: LGTM! Schema is well-defined with proper type inference.The Zod schema is correctly structured with:
- Clear field descriptions for each parameter
- Appropriate defaults (manus-1.6 for agentProfile, false for interactiveMode)
- Enum constraints for agentProfile and taskMode
- Proper type inference using
z.inferfor ManusInput (line 25)- Correct
Partial<ManusInput>for PartialManus (line 26)The previous concern about type inference has been addressed.
lib/agents/tools/manus.tsx (2)
17-45: LGTM! Excellent security-focused helper functions.The helper functions implement strong security measures:
sanitizeErrorMessage (lines 17-30):
- Masks sensitive configuration errors (MANUS_API_KEY)
- Replaces network errors with user-friendly messages
- Prevents information leakage through error messages
isValidUrl (lines 33-45):
- Enforces HTTPS protocol requirement
- Restricts to manus.ai domain and subdomains
- Prevents URL injection attacks
These align well with security best practices and address past review concerns.
47-156: LGTM! Comprehensive and secure tool implementation.The Manus tool implementation demonstrates excellent attention to security and reliability:
Security measures (addressing past review concerns):
- Request timeout: 30-second AbortController prevents indefinite hangs (lines 80-82, 97, 130-134)
- Error sanitization: prevents sensitive data leakage (lines 140-145, using sanitizeErrorMessage)
- URL validation: enforces HTTPS and manus.ai domain before rendering (lines 110-117)
- Response validation: Zod schema ensures type safety (line 107)
- Privacy by default: shareable links disabled (line 78)
Reliability features:
- Filters undefined fields from requests (lines 62-74)
- Comprehensive error handling with proper logging (lines 136-154)
- Audit trail for task creation (lines 123-126)
- Graceful error UI updates (lines 147-151)
Note: The
fullResponseparameter exists but is unused. This is consistent with the broader tool architecture pattern across the codebase and is not an issue specific to this implementation.
| # Manus AI Integration | ||
|
|
||
| This document describes the integration of Manus AI into the QCX platform. | ||
|
|
||
| ## Overview | ||
|
|
||
| Manus AI has been integrated as a specialized tool available to the QCX Researcher Agent. This integration enables QCX to delegate complex, multi-step tasks to the Manus AI platform, which can perform advanced reasoning, research, code execution, and workflow automation. | ||
|
|
||
| ## Architecture Decision | ||
|
|
||
| The Manus integration follows a **tool-based architecture** rather than creating a separate agent. This decision was made based on several factors: | ||
|
|
||
| - **Consistency**: Aligns with existing QCX patterns (search, retrieve, geospatial tools) | ||
| - **Simplicity**: Minimal changes to existing routing logic | ||
| - **Flexibility**: The Researcher Agent can intelligently decide when Manus is appropriate | ||
| - **Maintainability**: Follows established patterns in the codebase | ||
| - **Cost Efficiency**: Avoids unnecessary LLM calls for routing decisions | ||
|
|
||
| ## Implementation Details | ||
|
|
||
| ### Files Created | ||
|
|
||
| 1. **`lib/schema/manus.tsx`** - Zod schema for Manus tool parameters | ||
| - Defines validation for prompt, agentProfile, taskMode, and interactiveMode | ||
| - Provides TypeScript types for type safety using `z.infer` | ||
|
|
||
| 2. **`lib/agents/tools/manus.tsx`** - Manus tool implementation | ||
| - Handles API calls to Manus AI platform | ||
| - Implements comprehensive error handling with sanitized messages | ||
| - Validates API responses and URLs for security | ||
| - Includes fetch timeout to prevent hanging requests | ||
| - Filters undefined fields from request body | ||
| - Manages UI updates with proper streaming | ||
|
|
||
| 3. **`components/manus-section.tsx`** - UI component for displaying Manus task results | ||
| - Shows task title, ID, and status | ||
| - Provides accessible links with aria-labels | ||
| - Validates URLs before rendering | ||
| - Follows QCX design patterns | ||
|
|
||
| ### Files Modified | ||
|
|
||
| 1. **`lib/agents/tools/index.tsx`** - Tool registry | ||
| - Added Manus tool import | ||
| - Conditionally registers Manus tool when MANUS_API_KEY is present | ||
|
|
||
| 2. **`.env.local.example`** - Environment configuration | ||
| - Added MANUS_API_KEY configuration with documentation | ||
|
|
||
| ## Security Features | ||
|
|
||
| The integration implements several security measures: | ||
|
|
||
| ### 1. Error Message Sanitization | ||
| - Raw API errors are not exposed to users | ||
| - Error messages are sanitized to prevent information leakage | ||
| - Sensitive configuration errors are replaced with generic messages | ||
|
|
||
| ### 2. URL Validation | ||
| - All URLs from the API are validated before use | ||
| - Only HTTPS URLs from manus.ai domain are allowed | ||
| - Invalid URLs are rejected to prevent injection attacks | ||
|
|
||
| ### 3. Request Timeout | ||
| - 30-second timeout on API requests using AbortController | ||
| - Prevents indefinite hanging on slow or unresponsive API | ||
|
|
||
| ### 4. Response Validation | ||
| - API responses are validated against expected schema | ||
| - Malformed responses are rejected | ||
| - Type safety enforced with Zod validation | ||
|
|
||
| ### 5. Audit Logging | ||
| - Task creation events are logged (without sensitive data) | ||
| - Errors are logged securely with timestamps | ||
| - Helps with debugging and compliance | ||
|
|
||
| ### 6. Privacy by Default | ||
| - Shareable links are disabled by default | ||
| - Can be enabled when needed for specific use cases | ||
| - Prevents accidental data exposure | ||
|
|
||
| ## Configuration | ||
|
|
||
| ### Environment Variables | ||
|
|
||
| Add the following to your `.env.local` file: | ||
|
|
||
| ```bash | ||
| # Manus AI API Key | ||
| # Get your API key from https://open.manus.im/docs/quickstart | ||
| MANUS_API_KEY="your_manus_api_key_here" | ||
| ``` | ||
|
|
||
| ### Getting Your API Key | ||
|
|
||
| 1. Visit the [Manus API Integration settings](https://open.manus.im/docs/quickstart) | ||
| 2. Generate a new API key | ||
| 3. Add it to your `.env.local` file | ||
| 4. Restart your development server | ||
|
|
||
| ## Usage | ||
|
|
||
| Once configured, the Manus tool is automatically available to the QCX Researcher Agent. The agent will use Manus for tasks that require: | ||
|
|
||
| - Complex multi-step workflows | ||
| - Deep research across multiple sources | ||
| - Code execution or file manipulation | ||
| - Advanced reasoning and planning | ||
| - Tasks beyond simple search and retrieval | ||
|
|
||
| ### Tool Parameters | ||
|
|
||
| The Manus tool accepts the following parameters: | ||
|
|
||
| - **prompt** (required): The task instruction for Manus | ||
| - **agentProfile** (optional): Agent profile to use | ||
| - `manus-1.6` (default) - Balanced performance | ||
| - `manus-1.6-lite` - Faster execution | ||
| - `manus-1.6-max` - Most capable | ||
| - **taskMode** (optional): Execution mode | ||
| - `chat` - Conversational mode | ||
| - `adaptive` - Adaptive mode | ||
| - `agent` - Full agent mode | ||
| - **interactiveMode** (optional): Enable follow-up questions (default: false) | ||
|
|
||
| ### Example Usage | ||
|
|
||
| When a user asks a complex question like "Research the latest developments in quantum computing and create a comprehensive report with code examples," the Researcher Agent may decide to use the Manus tool: | ||
|
|
||
| ```typescript | ||
| { | ||
| prompt: "Research the latest developments in quantum computing and create a comprehensive report with code examples", | ||
| agentProfile: "manus-1.6", | ||
| taskMode: "agent", | ||
| interactiveMode: false | ||
| } | ||
| ``` | ||
|
|
||
| The tool will: | ||
| 1. Validate the API key is configured | ||
| 2. Filter undefined fields from the request | ||
| 3. Create a task on the Manus platform with timeout protection | ||
| 4. Validate the API response | ||
| 5. Validate URLs before displaying | ||
| 6. Show the task information with accessible links | ||
| 7. Log the task creation for audit trail | ||
|
|
||
| ## API Reference | ||
|
|
||
| ### Manus API Endpoint | ||
|
|
||
| - **URL**: `https://api.manus.ai/v1/tasks` | ||
| - **Method**: POST | ||
| - **Authentication**: API_KEY header | ||
| - **Timeout**: 30 seconds | ||
|
|
||
| ### Request Schema | ||
|
|
||
| ```typescript | ||
| { | ||
| prompt: string | ||
| agentProfile: 'manus-1.6' | 'manus-1.6-lite' | 'manus-1.6-max' | ||
| taskMode?: 'chat' | 'adaptive' | 'agent' | ||
| interactiveMode?: boolean | ||
| createShareableLink?: boolean | ||
| } | ||
| ``` | ||
|
|
||
| ### Response Schema | ||
|
|
||
| ```typescript | ||
| { | ||
| task_id: string | ||
| task_title: string | ||
| task_url: string (validated HTTPS URL) | ||
| share_url?: string (validated HTTPS URL) | ||
| } | ||
| ``` | ||
|
|
||
| ## Accessibility | ||
|
|
||
| The integration follows WCAG guidelines: | ||
|
|
||
| - Links have descriptive aria-labels | ||
| - Icons are marked as decorative with aria-hidden | ||
| - Semantic HTML structure | ||
| - Keyboard navigation support | ||
| - Screen reader friendly | ||
|
|
||
| ## Future Enhancements | ||
|
|
||
| Potential improvements for future iterations: | ||
|
|
||
| 1. **Task Result Polling**: Implement polling to fetch and display task results directly in QCX | ||
| 2. **Webhook Integration**: Use Manus webhooks for real-time task completion notifications | ||
| 3. **Connector Support**: Enable Manus connectors (Gmail, Notion, Google Calendar, etc.) | ||
| 4. **Dedicated Agent**: Create a specialized Manus agent for complex workflows requiring multiple Manus calls | ||
| 5. **File Attachments**: Support file uploads to Manus tasks | ||
| 6. **Multi-turn Conversations**: Enable continuing existing Manus tasks | ||
| 7. **Configurable Share Links**: Add UI option to enable/disable shareable links per task | ||
|
|
||
| ## Testing | ||
|
|
||
| To test the integration: | ||
|
|
||
| 1. Ensure MANUS_API_KEY is set in `.env.local` | ||
| 2. Start the development server: `bun dev` | ||
| 3. Ask a complex question that would benefit from Manus capabilities | ||
| 4. Verify the Manus tool is called and task information is displayed | ||
| 5. Check that URLs are valid and accessible | ||
| 6. Verify error handling with invalid API key | ||
| 7. Test timeout behavior with network issues | ||
|
|
||
| ## Troubleshooting | ||
|
|
||
| ### Tool Not Available | ||
|
|
||
| If the Manus tool is not being used: | ||
| - Check that MANUS_API_KEY is set in `.env.local` | ||
| - Restart the development server after adding the API key | ||
| - Verify the API key is valid by testing it directly with the Manus API | ||
|
|
||
| ### API Errors | ||
|
|
||
| If you encounter API errors: | ||
| - Check the console for detailed error logs (sanitized for security) | ||
| - Verify your API key has not expired | ||
| - Ensure you have sufficient credits on your Manus account | ||
| - Check the Manus API status page for service issues | ||
| - Verify network connectivity | ||
|
|
||
| ### Timeout Errors | ||
|
|
||
| If requests timeout: | ||
| - Check your network connection | ||
| - Verify the Manus API is responding | ||
| - Consider increasing the timeout if needed for complex tasks | ||
| - Check if firewall or proxy is blocking requests | ||
|
|
||
| ### Invalid URLs | ||
|
|
||
| If URL validation fails: | ||
| - Verify the Manus API is returning valid HTTPS URLs | ||
| - Check that URLs are from manus.ai domain | ||
| - Report any issues to Manus support | ||
|
|
||
| ## Resources | ||
|
|
||
| - [Manus API Documentation](https://open.manus.im/docs/quickstart) | ||
| - [Manus API Reference](https://open.manus.im/docs/api-reference) | ||
| - [AI SDK Workflow Patterns](https://ai-sdk.dev/docs/agents/workflows) | ||
| - [QCX Repository](https://github.com/QueueLab/QCX) | ||
| - [WCAG Accessibility Guidelines](https://www.w3.org/WAI/WCAG21/quickref/) | ||
|
|
||
| ## License |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
LGTM! Comprehensive and professional documentation.
The documentation is thorough and well-organized, covering:
- Architecture rationale and decision-making
- Complete implementation details and file structure
- Security features (sanitization, validation, timeout, audit logging, privacy)
- Clear configuration instructions with links to Manus documentation
- Usage examples and parameter descriptions
- API reference with request/response schemas
- Accessibility guidelines
- Troubleshooting section with common issues
- Future enhancement ideas
Optional: Fix markdown heading spacing for linting
Static analysis suggests adding blank lines around some headings to comply with markdown linting rules. While this doesn't affect readability, it would resolve linting warnings:
Add blank lines before headings at lines 54, 59, 64, 68, 73, and 78 (the numbered security feature subsections).
Example:
- Sensitive configuration errors are replaced with generic messages
+
### 2. URL Validation
- All URLs from the API are validated before useCommittable suggestion skipped: line range outside the PR's diff.
🧰 Tools
🪛 LanguageTool
[style] ~107-~107: Consider a different adjective to strengthen your wording.
Context: ...uire: - Complex multi-step workflows - Deep research across multiple sources - Code...
(DEEP_PROFOUND)
[grammar] ~235-~235: Ensure spelling is correct
Context: ...tivity ### Timeout Errors If requests timeout: - Check your network connection - Verify t...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
🪛 markdownlint-cli2 (0.18.1)
54-54: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
59-59: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
64-64: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
68-68: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
73-73: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
78-78: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
🤖 Prompt for AI Agents
In MANUS_INTEGRATION.md lines 1 to 256, markdown linting warns about missing
blank lines around several subsection headings; add a single blank line before
the headings at (approx.) lines 54, 59, 64, 68, 73, and 78 so each numbered
security feature subsection is separated by an empty line from the preceding
content, ensuring the file conforms to standard markdown heading spacing rules.
User description
Add Manus AI Integration as Specialized Tool
Overview
This PR integrates Manus AI into QCX as a specialized tool, enabling the Researcher Agent to delegate complex, multi-step tasks to the Manus AI platform for advanced reasoning, research, code execution, and workflow automation.
Architecture Decision
The integration follows a tool-based architecture rather than creating a separate agent. This approach was chosen because:
Based on the AI SDK workflow patterns documentation, this is the recommended approach for starting with the simplest solution that meets requirements.
Changes
New Files
lib/schema/manus.tsx- Zod schema for Manus tool parameterslib/agents/tools/manus.tsx- Manus tool implementationhttps://api.manus.ai/v1/tasks)components/manus-section.tsx- UI component for displaying Manus task resultsMANUS_INTEGRATION.md- Comprehensive documentationModified Files
lib/agents/tools/index.tsx- Tool registryMANUS_API_KEYis present.env.local.example- Environment configurationMANUS_API_KEYconfiguration with documentation linkConfiguration
Users need to add the following to their
.env.localfile:Tool Capabilities
The Manus tool is designed for:
Parameters
manus-1.6(default),manus-1.6-lite, ormanus-1.6-maxchat,adaptive, oragentTesting
Future Enhancements
Potential improvements for future iterations:
Documentation
See
MANUS_INTEGRATION.mdfor:References
Checklist
PR Type
Enhancement
Description
Integrates Manus AI as specialized tool for complex multi-step tasks
Adds Zod schema validation for Manus tool parameters
Creates ManusSection UI component for displaying task results
Conditionally registers Manus tool when API key is configured
Includes comprehensive integration documentation and setup guide
Diagram Walkthrough
File Walkthrough
manus.tsx
Manus tool parameter validation schemalib/schema/manus.tsx
manus.tsx
Manus tool implementation with API integrationlib/agents/tools/manus.tsx
https://api.manus.ai/v1/taskstracking
manus-section.tsx
UI component for Manus task result displaycomponents/manus-section.tsx
index.tsx
Tool registry update with Manus integrationlib/agents/tools/index.tsx
variable is present
.env.local.example
Environment configuration for Manus API key.env.local.example
MANUS_INTEGRATION.md
Complete Manus integration documentation and guideMANUS_INTEGRATION.md
design decisions
Summary by CodeRabbit
New Features
Documentation
Chores
✏️ Tip: You can customize this high-level summary in your review settings.