Skip to content

feat(tools): add MuAPI image and video generation tools#6199

Open
Anil-matcha wants to merge 4 commits into
crewAIInc:mainfrom
Anil-matcha:feat/muapi-tool
Open

feat(tools): add MuAPI image and video generation tools#6199
Anil-matcha wants to merge 4 commits into
crewAIInc:mainfrom
Anil-matcha:feat/muapi-tool

Conversation

@Anil-matcha

@Anil-matcha Anil-matcha commented Jun 17, 2026

Copy link
Copy Markdown

Summary

Adds MuApiImageTool and MuApiVideoTool — two new generation tools backed by muapi.ai, a unified API aggregator for 400+ generative media models.

What this adds

  • lib/crewai-tools/src/crewai_tools/tools/muapi_tool/muapi_tool.py — two BaseTool subclasses
  • lib/crewai-tools/src/crewai_tools/tools/muapi_tool/README.MD
  • Exports added to tools/__init__.py

MuApiImageTool

Generates images from text prompts. Supports: Flux Schnell/Dev/Kontext, HiDream, Midjourney, GPT-4o Image, Google Imagen 4, Seedream, Reve, Ideogram, Hunyuan, Wan, Qwen.

MuApiVideoTool

Generates short MP4 videos from text prompts. Supports: Veo3, Kling, Wan 2.1/2.2, Seedance Pro, Runway, Pixverse, Sora, Minimax.

Usage

from crewai_tools import MuApiImageTool, MuApiVideoTool

agent = Agent(
    role="Creative Director",
    goal="Generate visual assets",
    tools=[MuApiImageTool(), MuApiVideoTool()],
    backstory="...",
)

Setup: export MUAPI_API_KEY=your_key — get one at muapi.ai/dashboard/api-keys.

Implementation notes

  • Uses stdlib urllib.request to keep dependencies minimal (no httpx/requests required)
  • Submit → poll pattern: POST /api/v1/{model} → poll /api/v1/predictions/{id}/result
  • MUAPI_API_KEY declared via env_vars for proper crewAI credential handling

Summary by CodeRabbit

  • New Features

    • Added image generation tool with support for multiple image models
    • Added video generation tool with support for multiple video models
  • Documentation

    • Added setup and usage guide for new generation tools with API configuration instructions and example code

@coderabbitai

coderabbitai Bot commented Jun 17, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Two new CrewAI tools, MuApiImageTool and MuApiVideoTool, are added under muapi_tool/. Both use Pydantic schemas for input validation and a shared _submit_and_poll helper that submits generation jobs to MuAPI and polls for results. Both tools are registered in the top-level tools package exports and documented in a new README.

Changes

MuAPI Image and Video Tools

Layer / File(s) Summary
Constants, schemas, polling helper, and tool implementations
lib/crewai-tools/src/crewai_tools/tools/muapi_tool/__init__.py, lib/crewai-tools/src/crewai_tools/tools/muapi_tool/muapi_tool.py
Defines BASE_URL, IMAGE_MODELS, VIDEO_MODELS constants, Pydantic input schemas (MuApiImageSchema, MuApiVideoSchema), the _submit_and_poll helper (POST job submission + status polling loop), and _run implementations for MuApiImageTool and MuApiVideoTool, each reading MUAPI_API_KEY and returning a JSON result string.
Package exports and documentation
lib/crewai-tools/src/crewai_tools/tools/__init__.py, lib/crewai-tools/src/crewai_tools/tools/muapi_tool/README.MD
Imports and adds MuApiImageTool and MuApiVideoTool to the tools package __all__. README documents MUAPI_API_KEY setup, a full usage example with Agent/Task/Crew, and supported model identifiers.

Sequence Diagram(s)

sequenceDiagram
  participant Agent as CrewAI Agent
  participant ImageTool as MuApiImageTool
  participant VideoTool as MuApiVideoTool
  participant Helper as _submit_and_poll
  participant MuAPI as MuAPI REST API

  Agent->>ImageTool: _run(prompt, model, width, height)
  ImageTool->>Helper: POST /image endpoint + payload
  Helper->>MuAPI: submit job
  MuAPI-->>Helper: request_id
  Helper->>MuAPI: poll GET /result/{request_id}
  MuAPI-->>Helper: output URL
  Helper-->>ImageTool: image URL
  ImageTool-->>Agent: JSON {image_url, model, prompt}

  Agent->>VideoTool: _run(prompt, model, duration, aspect_ratio)
  VideoTool->>Helper: POST /video endpoint + payload
  Helper->>MuAPI: submit job
  MuAPI-->>Helper: request_id
  Helper->>MuAPI: poll GET /result/{request_id}
  MuAPI-->>Helper: output URL
  Helper-->>VideoTool: video URL
  VideoTool-->>Agent: JSON {video_url, model, prompt}
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding two new MuAPI tools for image and video generation to the tools module.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
lib/crewai-tools/src/crewai_tools/tools/muapi_tool/muapi_tool.py (1)

81-81: ⚡ Quick win

Remove redundant json import.

The module already imports json at line 1. The local reimport as _json is unnecessary and could confuse readers.

♻️ Simplify by using the module-level import
 def _submit_and_poll(api_key: str, endpoint: str, payload: dict, timeout: int = 300) -> str:
     """Submit a muapi.ai job and poll until completion, returning the output URL."""
-    import json as _json
 
     headers = {"x-api-key": api_key, "Content-Type": "application/json"}
-    body = _json.dumps(payload).encode()
+    body = json.dumps(payload).encode()
 
     # Submit
     req = urllib.request.Request(f"{BASE_URL}/{endpoint}", data=body, headers=headers, method="POST")
     with urllib.request.urlopen(req, timeout=30) as resp:
-        data = _json.loads(resp.read())
+        data = json.loads(resp.read())
     request_id = data["request_id"]
 
     # Poll
     deadline = time.time() + timeout
     while time.time() < deadline:
         time.sleep(3)
         poll_req = urllib.request.Request(
             f"{BASE_URL}/predictions/{request_id}/result",
             headers={"x-api-key": api_key},
         )
         with urllib.request.urlopen(poll_req, timeout=15) as resp:
-            result = _json.loads(resp.read())
+            result = json.loads(resp.read())
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/crewai-tools/src/crewai_tools/tools/muapi_tool/muapi_tool.py` at line 81,
The module has a redundant import statement where json is imported as _json at
line 81, while json is already imported at the module level at line 1. Remove
the redundant import statement import json as _json and instead use the existing
json module import that is already available at the module level. Update any
references from _json to json to use the module-level import.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@lib/crewai-tools/src/crewai_tools/tools/muapi_tool/muapi_tool.py`:
- Around line 87-90: The code block containing the urllib.request.urlopen call
and subsequent JSON parsing lacks error handling for HTTP errors, timeouts, and
malformed responses. Wrap the entire block starting with the urlopen call
through the data["request_id"] assignment in a try/except block that catches
HTTPError, URLError, socket.timeout, and json.JSONDecodeError exceptions, as
well as KeyError for missing "request_id" in the response. Each exception should
be logged or handled appropriately to provide clear feedback about what failed
during the API request.
- Around line 96-109: The polling request block starting with the `poll_req`
creation and `urllib.request.urlopen(poll_req, timeout=15)` call lacks error
handling for HTTP errors, network errors, and timeout exceptions. Wrap the
urlopen call and the result processing logic in a try/except block to catch
these exceptions gracefully and provide meaningful error messages to the user,
similar to how error handling should be implemented for the initial submission
request.

---

Nitpick comments:
In `@lib/crewai-tools/src/crewai_tools/tools/muapi_tool/muapi_tool.py`:
- Line 81: The module has a redundant import statement where json is imported as
_json at line 81, while json is already imported at the module level at line 1.
Remove the redundant import statement import json as _json and instead use the
existing json module import that is already available at the module level.
Update any references from _json to json to use the module-level import.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a959b638-65bb-4cbf-8995-9c792a091b1b

📥 Commits

Reviewing files that changed from the base of the PR and between 7bb9bc7 and 195815c.

📒 Files selected for processing (4)
  • lib/crewai-tools/src/crewai_tools/tools/__init__.py
  • lib/crewai-tools/src/crewai_tools/tools/muapi_tool/README.MD
  • lib/crewai-tools/src/crewai_tools/tools/muapi_tool/__init__.py
  • lib/crewai-tools/src/crewai_tools/tools/muapi_tool/muapi_tool.py

Comment on lines +87 to +90
req = urllib.request.Request(f"{BASE_URL}/{endpoint}", data=body, headers=headers, method="POST")
with urllib.request.urlopen(req, timeout=30) as resp:
data = _json.loads(resp.read())
request_id = data["request_id"]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add error handling for the submission request.

The urlopen call can raise HTTPError, URLError, or timeout exceptions, and JSON parsing can fail if the response is malformed. Additionally, data["request_id"] will raise KeyError if the API response doesn't include that field.

🛡️ Wrap HTTP call and response parsing in try/except
+    from urllib.error import HTTPError, URLError
+
     headers = {"x-api-key": api_key, "Content-Type": "application/json"}
     body = json.dumps(payload).encode()
 
     # Submit
-    req = urllib.request.Request(f"{BASE_URL}/{endpoint}", data=body, headers=headers, method="POST")
-    with urllib.request.urlopen(req, timeout=30) as resp:
-        data = json.loads(resp.read())
-    request_id = data["request_id"]
+    try:
+        req = urllib.request.Request(f"{BASE_URL}/{endpoint}", data=body, headers=headers, method="POST")
+        with urllib.request.urlopen(req, timeout=30) as resp:
+            data = json.loads(resp.read())
+        request_id = data.get("request_id")
+        if not request_id:
+            raise RuntimeError("API response missing 'request_id'")
+    except HTTPError as e:
+        raise RuntimeError(f"HTTP error during submission: {e.code} {e.reason}")
+    except URLError as e:
+        raise RuntimeError(f"Network error during submission: {e.reason}")
+    except (ValueError, KeyError) as e:
+        raise RuntimeError(f"Invalid JSON response from API: {e}")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/crewai-tools/src/crewai_tools/tools/muapi_tool/muapi_tool.py` around
lines 87 - 90, The code block containing the urllib.request.urlopen call and
subsequent JSON parsing lacks error handling for HTTP errors, timeouts, and
malformed responses. Wrap the entire block starting with the urlopen call
through the data["request_id"] assignment in a try/except block that catches
HTTPError, URLError, socket.timeout, and json.JSONDecodeError exceptions, as
well as KeyError for missing "request_id" in the response. Each exception should
be logged or handled appropriately to provide clear feedback about what failed
during the API request.

Comment on lines +96 to +109
poll_req = urllib.request.Request(
f"{BASE_URL}/predictions/{request_id}/result",
headers={"x-api-key": api_key},
)
with urllib.request.urlopen(poll_req, timeout=15) as resp:
result = _json.loads(resp.read())
status = result.get("status", "pending")
if status == "completed":
outputs = result.get("outputs", [])
if not outputs:
raise RuntimeError("Generation completed but returned no outputs")
return outputs[0]
if status in ("failed", "cancelled"):
raise RuntimeError(f"Generation {status}: {result.get('error', '')}")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add error handling for polling requests.

Similar to the submission request, urlopen during polling can raise HTTP errors, network errors, or timeout exceptions. The polling loop should handle these gracefully to provide useful error messages.

🛡️ Wrap polling requests in try/except
+    from urllib.error import HTTPError, URLError
+
     # Poll
     deadline = time.time() + timeout
     while time.time() < deadline:
         time.sleep(3)
-        poll_req = urllib.request.Request(
-            f"{BASE_URL}/predictions/{request_id}/result",
-            headers={"x-api-key": api_key},
-        )
-        with urllib.request.urlopen(poll_req, timeout=15) as resp:
-            result = json.loads(resp.read())
-        status = result.get("status", "pending")
-        if status == "completed":
-            outputs = result.get("outputs", [])
-            if not outputs:
-                raise RuntimeError("Generation completed but returned no outputs")
-            return outputs[0]
-        if status in ("failed", "cancelled"):
-            raise RuntimeError(f"Generation {status}: {result.get('error', '')}")
+        try:
+            poll_req = urllib.request.Request(
+                f"{BASE_URL}/predictions/{request_id}/result",
+                headers={"x-api-key": api_key},
+            )
+            with urllib.request.urlopen(poll_req, timeout=15) as resp:
+                result = json.loads(resp.read())
+        except (HTTPError, URLError) as e:
+            # Transient errors during polling should not immediately fail; continue polling
+            continue
+        except (ValueError, KeyError):
+            # Invalid JSON response; continue polling in case it's transient
+            continue
+        
+        status = result.get("status", "pending")
+        if status == "completed":
+            outputs = result.get("outputs", [])
+            if not outputs:
+                raise RuntimeError("Generation completed but returned no outputs")
+            return outputs[0]
+        if status in ("failed", "cancelled"):
+            raise RuntimeError(f"Generation {status}: {result.get('error', '')}")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/crewai-tools/src/crewai_tools/tools/muapi_tool/muapi_tool.py` around
lines 96 - 109, The polling request block starting with the `poll_req` creation
and `urllib.request.urlopen(poll_req, timeout=15)` call lacks error handling for
HTTP errors, network errors, and timeout exceptions. Wrap the urlopen call and
the result processing logic in a try/except block to catch these exceptions
gracefully and provide meaningful error messages to the user, similar to how
error handling should be implemented for the initial submission request.

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.

1 participant